mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 09:23:48 +00:00
Merge pull request #30 from taurusgroup/release_v1.14.10
Release v1.14.10
This commit is contained in:
commit
c19665bf82
309 changed files with 9190 additions and 11118 deletions
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
|
|
@ -20,8 +20,6 @@ les/ @zsfelfoldi @rjl493456442
|
|||
light/ @zsfelfoldi @rjl493456442
|
||||
node/ @fjl
|
||||
p2p/ @fjl @zsfelfoldi
|
||||
params/ @fjl @holiman @karalabe @gballet @rjl493456442 @zsfelfoldi
|
||||
rpc/ @fjl @holiman
|
||||
p2p/simulations @fjl
|
||||
p2p/protocols @fjl
|
||||
p2p/testing @fjl
|
||||
signer/ @holiman
|
||||
|
|
|
|||
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21.4
|
||||
go-version: 1.23.0
|
||||
cache: false
|
||||
- name: Run tests
|
||||
run: go test -short ./...
|
||||
|
|
|
|||
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -28,6 +28,14 @@ build/_vendor/pkg
|
|||
/build/bin/
|
||||
/geth*.zip
|
||||
|
||||
# used by the build/ci.go archive + upload tool
|
||||
/geth*.tar.gz
|
||||
/geth*.tar.gz.sig
|
||||
/geth*.tar.gz.asc
|
||||
/geth*.zip.sig
|
||||
/geth*.zip.asc
|
||||
|
||||
|
||||
# travis
|
||||
profile.tmp
|
||||
profile.cov
|
||||
|
|
|
|||
|
|
@ -60,14 +60,14 @@ issues:
|
|||
- path: crypto/bn256/
|
||||
linters:
|
||||
- revive
|
||||
- path: cmd/utils/flags.go
|
||||
text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead."
|
||||
- path: cmd/utils/flags.go
|
||||
text: "SA1019: ethconfig.Defaults.TxLookupLimit is deprecated: use 'TransactionHistory' instead."
|
||||
- path: internal/build/pgp.go
|
||||
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
|
||||
- path: core/vm/contracts.go
|
||||
text: 'SA1019: "golang.org/x/crypto/ripemd160" is deprecated: RIPEMD-160 is a legacy hash and should not be used for new applications.'
|
||||
- path: accounts/usbwallet/trezor.go
|
||||
text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.'
|
||||
- path: accounts/usbwallet/trezor/
|
||||
text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.'
|
||||
exclude:
|
||||
- 'SA1019: event.TypeMux is deprecated: use Feed'
|
||||
- 'SA1019: strings.Title is deprecated'
|
||||
|
|
|
|||
36
.travis.yml
36
.travis.yml
|
|
@ -15,8 +15,8 @@ jobs:
|
|||
if: type = push
|
||||
os: linux
|
||||
arch: amd64
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- docker
|
||||
services:
|
||||
|
|
@ -32,8 +32,8 @@ jobs:
|
|||
if: type = push
|
||||
os: linux
|
||||
arch: arm64
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- docker
|
||||
services:
|
||||
|
|
@ -49,9 +49,9 @@ jobs:
|
|||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
dist: noble
|
||||
dist: focal
|
||||
sudo: required
|
||||
go: 1.22.x
|
||||
go: 1.23.x
|
||||
env:
|
||||
- azure-linux
|
||||
git:
|
||||
|
|
@ -63,6 +63,7 @@ jobs:
|
|||
|
||||
# build 386
|
||||
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
||||
- git status --porcelain
|
||||
- go run build/ci.go install -dlgo -arch 386
|
||||
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||
|
||||
|
|
@ -84,12 +85,13 @@ jobs:
|
|||
if: type = push
|
||||
os: osx
|
||||
osx_image: xcode14.2
|
||||
go: 1.22.x
|
||||
go: 1.23.1 # See https://github.com/ethereum/go-ethereum/pull/30478
|
||||
env:
|
||||
- azure-osx
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
script:
|
||||
- ln -sf /Users/travis/gopath/bin/go1.23.1 /usr/local/bin/go # Work around travis go-setup bug
|
||||
- go run build/ci.go install -dlgo
|
||||
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||
- go run build/ci.go install -dlgo -arch arm64
|
||||
|
|
@ -100,16 +102,16 @@ jobs:
|
|||
if: type = push
|
||||
os: linux
|
||||
arch: amd64
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
script:
|
||||
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
dist: noble
|
||||
go: 1.21.x
|
||||
dist: focal
|
||||
go: 1.22.x
|
||||
script:
|
||||
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
|
|
@ -117,8 +119,8 @@ jobs:
|
|||
- stage: build
|
||||
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
||||
os: linux
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
git:
|
||||
|
|
@ -133,8 +135,8 @@ jobs:
|
|||
- stage: build
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- azure-purge
|
||||
git:
|
||||
|
|
@ -146,8 +148,8 @@ jobs:
|
|||
- stage: build
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- racetests
|
||||
script:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ ARG VERSION=""
|
|||
ARG BUILDNUM=""
|
||||
|
||||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.22-alpine as builder
|
||||
FROM golang:1.23-alpine as builder
|
||||
|
||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ ARG VERSION=""
|
|||
ARG BUILDNUM=""
|
||||
|
||||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.22-alpine as builder
|
||||
FROM golang:1.23-alpine as builder
|
||||
|
||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -42,7 +42,7 @@ clean:
|
|||
devtools:
|
||||
env GOBIN= go install golang.org/x/tools/cmd/stringer@latest
|
||||
env GOBIN= go install github.com/fjl/gencodec@latest
|
||||
env GOBIN= go install github.com/golang/protobuf/protoc-gen-go@latest
|
||||
env GOBIN= go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||
env GOBIN= go install ./cmd/abigen
|
||||
@type "solc" 2> /dev/null || echo 'Please install solc'
|
||||
@type "protoc" 2> /dev/null || echo 'Please install protoc'
|
||||
|
|
|
|||
14
README.md
14
README.md
|
|
@ -16,7 +16,7 @@ archives are published at https://geth.ethereum.org/downloads/.
|
|||
|
||||
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.21 or later) and a C compiler. You can install
|
||||
Building `geth` requires both a Go (version 1.22 or later) and a C compiler. You can install
|
||||
them using your favourite package manager. Once the dependencies are installed, run
|
||||
|
||||
```shell
|
||||
|
|
@ -89,7 +89,7 @@ This command will:
|
|||
This tool is optional and if you leave it out you can always attach it to an already running
|
||||
`geth` instance with `geth attach`.
|
||||
|
||||
### A Full node on the Görli test network
|
||||
### A Full node on the Holesky test network
|
||||
|
||||
Transitioning towards developers, if you'd like to play around with creating Ethereum
|
||||
contracts, you almost certainly would like to do that without any real money involved until
|
||||
|
|
@ -98,23 +98,23 @@ network, you want to join the **test** network with your node, which is fully eq
|
|||
the main network, but with play-Ether only.
|
||||
|
||||
```shell
|
||||
$ geth --goerli console
|
||||
$ geth --holesky console
|
||||
```
|
||||
|
||||
The `console` subcommand has the same meaning as above and is equally
|
||||
useful on the testnet too.
|
||||
|
||||
Specifying the `--goerli` flag, however, will reconfigure your `geth` instance a bit:
|
||||
Specifying the `--holesky` flag, however, will reconfigure your `geth` instance a bit:
|
||||
|
||||
* Instead of connecting to the main Ethereum network, the client will connect to the Görli
|
||||
* Instead of connecting to the main Ethereum network, the client will connect to the Holesky
|
||||
test network, which uses different P2P bootnodes, different network IDs and genesis
|
||||
states.
|
||||
* Instead of using the default data directory (`~/.ethereum` on Linux for example), `geth`
|
||||
will nest itself one level deeper into a `goerli` subfolder (`~/.ethereum/goerli` on
|
||||
will nest itself one level deeper into a `holesky` subfolder (`~/.ethereum/holesky` on
|
||||
Linux). Note, on OSX and Linux this also means that attaching to a running testnet node
|
||||
requires the use of a custom endpoint since `geth attach` will try to attach to a
|
||||
production node endpoint by default, e.g.,
|
||||
`geth attach <datadir>/goerli/geth.ipc`. Windows users are not affected by
|
||||
`geth attach <datadir>/holesky/geth.ipc`. Windows users are not affected by
|
||||
this.
|
||||
|
||||
*Note: Although some internal protective measures prevent transactions from
|
||||
|
|
|
|||
|
|
@ -171,5 +171,5 @@ i4O1UeWKs9owWttan9+PI47ozBSKOTxmMqLSQ0f56Np9FJsV0ilGxRKfjhzJ4KniOMUBA7mP
|
|||
epy6lH7HmxjjOR7eo0DaSxQGQpThAtFGwkWkFh8yki8j3E42kkrxvEyyYZDXn2YcI3bpqhJx
|
||||
PtwCMZUJ3kc/skOrs6bOI19iBNaEoNX5Dllm7UHjOgWNDQkcCuOCxucKano=
|
||||
=arte
|
||||
-----END PGP PUBLIC KEY BLOCK------
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1218,3 +1218,10 @@ func TestUnpackRevert(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInternalContractType(t *testing.T) {
|
||||
jsonData := `[{"inputs":[{"components":[{"internalType":"uint256","name":"dailyLimit","type":"uint256"},{"internalType":"uint256","name":"txLimit","type":"uint256"},{"internalType":"uint256","name":"accountDailyLimit","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"bool","name":"onlyWhitelisted","type":"bool"}],"internalType":"struct IMessagePassingBridge.BridgeLimits","name":"bridgeLimits","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastTransferReset","type":"uint256"},{"internalType":"uint256","name":"bridged24Hours","type":"uint256"}],"internalType":"struct IMessagePassingBridge.AccountLimit","name":"accountDailyLimit","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastTransferReset","type":"uint256"},{"internalType":"uint256","name":"bridged24Hours","type":"uint256"}],"internalType":"struct IMessagePassingBridge.BridgeDailyLimit","name":"bridgeDailyLimit","type":"tuple"},{"internalType":"contract INameService","name":"nameService","type":"INameService"},{"internalType":"bool","name":"isClosed","type":"bool"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"canBridge","outputs":[{"internalType":"bool","name":"isWithinLimit","type":"bool"},{"internalType":"string","name":"error","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"normalizeFrom18ToTokenDecimals","outputs":[{"internalType":"uint256","name":"normalized","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"normalizeFromTokenTo18Decimals","outputs":[{"internalType":"uint256","name":"normalized","type":"uint256"}],"stateMutability":"pure","type":"function"}]`
|
||||
if _, err := JSON(strings.NewReader(jsonData)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,11 +59,12 @@ type TransactOpts struct {
|
|||
Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state)
|
||||
Signer SignerFn // Method to use for signing the transaction (mandatory)
|
||||
|
||||
Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds)
|
||||
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
|
||||
GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle)
|
||||
GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle)
|
||||
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
|
||||
Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds)
|
||||
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
|
||||
GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle)
|
||||
GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle)
|
||||
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
|
||||
AccessList types.AccessList // Access list to set for the transaction execution (nil = no access list)
|
||||
|
||||
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
||||
|
||||
|
|
@ -300,20 +301,21 @@ func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Add
|
|||
return nil, err
|
||||
}
|
||||
baseTx := &types.DynamicFeeTx{
|
||||
To: contract,
|
||||
Nonce: nonce,
|
||||
GasFeeCap: gasFeeCap,
|
||||
GasTipCap: gasTipCap,
|
||||
Gas: gasLimit,
|
||||
Value: value,
|
||||
Data: input,
|
||||
To: contract,
|
||||
Nonce: nonce,
|
||||
GasFeeCap: gasFeeCap,
|
||||
GasTipCap: gasTipCap,
|
||||
Gas: gasLimit,
|
||||
Value: value,
|
||||
Data: input,
|
||||
AccessList: opts.AccessList,
|
||||
}
|
||||
return types.NewTx(baseTx), nil
|
||||
}
|
||||
|
||||
func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
|
||||
if opts.GasFeeCap != nil || opts.GasTipCap != nil {
|
||||
return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet")
|
||||
if opts.GasFeeCap != nil || opts.GasTipCap != nil || opts.AccessList != nil {
|
||||
return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas or accessList specified but london is not active yet")
|
||||
}
|
||||
// Normalize value
|
||||
value := opts.Value
|
||||
|
|
|
|||
|
|
@ -82,7 +82,9 @@ func TestWaitDeployed(t *testing.T) {
|
|||
}()
|
||||
|
||||
// Send and mine the transaction.
|
||||
backend.Client().SendTransaction(ctx, tx)
|
||||
if err := backend.Client().SendTransaction(ctx, tx); err != nil {
|
||||
t.Errorf("test %q: failed to send transaction: %v", name, err)
|
||||
}
|
||||
backend.Commit()
|
||||
|
||||
select {
|
||||
|
|
@ -116,7 +118,9 @@ func TestWaitDeployedCornerCases(t *testing.T) {
|
|||
tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
backend.Client().SendTransaction(ctx, tx)
|
||||
if err := backend.Client().SendTransaction(ctx, tx); err != nil {
|
||||
t.Errorf("failed to send transaction: %q", err)
|
||||
}
|
||||
backend.Commit()
|
||||
notContractCreation := errors.New("tx is not contract creation")
|
||||
if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != notContractCreation.Error() {
|
||||
|
|
@ -134,6 +138,8 @@ func TestWaitDeployedCornerCases(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
backend.Client().SendTransaction(ctx, tx)
|
||||
if err := backend.Client().SendTransaction(ctx, tx); err != nil {
|
||||
t.Errorf("failed to send transaction: %q", err)
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,7 +219,12 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
|
|||
typ.T = FunctionTy
|
||||
typ.Size = 24
|
||||
default:
|
||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
||||
if strings.HasPrefix(internalType, "contract ") {
|
||||
typ.Size = 20
|
||||
typ.T = AddressTy
|
||||
} else {
|
||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ func TestWatchNewFile(t *testing.T) {
|
|||
func TestWatchNoDir(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create ks but not the directory that it watches.
|
||||
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int()))
|
||||
dir := filepath.Join(t.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int()))
|
||||
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
|
||||
list := ks.Accounts()
|
||||
if len(list) > 0 {
|
||||
|
|
@ -126,7 +126,6 @@ func TestWatchNoDir(t *testing.T) {
|
|||
}
|
||||
// Create the directory and copy a key file into it.
|
||||
os.MkdirAll(dir, 0700)
|
||||
defer os.RemoveAll(dir)
|
||||
file := filepath.Join(dir, "aaa")
|
||||
if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@
|
|||
// - Download the latest protoc https://github.com/protocolbuffers/protobuf/releases
|
||||
// - Build with the usual `./configure && make` and ensure it's on your $PATH
|
||||
// - Delete all the .proto and .pb.go files, pull in fresh ones from Trezor
|
||||
// - Grab the latest Go plugin `go get -u github.com/golang/protobuf/protoc-gen-go`
|
||||
// - Vendor in the latest Go plugin `govendor fetch github.com/golang/protobuf/...`
|
||||
// - Grab the latest Go plugin `go get -u google.golang.org/protobuf/cmd/protoc-gen-go`
|
||||
// - Vendor in the latest Go plugin `govendor fetch google.golang.org/protobuf/...`
|
||||
|
||||
//go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ package trezor
|
|||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Type returns the protocol buffer type number of a specific message. If the
|
||||
|
|
|
|||
|
|
@ -70,7 +70,10 @@ func TestBlockSync(t *testing.T) {
|
|||
t.Helper()
|
||||
var expNumber, headNumber uint64
|
||||
if expHead != nil {
|
||||
p, _ := expHead.ExecutionPayload()
|
||||
p, err := expHead.ExecutionPayload()
|
||||
if err != nil {
|
||||
t.Fatalf("expHead.ExecutionPayload() failed: %v", err)
|
||||
}
|
||||
expNumber = p.NumberU64()
|
||||
}
|
||||
select {
|
||||
|
|
|
|||
|
|
@ -56,32 +56,17 @@ var (
|
|||
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}),
|
||||
Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"),
|
||||
}
|
||||
|
||||
GoerliConfig = lightClientConfig{
|
||||
ChainConfig: (&types.ChainConfig{
|
||||
GenesisValidatorsRoot: common.HexToHash("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb"),
|
||||
GenesisTime: 1614588812,
|
||||
}).
|
||||
AddFork("GENESIS", 0, []byte{0, 0, 16, 32}).
|
||||
AddFork("ALTAIR", 36660, []byte{1, 0, 16, 32}).
|
||||
AddFork("BELLATRIX", 112260, []byte{2, 0, 16, 32}).
|
||||
AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}).
|
||||
AddFork("DENEB", 231680, []byte{4, 0, 16, 32}),
|
||||
Checkpoint: common.HexToHash("0x53a0f4f0a378e2c4ae0a9ee97407eb69d0d737d8d8cd0a5fb1093f42f7b81c49"),
|
||||
}
|
||||
)
|
||||
|
||||
func makeChainConfig(ctx *cli.Context) lightClientConfig {
|
||||
var config lightClientConfig
|
||||
customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name)
|
||||
utils.CheckExclusive(ctx, utils.MainnetFlag, utils.GoerliFlag, utils.SepoliaFlag, utils.BeaconConfigFlag)
|
||||
utils.CheckExclusive(ctx, utils.MainnetFlag, utils.SepoliaFlag, utils.BeaconConfigFlag)
|
||||
switch {
|
||||
case ctx.Bool(utils.MainnetFlag.Name):
|
||||
config = MainnetConfig
|
||||
case ctx.Bool(utils.SepoliaFlag.Name):
|
||||
config = SepoliaConfig
|
||||
case ctx.Bool(utils.GoerliFlag.Name):
|
||||
config = GoerliConfig
|
||||
default:
|
||||
if !customConfig {
|
||||
config = MainnetConfig
|
||||
|
|
|
|||
|
|
@ -17,23 +17,25 @@ var _ = (*executableDataMarshaling)(nil)
|
|||
// MarshalJSON marshals as JSON.
|
||||
func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
||||
type ExecutableData struct {
|
||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
||||
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||
Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
||||
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
||||
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||
LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||
Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
||||
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||
Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||
ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||
Deposits types.Deposits `json:"depositRequests"`
|
||||
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||
}
|
||||
var enc ExecutableData
|
||||
enc.ParentHash = e.ParentHash
|
||||
|
|
@ -58,29 +60,33 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
|||
enc.Withdrawals = e.Withdrawals
|
||||
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
|
||||
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
|
||||
enc.Deposits = e.Deposits
|
||||
enc.ExecutionWitness = e.ExecutionWitness
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
||||
type ExecutableData struct {
|
||||
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
||||
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
|
||||
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
|
||||
ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||
LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
||||
Random *common.Hash `json:"prevRandao" gencodec:"required"`
|
||||
Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
||||
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||
ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
||||
BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
|
||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
|
||||
FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"`
|
||||
StateRoot *common.Hash `json:"stateRoot" gencodec:"required"`
|
||||
ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||
LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"`
|
||||
Random *common.Hash `json:"prevRandao" gencodec:"required"`
|
||||
Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"`
|
||||
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||
Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||
ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||
BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"`
|
||||
BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
|
||||
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||
Deposits *types.Deposits `json:"depositRequests"`
|
||||
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||
}
|
||||
var dec ExecutableData
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
|
|
@ -154,5 +160,11 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
|||
if dec.ExcessBlobGas != nil {
|
||||
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
|
||||
}
|
||||
if dec.Deposits != nil {
|
||||
e.Deposits = *dec.Deposits
|
||||
}
|
||||
if dec.ExecutionWitness != nil {
|
||||
e.ExecutionWitness = dec.ExecutionWitness
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,14 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) {
|
|||
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
|
||||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||
Override bool `json:"shouldOverrideBuilder"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
}
|
||||
var enc ExecutionPayloadEnvelope
|
||||
enc.ExecutionPayload = e.ExecutionPayload
|
||||
enc.BlockValue = (*hexutil.Big)(e.BlockValue)
|
||||
enc.BlobsBundle = e.BlobsBundle
|
||||
enc.Override = e.Override
|
||||
enc.Witness = e.Witness
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
|
|
@ -35,6 +37,7 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
|
|||
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
|
||||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||
Override *bool `json:"shouldOverrideBuilder"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
}
|
||||
var dec ExecutionPayloadEnvelope
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
|
|
@ -54,5 +57,8 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
|
|||
if dec.Override != nil {
|
||||
e.Override = *dec.Override
|
||||
}
|
||||
if dec.Witness != nil {
|
||||
e.Witness = dec.Witness
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
|
|
@ -58,23 +59,25 @@ type payloadAttributesMarshaling struct {
|
|||
|
||||
// ExecutableData is the data necessary to execute an EL payload.
|
||||
type ExecutableData struct {
|
||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
||||
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||
LogsBloom []byte `json:"logsBloom" gencodec:"required"`
|
||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||
Number uint64 `json:"blockNumber" gencodec:"required"`
|
||||
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
|
||||
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
||||
Timestamp uint64 `json:"timestamp" gencodec:"required"`
|
||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||
BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
|
||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
||||
Transactions [][]byte `json:"transactions" gencodec:"required"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||
FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"`
|
||||
StateRoot common.Hash `json:"stateRoot" gencodec:"required"`
|
||||
ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||
LogsBloom []byte `json:"logsBloom" gencodec:"required"`
|
||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||
Number uint64 `json:"blockNumber" gencodec:"required"`
|
||||
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
|
||||
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
||||
Timestamp uint64 `json:"timestamp" gencodec:"required"`
|
||||
ExtraData []byte `json:"extraData" gencodec:"required"`
|
||||
BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"`
|
||||
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
|
||||
Transactions [][]byte `json:"transactions" gencodec:"required"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
||||
Deposits types.Deposits `json:"depositRequests"`
|
||||
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||
}
|
||||
|
||||
// JSON type overrides for executableData.
|
||||
|
|
@ -91,6 +94,14 @@ type executableDataMarshaling struct {
|
|||
ExcessBlobGas *hexutil.Uint64
|
||||
}
|
||||
|
||||
// StatelessPayloadStatusV1 is the result of a stateless payload execution.
|
||||
type StatelessPayloadStatusV1 struct {
|
||||
Status string `json:"status"`
|
||||
StateRoot common.Hash `json:"stateRoot"`
|
||||
ReceiptsRoot common.Hash `json:"receiptsRoot"`
|
||||
ValidationError *string `json:"validationError"`
|
||||
}
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go
|
||||
|
||||
type ExecutionPayloadEnvelope struct {
|
||||
|
|
@ -98,6 +109,7 @@ type ExecutionPayloadEnvelope struct {
|
|||
BlockValue *big.Int `json:"blockValue" gencodec:"required"`
|
||||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||
Override bool `json:"shouldOverrideBuilder"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
}
|
||||
|
||||
type BlobsBundleV1 struct {
|
||||
|
|
@ -112,9 +124,10 @@ type executionPayloadEnvelopeMarshaling struct {
|
|||
}
|
||||
|
||||
type PayloadStatusV1 struct {
|
||||
Status string `json:"status"`
|
||||
LatestValidHash *common.Hash `json:"latestValidHash"`
|
||||
ValidationError *string `json:"validationError"`
|
||||
Status string `json:"status"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
LatestValidHash *common.Hash `json:"latestValidHash"`
|
||||
ValidationError *string `json:"validationError"`
|
||||
}
|
||||
|
||||
type TransitionConfigurationV1 struct {
|
||||
|
|
@ -193,21 +206,35 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
|||
//
|
||||
// and that the blockhash of the constructed block matches the parameters. Nil
|
||||
// Withdrawals value will propagate through the returned block. Empty
|
||||
// Withdrawals value must be passed via non-nil, length 0 value in params.
|
||||
func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
|
||||
txs, err := decodeTransactions(params.Transactions)
|
||||
// Withdrawals value must be passed via non-nil, length 0 value in data.
|
||||
func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
|
||||
block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(params.ExtraData) > 32 {
|
||||
return nil, fmt.Errorf("invalid extradata length: %v", len(params.ExtraData))
|
||||
if block.Hash() != data.BlockHash {
|
||||
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
|
||||
}
|
||||
if len(params.LogsBloom) != 256 {
|
||||
return nil, fmt.Errorf("invalid logsBloom length: %v", len(params.LogsBloom))
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used
|
||||
// for stateless execution, so it skips checking if the executable data hashes to
|
||||
// the requested hash (stateless has to *compute* the root hash, it's not given).
|
||||
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
|
||||
txs, err := decodeTransactions(data.Transactions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(data.ExtraData) > int(params.MaximumExtraDataSize) {
|
||||
return nil, fmt.Errorf("invalid extradata length: %v", len(data.ExtraData))
|
||||
}
|
||||
if len(data.LogsBloom) != 256 {
|
||||
return nil, fmt.Errorf("invalid logsBloom length: %v", len(data.LogsBloom))
|
||||
}
|
||||
// Check that baseFeePerGas is not negative or too big
|
||||
if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) {
|
||||
return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas)
|
||||
if data.BaseFeePerGas != nil && (data.BaseFeePerGas.Sign() == -1 || data.BaseFeePerGas.BitLen() > 256) {
|
||||
return nil, fmt.Errorf("invalid baseFeePerGas: %v", data.BaseFeePerGas)
|
||||
}
|
||||
var blobHashes = make([]common.Hash, 0, len(txs))
|
||||
for _, tx := range txs {
|
||||
|
|
@ -225,59 +252,73 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash,
|
|||
// ExecutableData before withdrawals are enabled by marshaling
|
||||
// Withdrawals as the json null value.
|
||||
var withdrawalsRoot *common.Hash
|
||||
if params.Withdrawals != nil {
|
||||
h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil))
|
||||
if data.Withdrawals != nil {
|
||||
h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil))
|
||||
withdrawalsRoot = &h
|
||||
}
|
||||
// Compute requestsHash if any requests are non-nil.
|
||||
var (
|
||||
requestsHash *common.Hash
|
||||
requests types.Requests
|
||||
)
|
||||
if data.Deposits != nil {
|
||||
requests = make(types.Requests, 0)
|
||||
for _, d := range data.Deposits {
|
||||
requests = append(requests, types.NewRequest(d))
|
||||
}
|
||||
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
|
||||
requestsHash = &h
|
||||
}
|
||||
header := &types.Header{
|
||||
ParentHash: params.ParentHash,
|
||||
ParentHash: data.ParentHash,
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
Coinbase: params.FeeRecipient,
|
||||
Root: params.StateRoot,
|
||||
Coinbase: data.FeeRecipient,
|
||||
Root: data.StateRoot,
|
||||
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
|
||||
ReceiptHash: params.ReceiptsRoot,
|
||||
Bloom: types.BytesToBloom(params.LogsBloom),
|
||||
ReceiptHash: data.ReceiptsRoot,
|
||||
Bloom: types.BytesToBloom(data.LogsBloom),
|
||||
Difficulty: common.Big0,
|
||||
Number: new(big.Int).SetUint64(params.Number),
|
||||
GasLimit: params.GasLimit,
|
||||
GasUsed: params.GasUsed,
|
||||
Time: params.Timestamp,
|
||||
BaseFee: params.BaseFeePerGas,
|
||||
Extra: params.ExtraData,
|
||||
MixDigest: params.Random,
|
||||
Number: new(big.Int).SetUint64(data.Number),
|
||||
GasLimit: data.GasLimit,
|
||||
GasUsed: data.GasUsed,
|
||||
Time: data.Timestamp,
|
||||
BaseFee: data.BaseFeePerGas,
|
||||
Extra: data.ExtraData,
|
||||
MixDigest: data.Random,
|
||||
WithdrawalsHash: withdrawalsRoot,
|
||||
ExcessBlobGas: params.ExcessBlobGas,
|
||||
BlobGasUsed: params.BlobGasUsed,
|
||||
ExcessBlobGas: data.ExcessBlobGas,
|
||||
BlobGasUsed: data.BlobGasUsed,
|
||||
ParentBeaconRoot: beaconRoot,
|
||||
RequestsHash: requestsHash,
|
||||
}
|
||||
block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: params.Withdrawals})
|
||||
if block.Hash() != params.BlockHash {
|
||||
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash())
|
||||
}
|
||||
return block, nil
|
||||
return types.NewBlockWithHeader(header).
|
||||
WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests}).
|
||||
WithWitness(data.ExecutionWitness),
|
||||
nil
|
||||
}
|
||||
|
||||
// BlockToExecutableData constructs the ExecutableData structure by filling the
|
||||
// fields from the given block. It assumes the given block is post-merge block.
|
||||
func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar) *ExecutionPayloadEnvelope {
|
||||
data := &ExecutableData{
|
||||
BlockHash: block.Hash(),
|
||||
ParentHash: block.ParentHash(),
|
||||
FeeRecipient: block.Coinbase(),
|
||||
StateRoot: block.Root(),
|
||||
Number: block.NumberU64(),
|
||||
GasLimit: block.GasLimit(),
|
||||
GasUsed: block.GasUsed(),
|
||||
BaseFeePerGas: block.BaseFee(),
|
||||
Timestamp: block.Time(),
|
||||
ReceiptsRoot: block.ReceiptHash(),
|
||||
LogsBloom: block.Bloom().Bytes(),
|
||||
Transactions: encodeTransactions(block.Transactions()),
|
||||
Random: block.MixDigest(),
|
||||
ExtraData: block.Extra(),
|
||||
Withdrawals: block.Withdrawals(),
|
||||
BlobGasUsed: block.BlobGasUsed(),
|
||||
ExcessBlobGas: block.ExcessBlobGas(),
|
||||
BlockHash: block.Hash(),
|
||||
ParentHash: block.ParentHash(),
|
||||
FeeRecipient: block.Coinbase(),
|
||||
StateRoot: block.Root(),
|
||||
Number: block.NumberU64(),
|
||||
GasLimit: block.GasLimit(),
|
||||
GasUsed: block.GasUsed(),
|
||||
BaseFeePerGas: block.BaseFee(),
|
||||
Timestamp: block.Time(),
|
||||
ReceiptsRoot: block.ReceiptHash(),
|
||||
LogsBloom: block.Bloom().Bytes(),
|
||||
Transactions: encodeTransactions(block.Transactions()),
|
||||
Random: block.MixDigest(),
|
||||
ExtraData: block.Extra(),
|
||||
Withdrawals: block.Withdrawals(),
|
||||
BlobGasUsed: block.BlobGasUsed(),
|
||||
ExcessBlobGas: block.ExcessBlobGas(),
|
||||
ExecutionWitness: block.ExecutionWitness(),
|
||||
}
|
||||
bundle := BlobsBundleV1{
|
||||
Commitments: make([]hexutil.Bytes, 0),
|
||||
|
|
@ -291,13 +332,30 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
|
|||
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
|
||||
}
|
||||
}
|
||||
setRequests(block.Requests(), data)
|
||||
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
|
||||
}
|
||||
|
||||
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
|
||||
type ExecutionPayloadBodyV1 struct {
|
||||
// setRequests differentiates the different request types and
|
||||
// assigns them to the associated fields in ExecutableData.
|
||||
func setRequests(requests types.Requests, data *ExecutableData) {
|
||||
if requests != nil {
|
||||
// If requests is non-nil, it means deposits are available in block and we
|
||||
// should return an empty slice instead of nil if there are no deposits.
|
||||
data.Deposits = make(types.Deposits, 0)
|
||||
}
|
||||
for _, r := range requests {
|
||||
if d, ok := r.Inner().(*types.Deposit); ok {
|
||||
data.Deposits = append(data.Deposits, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange
|
||||
type ExecutionPayloadBody struct {
|
||||
TransactionData []hexutil.Bytes `json:"transactions"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
Deposits types.Deposits `json:"depositRequests"`
|
||||
}
|
||||
|
||||
// Client identifiers to support ClientVersionV1.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -120,8 +122,12 @@ func NewBeaconLightApi(url string, customHeaders map[string]string) *BeaconLight
|
|||
}
|
||||
}
|
||||
|
||||
func (api *BeaconLightApi) httpGet(path string) ([]byte, error) {
|
||||
req, err := http.NewRequest("GET", api.url+path, nil)
|
||||
func (api *BeaconLightApi) httpGet(path string, params url.Values) ([]byte, error) {
|
||||
uri, err := api.buildURL(path, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := http.NewRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -145,17 +151,16 @@ func (api *BeaconLightApi) httpGet(path string) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (api *BeaconLightApi) httpGetf(format string, params ...any) ([]byte, error) {
|
||||
return api.httpGet(fmt.Sprintf(format, params...))
|
||||
}
|
||||
|
||||
// GetBestUpdatesAndCommittees fetches and validates LightClientUpdate for given
|
||||
// period and full serialized committee for the next period (committee root hash
|
||||
// equals update.NextSyncCommitteeRoot).
|
||||
// Note that the results are validated but the update signature should be verified
|
||||
// by the caller as its validity depends on the update chain.
|
||||
func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64) ([]*types.LightClientUpdate, []*types.SerializedSyncCommittee, error) {
|
||||
resp, err := api.httpGetf("/eth/v1/beacon/light_client/updates?start_period=%d&count=%d", firstPeriod, count)
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/updates", map[string][]string{
|
||||
"start_period": {strconv.FormatUint(firstPeriod, 10)},
|
||||
"count": {strconv.FormatUint(count, 10)},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -192,7 +197,7 @@ func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64
|
|||
// See data structure definition here:
|
||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
|
||||
func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error) {
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update")
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update", nil)
|
||||
if err != nil {
|
||||
return types.OptimisticUpdate{}, err
|
||||
}
|
||||
|
|
@ -245,7 +250,7 @@ func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) {
|
|||
// See data structure definition here:
|
||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
|
||||
func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) {
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update")
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update", nil)
|
||||
if err != nil {
|
||||
return types.FinalityUpdate{}, err
|
||||
}
|
||||
|
|
@ -311,7 +316,7 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool,
|
|||
} else {
|
||||
blockId = blockRoot.Hex()
|
||||
}
|
||||
resp, err := api.httpGetf("/eth/v1/beacon/headers/%s", blockId)
|
||||
resp, err := api.httpGet(fmt.Sprintf("/eth/v1/beacon/headers/%s", blockId), nil)
|
||||
if err != nil {
|
||||
return types.Header{}, false, false, err
|
||||
}
|
||||
|
|
@ -342,7 +347,7 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool,
|
|||
|
||||
// GetCheckpointData fetches and validates bootstrap data belonging to the given checkpoint.
|
||||
func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types.BootstrapData, error) {
|
||||
resp, err := api.httpGetf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:])
|
||||
resp, err := api.httpGet(fmt.Sprintf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:]), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -384,7 +389,7 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types
|
|||
}
|
||||
|
||||
func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconBlock, error) {
|
||||
resp, err := api.httpGetf("/eth/v2/beacon/blocks/0x%x", blockRoot)
|
||||
resp, err := api.httpGet(fmt.Sprintf("/eth/v2/beacon/blocks/0x%x", blockRoot), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -545,9 +550,13 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
|
|||
// established. It can only return nil when the context is canceled.
|
||||
func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream {
|
||||
for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) {
|
||||
path := "/eth/v1/events?topics=head&topics=light_client_finality_update&topics=light_client_optimistic_update"
|
||||
log.Trace("Sending event subscription request")
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil)
|
||||
uri, err := api.buildURL("/eth/v1/events", map[string][]string{"topics": {"head", "light_client_finality_update", "light_client_optimistic_update"}})
|
||||
if err != nil {
|
||||
listener.OnError(fmt.Errorf("error creating event subscription URL: %v", err))
|
||||
continue
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", uri, nil)
|
||||
if err != nil {
|
||||
listener.OnError(fmt.Errorf("error creating event subscription request: %v", err))
|
||||
continue
|
||||
|
|
@ -576,3 +585,15 @@ func ctxSleep(ctx context.Context, timeout time.Duration) (ok bool) {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (api *BeaconLightApi) buildURL(path string, params url.Values) (string, error) {
|
||||
uri, err := url.Parse(api.url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
uri = uri.JoinPath(path)
|
||||
if params != nil {
|
||||
uri.RawQuery = params.Encode()
|
||||
}
|
||||
return uri.String(), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,6 +201,34 @@ func TestUpdateSyncDifferentHeads(t *testing.T) {
|
|||
chain.ExpNextSyncPeriod(t, 17)
|
||||
}
|
||||
|
||||
func TestRangeLock(t *testing.T) {
|
||||
r := make(rangeLock)
|
||||
|
||||
// Lock from 0 to 99.
|
||||
r.lock(0, 100, 1)
|
||||
for i := 0; i < 100; i++ {
|
||||
if v, ok := r[uint64(i)]; v <= 0 || !ok {
|
||||
t.Fatalf("integer space: %d not locked", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock from 0 to 99.
|
||||
r.lock(0, 100, -1)
|
||||
for i := 0; i < 100; i++ {
|
||||
if v, ok := r[uint64(i)]; v > 0 || ok {
|
||||
t.Fatalf("integer space: %d is locked", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Lock from 0 to 99 then unlock from 10 to 59.
|
||||
r.lock(0, 100, 1)
|
||||
r.lock(10, 50, -1)
|
||||
first, count := r.firstUnlocked(0, 100)
|
||||
if first != 10 || count != 50 {
|
||||
t.Fatalf("unexpected first: %d or count: %d", first, count)
|
||||
}
|
||||
}
|
||||
|
||||
func testRespUpdate(request requestWithID) request.Response {
|
||||
var resp RespUpdates
|
||||
if request.request == nil {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) {
|
|||
case "capella":
|
||||
obj = new(capella.BeaconBlock)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported fork: " + forkName)
|
||||
return nil, fmt.Errorf("unsupported fork: %s", forkName)
|
||||
}
|
||||
if err := json.Unmarshal(data, obj); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, er
|
|||
case "deneb":
|
||||
obj = new(deneb.ExecutionPayloadHeader)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported fork: " + forkName)
|
||||
return nil, fmt.Errorf("unsupported fork: %s", forkName)
|
||||
}
|
||||
if err := json.Unmarshal(data, obj); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -5,55 +5,56 @@
|
|||
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
||||
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
||||
|
||||
# version:golang 1.22.5
|
||||
# version:golang 1.23.1
|
||||
# https://go.dev/dl/
|
||||
ac9c723f224969aee624bc34fd34c9e13f2a212d75c71c807de644bb46e112f6 go1.22.5.src.tar.gz
|
||||
c82ba3403c45a4aa4b84b08244656a51e55b86fb130dcc500f5291d0f3b12222 go1.22.5.aix-ppc64.tar.gz
|
||||
8a8872b1bac959b3b76f2e3978c46406d22a54a99c83ca55840ca08b4f2960bc go1.22.5.darwin-amd64.pkg
|
||||
95d9933cdcf45f211243c42c7705c37353cccd99f27eb4d8e2d1bf2f4165cb50 go1.22.5.darwin-amd64.tar.gz
|
||||
8c943512d1fa4e849f0078b03721df02aac19d8bb872dd17ab3ee7127ae6b732 go1.22.5.darwin-arm64.pkg
|
||||
4cd1bcb05be03cecb77bccd765785d5ff69d79adf4dd49790471d00c06b41133 go1.22.5.darwin-arm64.tar.gz
|
||||
1f1f035e968a877cd8ed62adae6edb2feeee62470660b7587ddcb904a3877a21 go1.22.5.dragonfly-amd64.tar.gz
|
||||
d660698411465531d475ec1c617fdb415df68740f3511138a8d15506665a06f9 go1.22.5.freebsd-386.tar.gz
|
||||
75f43ef46c2ad46c534ded25d26fba9bef036fc07074dfa45c0b3b90856a8151 go1.22.5.freebsd-amd64.tar.gz
|
||||
75614714e7e4a4dd721f0eddd6555b3f6afc4c07e59c1b9b769cf663996165f9 go1.22.5.freebsd-arm.tar.gz
|
||||
1377d0d7233f1b8f4cb8e3456f2e7ed44aca4a95daab79ae09605d34aa967c6b go1.22.5.freebsd-arm64.tar.gz
|
||||
07baf198587abc05ea789dbe5810a2d6612ad56a51718bbf74de2c93bdbe676a go1.22.5.freebsd-riscv64.tar.gz
|
||||
c0bd4f0d44252f3ec93ca850a41b167bb868179c7c283f8af9439e73b2654b17 go1.22.5.illumos-amd64.tar.gz
|
||||
3ea4c78e6fa52978ae1ed2e5927ad17495da440c9fae7787b1ebc1d0572f7f43 go1.22.5.linux-386.tar.gz
|
||||
904b924d435eaea086515bc63235b192ea441bd8c9b198c507e85009e6e4c7f0 go1.22.5.linux-amd64.tar.gz
|
||||
8d21325bfcf431be3660527c1a39d3d9ad71535fabdf5041c826e44e31642b5a go1.22.5.linux-arm64.tar.gz
|
||||
8c4587cf3e63c9aefbcafa92818c4d9d51683af93ea687bf6c7508d6fa36f85e go1.22.5.linux-armv6l.tar.gz
|
||||
780e2eeb6376a763c564f776eaac6700f33f95e29302faa54b040b19cb1f6fd2 go1.22.5.linux-loong64.tar.gz
|
||||
f784aa1adfb605da3bfe8cd534b545bddae3eb893e9302f7c2f5d44656b1cae2 go1.22.5.linux-mips.tar.gz
|
||||
aaa3756571467768388f2ab641a02ff54f98f1684808cda047a7be3026e4b438 go1.22.5.linux-mips64.tar.gz
|
||||
b7956d925c9ef5a4dc53017feaed2d78dba5d0a1036bad5ea513f1f15ba08fbc go1.22.5.linux-mips64le.tar.gz
|
||||
7baf605be9b787acd750b6b48a91818a5590ec9289b14aea5696a46b41853888 go1.22.5.linux-mipsle.tar.gz
|
||||
f09b2a6c1a409662e8e8fe267e1eabeba0a1fd00eb1422fd88297b013803952e go1.22.5.linux-ppc64.tar.gz
|
||||
5312bb420ac0b59175a58927e70b4660b14ab7319aab54398b6071fabcbfbb09 go1.22.5.linux-ppc64le.tar.gz
|
||||
f8d0c7d96b336f4133409ff9da7241cfe91e65723c2e8e7c7f9b58a9f9603476 go1.22.5.linux-riscv64.tar.gz
|
||||
24c6c5c9d515adea5d58ae78388348c97614a0c21ac4d4f4c0dab75e893b0b5d go1.22.5.linux-s390x.tar.gz
|
||||
39144c62acbaa85e4f1ab57bad8f5b3dc67d6fa24b711ec1fa593f4a0ea1fe91 go1.22.5.netbsd-386.tar.gz
|
||||
118f79640588eb878529b46cdf56599012da6575f0ac07069ec1e9a8e78ddd0b go1.22.5.netbsd-amd64.tar.gz
|
||||
d39c2b94ae3fd0a6399e545cbecb673496293075291bd98ef15f24d21625a490 go1.22.5.netbsd-arm.tar.gz
|
||||
f7fb617d10c39248996521d72370db82d50724fa894089c76ae4298fbbe1fb0b go1.22.5.netbsd-arm64.tar.gz
|
||||
e0f778a34746587ae7c18e8a24cfaba1b2eaabce75d0ceb470adf576ad1cd90f go1.22.5.openbsd-386.tar.gz
|
||||
b417311df26ef7ae8b34fcb991519a5c496010561c12386d9469aea03c1bdf0b go1.22.5.openbsd-amd64.tar.gz
|
||||
e78e8ad05605d530a4f79e55031c7c65f2020a9d442e05d490bd08f0d947a34f go1.22.5.openbsd-arm.tar.gz
|
||||
8027898948f17742717786ead2ff2e960ee1fc82995d6edbad0050d551710f59 go1.22.5.openbsd-arm64.tar.gz
|
||||
99c5b81d75bcc0d83d25dedc9535682c42c0e761276c88bcc4db6340344644fd go1.22.5.openbsd-ppc64.tar.gz
|
||||
30d5dacdee0481f0b8cabb75b706465e2177c3a4a1d1c46293332f4b90a3d199 go1.22.5.plan9-386.tar.gz
|
||||
65628650cd7665387cfe6fa386c381f4de1ef7b03a12067ae9ccf06d2feaea2c go1.22.5.plan9-amd64.tar.gz
|
||||
322541cbfc9ae95b48b9eec4eb45df48299784592e23121084f790cf1082787e go1.22.5.plan9-arm.tar.gz
|
||||
87c590e3eb81fcffa3dc1524c03c2847f0890e95c2a43586e82b56c262eb03d8 go1.22.5.solaris-amd64.tar.gz
|
||||
3ec89ed822b38f4483977a90913fbe39d0857f0ed16c4642dec1950ddbe8c943 go1.22.5.windows-386.msi
|
||||
c44fc421075022add78fbf8db38519dd5520a11832749be2189e64b3cf4f02f9 go1.22.5.windows-386.zip
|
||||
86b0299ab8cb9c44882a9080dac03f7f4d9546f51ed1ba1015599114bcbc66d0 go1.22.5.windows-amd64.msi
|
||||
59968438b8d90f108fd240d4d2f95b037e59716995f7409e0a322dcb996e9f42 go1.22.5.windows-amd64.zip
|
||||
013d3b300e6b8f26482d6dd17b02830b83ee63795498bd8c0c9d80bb2c4d6cf7 go1.22.5.windows-arm.msi
|
||||
8cc860630a84e2dbff3e84280f46a571741f26f8a1819aa4fbcb3164fdd51312 go1.22.5.windows-arm.zip
|
||||
8f90519d9f305f2caa05d1d4fb0656b50f1bf89d76e194279f480e5a484c891f go1.22.5.windows-arm64.msi
|
||||
6717d5841162aa8c05f932eb74a643f1310b8a88f80f0830e86d194289734bbf go1.22.5.windows-arm64.zip
|
||||
6ee44e298379d146a5e5aa6b1c5b5d5f5d0a3365eabdd70741e6e21340ec3b0d go1.23.1.src.tar.gz
|
||||
f17f2791717c15728ec63213a014e244c35f9c8846fb29f5a1b63d0c0556f756 go1.23.1.aix-ppc64.tar.gz
|
||||
dd9e772686ed908bcff94b6144322d4e2473a7dcd7c696b7e8b6d12f23c887fd go1.23.1.darwin-amd64.pkg
|
||||
488d9e4ca3e3ed513ee4edd91bef3a2360c65fa6d6be59cf79640bf840130a58 go1.23.1.darwin-amd64.tar.gz
|
||||
be34b488157ec69d94e26e1554558219a2c90789bcb7e3686965a7f9c8cfcbe7 go1.23.1.darwin-arm64.pkg
|
||||
e223795ca340e285a760a6446ce57a74500b30e57469a4109961d36184d3c05a go1.23.1.darwin-arm64.tar.gz
|
||||
6af626176923a6ae6c5de6dc1c864f38365793c0e4ecd0d6eab847bdc23953e5 go1.23.1.dragonfly-amd64.tar.gz
|
||||
cc957c1a019702e6cdc2e257202d42799011ebc1968b6c3bcd6b1965952607d5 go1.23.1.freebsd-386.tar.gz
|
||||
a7d57781c50bb80886a8f04066791956d45aa3eea0f83070c5268b6223afb2ff go1.23.1.freebsd-amd64.tar.gz
|
||||
c7b09f3fef456048e596db9bea746eb66796aeb82885622b0388feee18f36a3e go1.23.1.freebsd-arm.tar.gz
|
||||
b05cd6a77995a0c8439d88df124811c725fb78b942d0b6dd1643529d7ba62f1f go1.23.1.freebsd-arm64.tar.gz
|
||||
56236ae70be1613f2915943b94f53c96be5bffc0719314078facd778a89bc57e go1.23.1.freebsd-riscv64.tar.gz
|
||||
8644c52df4e831202114fd67c9fcaf1f7233ad27bf945ac53fa7217cf1a0349f go1.23.1.illumos-amd64.tar.gz
|
||||
cdee2f4e2efa001f7ee75c90f2efc310b63346cfbba7b549987e9139527c6b17 go1.23.1.linux-386.tar.gz
|
||||
49bbb517cfa9eee677e1e7897f7cf9cfdbcf49e05f61984a2789136de359f9bd go1.23.1.linux-amd64.tar.gz
|
||||
faec7f7f8ae53fda0f3d408f52182d942cc89ef5b7d3d9f23ff117437d4b2d2f go1.23.1.linux-arm64.tar.gz
|
||||
6c7832c7dcd8fb6d4eb308f672a725393403c74ee7be1aeccd8a443015df99de go1.23.1.linux-armv6l.tar.gz
|
||||
649ce3856ddc808c00b14a46232eab0bf95e7911cdf497010b17d76656f5ca4e go1.23.1.linux-loong64.tar.gz
|
||||
201911048f234e5a0c51ec94b1a11d4e47062fee4398b1d2faa6c820dc026724 go1.23.1.linux-mips.tar.gz
|
||||
2bce3743df463915e45d2612f9476ffb03d0b3750b1cb3879347de08715b5fc6 go1.23.1.linux-mips64.tar.gz
|
||||
54e301f266e33431b0703136e0bbd4cf02461b1ecedd37b7cbd90cb862a98e5f go1.23.1.linux-mips64le.tar.gz
|
||||
8efd495e93d17408c0803595cdc3bf13cb28e0f957aeabd9cc18245fb8e64019 go1.23.1.linux-mipsle.tar.gz
|
||||
52bd68689095831ad9af7160844c23b28bb8d0acd268de7e300ff5f0662b7a07 go1.23.1.linux-ppc64.tar.gz
|
||||
042888cae54b5fbfd9dd1e3b6bc4a5134879777fe6497fc4c62ec394b5ecf2da go1.23.1.linux-ppc64le.tar.gz
|
||||
1a4a609f0391bea202d9095453cbfaf7368fa88a04c206bf9dd715a738664dc3 go1.23.1.linux-riscv64.tar.gz
|
||||
47dc49ad45c45e192efa0df7dc7bc5403f5f2d15b5d0dc74ef3018154b616f4d go1.23.1.linux-s390x.tar.gz
|
||||
fbfbd5efa6a5d581ea7f5e65015f927db0e52135cab057e43d39d5482da54b61 go1.23.1.netbsd-386.tar.gz
|
||||
e96e1cc5cf36113ee6099d1a7306b22cd9c3f975a36bdff954c59f104f22b853 go1.23.1.netbsd-amd64.tar.gz
|
||||
c394dfc06bfc276a591209a37e09cd39089ec9a9cc3db30b94814ce2e39eb1d4 go1.23.1.netbsd-arm.tar.gz
|
||||
b3b35d64f32821a68b3e2994032dbefb81978f2ec3f218c7a770623b82d36b8e go1.23.1.netbsd-arm64.tar.gz
|
||||
3c775c4c16c182e33c2c4ac090d9a247a93b3fb18a3df01d87d490f29599faff go1.23.1.openbsd-386.tar.gz
|
||||
5edbe53b47c57b32707fd7154536fbe9eaa79053fea01650c93b54cdba13fc0f go1.23.1.openbsd-amd64.tar.gz
|
||||
c30903dd8fa98b8aca8e9db0962ce9f55502aed93e0ef41e5ae148aaa0088de1 go1.23.1.openbsd-arm.tar.gz
|
||||
12da183489e58f9c6b357bc1b626f85ed7d4220cab31a49d6a49e6ac6a718b67 go1.23.1.openbsd-arm64.tar.gz
|
||||
9cc9aad37696a4a10c31dcec9e35a308de0b369dad354d54cf07406ac6fa7c6f go1.23.1.openbsd-ppc64.tar.gz
|
||||
e1d740dda062ce5a276a0c3ed7d8b6353238bc8ff405f63e2e3480bfd26a5ec5 go1.23.1.openbsd-riscv64.tar.gz
|
||||
da2a37f9987f01f096859230aa13ecc4ad2e7884465bce91004bc78c64435d65 go1.23.1.plan9-386.tar.gz
|
||||
fd8fff8b0697d55c4a4d02a8dc998192b80a9dc2a057647373d6ff607cad29de go1.23.1.plan9-amd64.tar.gz
|
||||
52efbc5804c1c86ba7868aa8ebbc31cc8c2a27b62a60fd57944970d48fc67525 go1.23.1.plan9-arm.tar.gz
|
||||
f54205f21e2143f2ada1bf1c00ddf64590f5139d5c3fb77cc06175f0d8cc7567 go1.23.1.solaris-amd64.tar.gz
|
||||
369a17f0cfd29e5c848e58ffe0d772da20abe334d1c7ca01dbcd55bb3db0b440 go1.23.1.windows-386.msi
|
||||
ab866f47d7be56e6b1c67f1d529bf4c23331a339fb0785f435a0552d352cb257 go1.23.1.windows-386.zip
|
||||
e99dac215ee437b9bb8f8b14bbfe0e8756882c1ed291f30818e8363bc9c047a5 go1.23.1.windows-amd64.msi
|
||||
32dedf277c86610e380e1765593edb66876f00223df71690bd6be68ee17675c0 go1.23.1.windows-amd64.zip
|
||||
23169c79dc6b54e0dffb25be6b67425ad9759392a58309bc057430a9bf4c8f6a go1.23.1.windows-arm.msi
|
||||
1a57615a09f13534f88e9f2d7efd5743535d1a5719b19e520eef965a634f8efb go1.23.1.windows-arm.zip
|
||||
313e1a543931ad8735b4df8969e00f5f4c2ef07be21f54015ede961a70263d35 go1.23.1.windows-arm64.msi
|
||||
64ad0954d2c33f556fb1018d62de091254aa6e3a94f1c8a8b16af0d3701d194e go1.23.1.windows-arm64.zip
|
||||
|
||||
# version:golangci 1.59.0
|
||||
# https://github.com/golangci/golangci-lint/releases/
|
||||
|
|
|
|||
82
build/ci.go
82
build/ci.go
|
|
@ -126,8 +126,6 @@ var (
|
|||
"focal", // 20.04, EOL: 04/2030
|
||||
"jammy", // 22.04, EOL: 04/2032
|
||||
"noble", // 24.04, EOL: 04/2034
|
||||
|
||||
"mantic", // 23.10, EOL: 07/2024
|
||||
}
|
||||
|
||||
// This is where the tests should be unpacked.
|
||||
|
|
@ -239,6 +237,10 @@ func doInstall(cmdline []string) {
|
|||
// buildFlags returns the go tool flags for building.
|
||||
func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) {
|
||||
var ld []string
|
||||
// See https://github.com/golang/go/issues/33772#issuecomment-528176001
|
||||
// We need to set --buildid to the linker here, and also pass --build-id to the
|
||||
// cgo-linker further down.
|
||||
ld = append(ld, "--buildid=none")
|
||||
if env.Commit != "" {
|
||||
ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitCommit="+env.Commit)
|
||||
ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitDate="+env.Date)
|
||||
|
|
@ -251,7 +253,11 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (
|
|||
if runtime.GOOS == "linux" {
|
||||
// Enforce the stacksize to 8M, which is the case on most platforms apart from
|
||||
// alpine Linux.
|
||||
extld := []string{"-Wl,-z,stack-size=0x800000"}
|
||||
// See https://sourceware.org/binutils/docs-2.23.1/ld/Options.html#Options
|
||||
// regarding the options --build-id=none and --strip-all. It is needed for
|
||||
// reproducible builds; removing references to temporary files in C-land, and
|
||||
// making build-id reproducably absent.
|
||||
extld := []string{"-Wl,-z,stack-size=0x800000,--build-id=none,--strip-all"}
|
||||
if staticLinking {
|
||||
extld = append(extld, "-static")
|
||||
// Under static linking, use of certain glibc features must be
|
||||
|
|
@ -298,7 +304,7 @@ func doTest(cmdline []string) {
|
|||
gotest := tc.Go("test")
|
||||
|
||||
// CI needs a bit more time for the statetests (default 10m).
|
||||
gotest.Args = append(gotest.Args, "-timeout=20m")
|
||||
gotest.Args = append(gotest.Args, "-timeout=30m")
|
||||
|
||||
// Enable CKZG backend in CI.
|
||||
gotest.Args = append(gotest.Args, "-tags=ckzg")
|
||||
|
|
@ -349,10 +355,10 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
|
|||
return filepath.Join(cachedir, base)
|
||||
}
|
||||
|
||||
// hashSourceFiles iterates all files under the top-level project directory
|
||||
// hashAllSourceFiles iterates all files under the top-level project directory
|
||||
// computing the hash of each file (excluding files within the tests
|
||||
// subrepo)
|
||||
func hashSourceFiles() (map[string]common.Hash, error) {
|
||||
func hashAllSourceFiles() (map[string]common.Hash, error) {
|
||||
res := make(map[string]common.Hash)
|
||||
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
|
||||
if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) {
|
||||
|
|
@ -379,6 +385,56 @@ func hashSourceFiles() (map[string]common.Hash, error) {
|
|||
return res, nil
|
||||
}
|
||||
|
||||
// hashSourceFiles iterates the provided set of filepaths (relative to the top-level geth project directory)
|
||||
// computing the hash of each file.
|
||||
func hashSourceFiles(files []string) (map[string]common.Hash, error) {
|
||||
res := make(map[string]common.Hash)
|
||||
for _, filePath := range files {
|
||||
f, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hasher := sha256.New()
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res[filePath] = common.Hash(hasher.Sum(nil))
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// compareHashedFilesets compares two maps (key is relative file path to top-level geth directory, value is its hash)
|
||||
// and returns the list of file paths whose hashes differed.
|
||||
func compareHashedFilesets(preHashes map[string]common.Hash, postHashes map[string]common.Hash) []string {
|
||||
updates := []string{}
|
||||
for path, postHash := range postHashes {
|
||||
preHash, ok := preHashes[path]
|
||||
if !ok || preHash != postHash {
|
||||
updates = append(updates, path)
|
||||
}
|
||||
}
|
||||
return updates
|
||||
}
|
||||
|
||||
func doGoModTidy() {
|
||||
targetFiles := []string{"go.mod", "go.sum"}
|
||||
preHashes, err := hashSourceFiles(targetFiles)
|
||||
if err != nil {
|
||||
log.Fatal("failed to hash go.mod/go.sum", "err", err)
|
||||
}
|
||||
tc := new(build.GoToolchain)
|
||||
c := tc.Go("mod", "tidy")
|
||||
build.MustRun(c)
|
||||
postHashes, err := hashSourceFiles(targetFiles)
|
||||
updates := compareHashedFilesets(preHashes, postHashes)
|
||||
for _, updatedFile := range updates {
|
||||
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
|
||||
}
|
||||
if len(updates) != 0 {
|
||||
log.Fatal("go.sum and/or go.mod were updated by running 'go mod tidy'")
|
||||
}
|
||||
}
|
||||
|
||||
// doGenerate ensures that re-generating generated files does not cause
|
||||
// any mutations in the source file tree: i.e. all generated files were
|
||||
// updated and committed. Any stale generated files are updated.
|
||||
|
|
@ -395,7 +451,7 @@ func doGenerate() {
|
|||
var preHashes map[string]common.Hash
|
||||
if *verify {
|
||||
var err error
|
||||
preHashes, err = hashSourceFiles()
|
||||
preHashes, err = hashAllSourceFiles()
|
||||
if err != nil {
|
||||
log.Fatal("failed to compute map of source hashes", "err", err)
|
||||
}
|
||||
|
|
@ -410,17 +466,11 @@ func doGenerate() {
|
|||
return
|
||||
}
|
||||
// Check if files were changed.
|
||||
postHashes, err := hashSourceFiles()
|
||||
postHashes, err := hashAllSourceFiles()
|
||||
if err != nil {
|
||||
log.Fatal("error computing source tree file hashes", "err", err)
|
||||
}
|
||||
updates := []string{}
|
||||
for path, postHash := range postHashes {
|
||||
preHash, ok := preHashes[path]
|
||||
if !ok || preHash != postHash {
|
||||
updates = append(updates, path)
|
||||
}
|
||||
}
|
||||
updates := compareHashedFilesets(preHashes, postHashes)
|
||||
for _, updatedFile := range updates {
|
||||
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
|
||||
}
|
||||
|
|
@ -443,6 +493,8 @@ func doLint(cmdline []string) {
|
|||
linter := downloadLinter(*cachedir)
|
||||
lflags := []string{"run", "--config", ".golangci.yml"}
|
||||
build.MustRunCommandWithOutput(linter, append(lflags, packages...)...)
|
||||
|
||||
doGoModTidy()
|
||||
fmt.Println("You have achieved perfection.")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,6 @@ package tools
|
|||
import (
|
||||
// Tool imports for go:generate.
|
||||
_ "github.com/fjl/gencodec"
|
||||
_ "github.com/golang/protobuf/protoc-gen-go"
|
||||
_ "golang.org/x/tools/cmd/stringer"
|
||||
_ "google.golang.org/protobuf/cmd/protoc-gen-go"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ func main() {
|
|||
//TODO datadir for optional permanent database
|
||||
utils.MainnetFlag,
|
||||
utils.SepoliaFlag,
|
||||
utils.GoerliFlag,
|
||||
utils.BlsyncApiFlag,
|
||||
utils.BlsyncJWTSecretFlag,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ GLOBAL OPTIONS:
|
|||
--loglevel value log level to emit to the screen (default: 4)
|
||||
--keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore")
|
||||
--configdir value Directory for Clef configuration (default: "$HOME/.clef")
|
||||
--chainid value Chain id to use for signing (1=mainnet, 5=Goerli) (default: 1)
|
||||
--chainid value Chain id to use for signing (1=mainnet, 17000=Holesky) (default: 1)
|
||||
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
|
||||
--nousb Disables monitoring for and managing USB hardware wallets
|
||||
--pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")
|
||||
|
|
|
|||
|
|
@ -27,9 +27,8 @@ import (
|
|||
// TestImportRaw tests clef --importraw
|
||||
func TestImportRaw(t *testing.T) {
|
||||
t.Parallel()
|
||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||
t.Cleanup(func() { os.Remove(keyPath) })
|
||||
|
||||
t.Run("happy-path", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
@ -68,9 +67,8 @@ func TestImportRaw(t *testing.T) {
|
|||
// TestListAccounts tests clef --list-accounts
|
||||
func TestListAccounts(t *testing.T) {
|
||||
t.Parallel()
|
||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||
t.Cleanup(func() { os.Remove(keyPath) })
|
||||
|
||||
t.Run("no-accounts", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
@ -97,9 +95,8 @@ func TestListAccounts(t *testing.T) {
|
|||
// TestListWallets tests clef --list-wallets
|
||||
func TestListWallets(t *testing.T) {
|
||||
t.Parallel()
|
||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||
t.Cleanup(func() { os.Remove(keyPath) })
|
||||
|
||||
t.Run("no-accounts", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ var (
|
|||
chainIdFlag = &cli.Int64Flag{
|
||||
Name: "chainid",
|
||||
Value: params.MainnetChainConfig.ChainID.Int64(),
|
||||
Usage: "Chain id to use for signing (1=mainnet, 5=Goerli)",
|
||||
Usage: "Chain id to use for signing (1=mainnet, 17000=Holesky)",
|
||||
}
|
||||
rpcPortFlag = &cli.IntFlag{
|
||||
Name: "http.port",
|
||||
|
|
|
|||
|
|
@ -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/holesky>` filters nodes by "eth" ENR entry
|
||||
- `-eth-network <mainnet/sepolia/holesky>` filters nodes by "eth" ENR entry
|
||||
- `-les-server` filters nodes by LES server support
|
||||
- `-snap` filters nodes by snap protocol support
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,8 @@ func (c *cloudflareClient) checkZone(name string) error {
|
|||
if !strings.HasSuffix(name, "."+zone.Name) {
|
||||
return fmt.Errorf("CloudFlare zone name %q does not match name %q to be deployed", zone.Name, name)
|
||||
}
|
||||
needPerms := map[string]bool{"#zone:edit": false, "#zone:read": false}
|
||||
// Necessary permissions for Cloudlare management - Zone:Read, DNS:Read, Zone:Edit, DNS:Edit
|
||||
needPerms := map[string]bool{"#zone:edit": false, "#zone:read": false, "#dns_records:read": false, "#dns_records:edit": false}
|
||||
for _, perm := range zone.Permissions {
|
||||
if _, ok := needPerms[perm]; ok {
|
||||
needPerms[perm] = true
|
||||
|
|
|
|||
|
|
@ -849,7 +849,16 @@ func (s *Suite) TestBlobViolations(t *utesting.T) {
|
|||
if code, _, err := conn.Read(); err != nil {
|
||||
t.Fatalf("expected disconnect on blob violation, got err: %v", err)
|
||||
} else if code != discMsg {
|
||||
t.Fatalf("expected disconnect on blob violation, got msg code: %d", code)
|
||||
if code == protoOffset(ethProto)+eth.NewPooledTransactionHashesMsg {
|
||||
// sometimes we'll get a blob transaction hashes announcement before the disconnect
|
||||
// because blob transactions are scheduled to be fetched right away.
|
||||
if code, _, err = conn.Read(); err != nil {
|
||||
t.Fatalf("expected disconnect on blob violation, got err on second read: %v", err)
|
||||
}
|
||||
}
|
||||
if code != discMsg {
|
||||
t.Fatalf("expected disconnect on blob violation, got msg code: %d", code)
|
||||
}
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,12 +34,12 @@ import (
|
|||
"github.com/ethereum/go-ethereum/p2p"
|
||||
)
|
||||
|
||||
func makeJWTSecret() (string, [32]byte, error) {
|
||||
func makeJWTSecret(t *testing.T) (string, [32]byte, error) {
|
||||
var secret [32]byte
|
||||
if _, err := crand.Read(secret[:]); err != nil {
|
||||
return "", secret, fmt.Errorf("failed to create jwt secret: %v", err)
|
||||
}
|
||||
jwtPath := filepath.Join(os.TempDir(), "jwt_secret")
|
||||
jwtPath := filepath.Join(t.TempDir(), "jwt_secret")
|
||||
if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil {
|
||||
return "", secret, fmt.Errorf("failed to prepare jwt secret file: %v", err)
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ func makeJWTSecret() (string, [32]byte, error) {
|
|||
}
|
||||
|
||||
func TestEthSuite(t *testing.T) {
|
||||
jwtPath, secret, err := makeJWTSecret()
|
||||
jwtPath, secret, err := makeJWTSecret(t)
|
||||
if err != nil {
|
||||
t.Fatalf("could not make jwt secret: %v", err)
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ func TestEthSuite(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSnapSuite(t *testing.T) {
|
||||
jwtPath, secret, err := makeJWTSecret()
|
||||
jwtPath, secret, err := makeJWTSecret(t)
|
||||
if err != nil {
|
||||
t.Fatalf("could not make jwt secret: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -230,8 +230,6 @@ func ethFilter(args []string) (nodeFilter, error) {
|
|||
switch args[0] {
|
||||
case "mainnet":
|
||||
filter = forkid.NewStaticFilter(params.MainnetChainConfig, core.DefaultGenesisBlock().ToBlock())
|
||||
case "goerli":
|
||||
filter = forkid.NewStaticFilter(params.GoerliChainConfig, core.DefaultGoerliGenesisBlock().ToBlock())
|
||||
case "sepolia":
|
||||
filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock())
|
||||
case "holesky":
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ func rlpxPing(ctx *cli.Context) error {
|
|||
n := getNodeArg(ctx)
|
||||
tcpEndpoint, ok := n.TCPEndpoint()
|
||||
if !ok {
|
||||
return fmt.Errorf("node has no TCP endpoint")
|
||||
return errors.New("node has no TCP endpoint")
|
||||
}
|
||||
fd, err := net.Dial("tcp", tcpEndpoint.String())
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ type ExecutionResult struct {
|
|||
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
|
||||
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
||||
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
|
||||
RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
|
||||
DepositRequests *types.Deposits `json:"depositRequests,omitempty"`
|
||||
}
|
||||
|
||||
type ommer struct {
|
||||
|
|
@ -196,7 +198,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
|
||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
||||
}
|
||||
|
||||
if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) {
|
||||
var (
|
||||
prevNumber = pre.Env.Number - 1
|
||||
prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)]
|
||||
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
|
||||
)
|
||||
core.ProcessParentBlockHash(prevHash, evm, statedb)
|
||||
}
|
||||
for i := 0; txIt.Next(); i++ {
|
||||
tx, err := txIt.Tx()
|
||||
if err != nil {
|
||||
|
|
@ -370,9 +379,31 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
|
||||
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
|
||||
}
|
||||
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
|
||||
// Parse the requests from the logs
|
||||
var allLogs []*types.Log
|
||||
for _, receipt := range receipts {
|
||||
allLogs = append(allLogs, receipt.Logs...)
|
||||
}
|
||||
requests, err := core.ParseDepositLogs(allLogs, chainConfig)
|
||||
if err != nil {
|
||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
|
||||
}
|
||||
// Calculate the requests root
|
||||
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
|
||||
execRs.RequestsHash = &h
|
||||
// Get the deposits from the requests
|
||||
deposits := make(types.Deposits, 0)
|
||||
for _, req := range requests {
|
||||
if dep, ok := req.Inner().(*types.Deposit); ok {
|
||||
deposits = append(deposits, dep)
|
||||
}
|
||||
}
|
||||
execRs.DepositRequests = &deposits
|
||||
}
|
||||
// Re-create statedb instance with new root upon the updated database
|
||||
// for accessing latest states.
|
||||
statedb, err = state.New(root, statedb.Database(), nil)
|
||||
statedb, err = state.New(root, statedb.Database())
|
||||
if err != nil {
|
||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
|
||||
}
|
||||
|
|
@ -381,8 +412,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
}
|
||||
|
||||
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
|
||||
sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
||||
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
|
||||
tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
||||
sdb := state.NewDatabase(tdb, nil)
|
||||
statedb, _ := state.New(types.EmptyRootHash, sdb)
|
||||
for addr, a := range accounts {
|
||||
statedb.SetCode(addr, a.Code)
|
||||
statedb.SetNonce(addr, a.Nonce)
|
||||
|
|
@ -393,7 +425,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB
|
|||
}
|
||||
// Commit and re-open to start with a clean state.
|
||||
root, _ := statedb.Commit(0, false)
|
||||
statedb, _ = state.New(root, sdb, nil)
|
||||
statedb, _ = state.New(root, sdb)
|
||||
return statedb
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,14 +155,13 @@ func runCmd(ctx *cli.Context) error {
|
|||
})
|
||||
defer triedb.Close()
|
||||
genesis := genesisConfig.MustCommit(db, triedb)
|
||||
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
||||
statedb, _ = state.New(genesis.Root(), sdb, nil)
|
||||
sdb := state.NewDatabase(triedb, nil)
|
||||
statedb, _ = state.New(genesis.Root(), sdb)
|
||||
chainConfig = genesisConfig.Config
|
||||
|
||||
if ctx.String(SenderFlag.Name) != "" {
|
||||
sender = common.HexToAddress(ctx.String(SenderFlag.Name))
|
||||
}
|
||||
statedb.CreateAccount(sender)
|
||||
|
||||
if ctx.String(ReceiverFlag.Name) != "" {
|
||||
receiver = common.HexToAddress(ctx.String(ReceiverFlag.Name))
|
||||
|
|
@ -222,6 +221,7 @@ func runCmd(ctx *cli.Context) error {
|
|||
Time: genesisConfig.Timestamp,
|
||||
Coinbase: genesisConfig.Coinbase,
|
||||
BlockNumber: new(big.Int).SetUint64(genesisConfig.Number),
|
||||
BaseFee: genesisConfig.BaseFee,
|
||||
BlobHashes: blobHashes,
|
||||
BlobBaseFee: blobBaseFee,
|
||||
EVMConfig: vm.Config{
|
||||
|
|
@ -277,7 +277,7 @@ func runCmd(ctx *cli.Context) error {
|
|||
fmt.Printf("Failed to commit changes %v\n", err)
|
||||
return err
|
||||
}
|
||||
dumpdb, err := state.New(root, sdb, nil)
|
||||
dumpdb, err := state.New(root, sdb)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to open statedb %v\n", err)
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error {
|
|||
result.Root = &root
|
||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||
if dump { // Dump any state to aid debugging
|
||||
cpy, _ := state.New(root, tstate.StateDB.Database(), nil)
|
||||
cpy, _ := state.New(root, tstate.StateDB.Database())
|
||||
dump := cpy.RawDump(nil)
|
||||
result.State = &dump
|
||||
}
|
||||
|
|
|
|||
|
|
@ -425,8 +425,6 @@ func importHistory(ctx *cli.Context) error {
|
|||
network = "mainnet"
|
||||
case ctx.Bool(utils.SepoliaFlag.Name):
|
||||
network = "sepolia"
|
||||
case ctx.Bool(utils.GoerliFlag.Name):
|
||||
network = "goerli"
|
||||
}
|
||||
} else {
|
||||
// No network flag set, try to determine network based on files
|
||||
|
|
@ -586,7 +584,7 @@ func dump(ctx *cli.Context) error {
|
|||
triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup
|
||||
defer triedb.Close()
|
||||
|
||||
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
state, err := state.New(root, state.NewDatabase(triedb, nil))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ var tomlSettings = toml.Config{
|
|||
},
|
||||
MissingField: func(rt reflect.Type, field string) error {
|
||||
id := fmt.Sprintf("%s.%s", rt.String(), field)
|
||||
if deprecated(id) {
|
||||
log.Warn("Config field is deprecated and won't have an effect", "name", id)
|
||||
if deprecatedConfigFields[id] {
|
||||
log.Warn(fmt.Sprintf("Config field '%s' is deprecated and won't have any effect.", id))
|
||||
return nil
|
||||
}
|
||||
var link string
|
||||
|
|
@ -87,6 +87,19 @@ var tomlSettings = toml.Config{
|
|||
},
|
||||
}
|
||||
|
||||
var deprecatedConfigFields = map[string]bool{
|
||||
"ethconfig.Config.EVMInterpreter": true,
|
||||
"ethconfig.Config.EWASMInterpreter": true,
|
||||
"ethconfig.Config.TrieCleanCacheJournal": true,
|
||||
"ethconfig.Config.TrieCleanCacheRejournal": true,
|
||||
"ethconfig.Config.LightServ": true,
|
||||
"ethconfig.Config.LightIngress": true,
|
||||
"ethconfig.Config.LightEgress": true,
|
||||
"ethconfig.Config.LightPeers": true,
|
||||
"ethconfig.Config.LightNoPrune": true,
|
||||
"ethconfig.Config.LightNoSyncServe": true,
|
||||
}
|
||||
|
||||
type ethstatsConfig struct {
|
||||
URL string `toml:",omitempty"`
|
||||
}
|
||||
|
|
@ -314,21 +327,6 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
func deprecated(field string) bool {
|
||||
switch field {
|
||||
case "ethconfig.Config.EVMInterpreter":
|
||||
return true
|
||||
case "ethconfig.Config.EWASMInterpreter":
|
||||
return true
|
||||
case "ethconfig.Config.TrieCleanCacheJournal":
|
||||
return true
|
||||
case "ethconfig.Config.TrieCleanCacheRejournal":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error {
|
||||
scryptN := keystore.StandardScryptN
|
||||
scryptP := keystore.StandardScryptP
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
ipcAPIs = "admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
||||
ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
||||
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||
)
|
||||
|
||||
|
|
@ -38,10 +38,10 @@ const (
|
|||
// memory and disk IO. If the args don't set --datadir, the
|
||||
// child g gets a temporary data directory.
|
||||
func runMinimalGeth(t *testing.T, args ...string) *testgeth {
|
||||
// --goerli to make the 'writing genesis to disk' faster (no accounts)
|
||||
// --holesky to make the 'writing genesis to disk' faster (no accounts)
|
||||
// --networkid=1337 to avoid cache bump
|
||||
// --syncmode=full to avoid allocating fast sync bloom
|
||||
allArgs := []string{"--goerli", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
|
||||
allArgs := []string{"--holesky", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
|
||||
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
|
||||
"--datadir.minfreedisk", "0"}
|
||||
return runGeth(t, append(allArgs, args...)...)
|
||||
|
|
@ -62,7 +62,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(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
})
|
||||
geth.SetTemplateFunc("apis", func() string { return ipcAPIs })
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
|
|||
attach.SetTemplateFunc("gover", runtime.Version)
|
||||
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
||||
attach.SetTemplateFunc("niltime", func() string {
|
||||
return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
})
|
||||
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
|
||||
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
|
||||
|
|
|
|||
|
|
@ -248,7 +248,8 @@ func removeDB(ctx *cli.Context) error {
|
|||
// Delete state data
|
||||
statePaths := []string{
|
||||
rootDir,
|
||||
filepath.Join(ancientDir, rawdb.StateFreezerName),
|
||||
filepath.Join(ancientDir, rawdb.MerkleStateFreezerName),
|
||||
filepath.Join(ancientDir, rawdb.VerkleStateFreezerName),
|
||||
}
|
||||
confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name)
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ import (
|
|||
// TestExport does a basic test of "geth export", exporting the test-genesis.
|
||||
func TestExport(t *testing.T) {
|
||||
t.Parallel()
|
||||
outfile := fmt.Sprintf("%v/testExport.out", os.TempDir())
|
||||
defer os.Remove(outfile)
|
||||
outfile := fmt.Sprintf("%v/testExport.out", t.TempDir())
|
||||
geth := runGeth(t, "--datadir", initGeth(t), "export", outfile)
|
||||
geth.WaitExit()
|
||||
if have, want := geth.ExitStatus(), 0; have != want {
|
||||
|
|
|
|||
|
|
@ -201,9 +201,8 @@ func TestFileOut(t *testing.T) {
|
|||
var (
|
||||
have, want []byte
|
||||
err error
|
||||
path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63())
|
||||
path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
|
||||
)
|
||||
t.Cleanup(func() { os.Remove(path) })
|
||||
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "logtest"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -222,9 +221,8 @@ func TestRotatingFileOut(t *testing.T) {
|
|||
var (
|
||||
have, want []byte
|
||||
err error
|
||||
path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63())
|
||||
path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
|
||||
)
|
||||
t.Cleanup(func() { os.Remove(path) })
|
||||
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "--log.rotate", "logtest"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,7 +156,6 @@ var (
|
|||
utils.BeaconGenesisRootFlag,
|
||||
utils.BeaconGenesisTimeFlag,
|
||||
utils.BeaconCheckpointFlag,
|
||||
utils.CollectWitnessFlag,
|
||||
}, utils.NetworkFlags, utils.DatabaseFlags)
|
||||
|
||||
rpcFlags = []cli.Flag{
|
||||
|
|
@ -289,9 +288,6 @@ func main() {
|
|||
func prepare(ctx *cli.Context) {
|
||||
// If we're running a known preset, log it for convenience.
|
||||
switch {
|
||||
case ctx.IsSet(utils.GoerliFlag.Name):
|
||||
log.Info("Starting Geth on Görli testnet...")
|
||||
|
||||
case ctx.IsSet(utils.SepoliaFlag.Name):
|
||||
log.Info("Starting Geth on Sepolia testnet...")
|
||||
|
||||
|
|
@ -324,7 +320,6 @@ func prepare(ctx *cli.Context) {
|
|||
// Make sure we're not on any supported preconfigured testnet either
|
||||
if !ctx.IsSet(utils.HoleskyFlag.Name) &&
|
||||
!ctx.IsSet(utils.SepoliaFlag.Name) &&
|
||||
!ctx.IsSet(utils.GoerliFlag.Name) &&
|
||||
!ctx.IsSet(utils.DeveloperFlag.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)
|
||||
|
|
@ -360,8 +355,6 @@ func geth(ctx *cli.Context) error {
|
|||
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
|
||||
// miner.
|
||||
func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) {
|
||||
debug.Memsize.Add("node", stack)
|
||||
|
||||
// Start up the node itself
|
||||
utils.StartNode(ctx, stack, isConsole)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,443 +0,0 @@
|
|||
// Copyright 2017 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/>.
|
||||
|
||||
// p2psim provides a command-line client for a simulation HTTP API.
|
||||
//
|
||||
// Here is an example of creating a 2 node network with the first node
|
||||
// connected to the second:
|
||||
//
|
||||
// $ p2psim node create
|
||||
// Created node01
|
||||
//
|
||||
// $ p2psim node start node01
|
||||
// Started node01
|
||||
//
|
||||
// $ p2psim node create
|
||||
// Created node02
|
||||
//
|
||||
// $ p2psim node start node02
|
||||
// Started node02
|
||||
//
|
||||
// $ p2psim node connect node01 node02
|
||||
// Connected node01 to node02
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/simulations"
|
||||
"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var client *simulations.Client
|
||||
|
||||
var (
|
||||
// global command flags
|
||||
apiFlag = &cli.StringFlag{
|
||||
Name: "api",
|
||||
Value: "http://localhost:8888",
|
||||
Usage: "simulation API URL",
|
||||
EnvVars: []string{"P2PSIM_API_URL"},
|
||||
}
|
||||
|
||||
// events subcommand flags
|
||||
currentFlag = &cli.BoolFlag{
|
||||
Name: "current",
|
||||
Usage: "get existing nodes and conns first",
|
||||
}
|
||||
filterFlag = &cli.StringFlag{
|
||||
Name: "filter",
|
||||
Value: "",
|
||||
Usage: "message filter",
|
||||
}
|
||||
|
||||
// node create subcommand flags
|
||||
nameFlag = &cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "node name",
|
||||
}
|
||||
servicesFlag = &cli.StringFlag{
|
||||
Name: "services",
|
||||
Value: "",
|
||||
Usage: "node services (comma separated)",
|
||||
}
|
||||
keyFlag = &cli.StringFlag{
|
||||
Name: "key",
|
||||
Value: "",
|
||||
Usage: "node private key (hex encoded)",
|
||||
}
|
||||
|
||||
// node rpc subcommand flags
|
||||
subscribeFlag = &cli.BoolFlag{
|
||||
Name: "subscribe",
|
||||
Usage: "method is a subscription",
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := flags.NewApp("devp2p simulation command-line client")
|
||||
app.Flags = []cli.Flag{
|
||||
apiFlag,
|
||||
}
|
||||
app.Before = func(ctx *cli.Context) error {
|
||||
client = simulations.NewClient(ctx.String(apiFlag.Name))
|
||||
return nil
|
||||
}
|
||||
app.Commands = []*cli.Command{
|
||||
{
|
||||
Name: "show",
|
||||
Usage: "show network information",
|
||||
Action: showNetwork,
|
||||
},
|
||||
{
|
||||
Name: "events",
|
||||
Usage: "stream network events",
|
||||
Action: streamNetwork,
|
||||
Flags: []cli.Flag{
|
||||
currentFlag,
|
||||
filterFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "snapshot",
|
||||
Usage: "create a network snapshot to stdout",
|
||||
Action: createSnapshot,
|
||||
},
|
||||
{
|
||||
Name: "load",
|
||||
Usage: "load a network snapshot from stdin",
|
||||
Action: loadSnapshot,
|
||||
},
|
||||
{
|
||||
Name: "node",
|
||||
Usage: "manage simulation nodes",
|
||||
Action: listNodes,
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "list",
|
||||
Usage: "list nodes",
|
||||
Action: listNodes,
|
||||
},
|
||||
{
|
||||
Name: "create",
|
||||
Usage: "create a node",
|
||||
Action: createNode,
|
||||
Flags: []cli.Flag{
|
||||
nameFlag,
|
||||
servicesFlag,
|
||||
keyFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "show",
|
||||
ArgsUsage: "<node>",
|
||||
Usage: "show node information",
|
||||
Action: showNode,
|
||||
},
|
||||
{
|
||||
Name: "start",
|
||||
ArgsUsage: "<node>",
|
||||
Usage: "start a node",
|
||||
Action: startNode,
|
||||
},
|
||||
{
|
||||
Name: "stop",
|
||||
ArgsUsage: "<node>",
|
||||
Usage: "stop a node",
|
||||
Action: stopNode,
|
||||
},
|
||||
{
|
||||
Name: "connect",
|
||||
ArgsUsage: "<node> <peer>",
|
||||
Usage: "connect a node to a peer node",
|
||||
Action: connectNode,
|
||||
},
|
||||
{
|
||||
Name: "disconnect",
|
||||
ArgsUsage: "<node> <peer>",
|
||||
Usage: "disconnect a node from a peer node",
|
||||
Action: disconnectNode,
|
||||
},
|
||||
{
|
||||
Name: "rpc",
|
||||
ArgsUsage: "<node> <method> [<args>]",
|
||||
Usage: "call a node RPC method",
|
||||
Action: rpcNode,
|
||||
Flags: []cli.Flag{
|
||||
subscribeFlag,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func showNetwork(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 0 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
network, err := client.GetNetwork()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0)
|
||||
defer w.Flush()
|
||||
fmt.Fprintf(w, "NODES\t%d\n", len(network.Nodes))
|
||||
fmt.Fprintf(w, "CONNS\t%d\n", len(network.Conns))
|
||||
return nil
|
||||
}
|
||||
|
||||
func streamNetwork(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 0 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
events := make(chan *simulations.Event)
|
||||
sub, err := client.SubscribeNetwork(events, simulations.SubscribeOpts{
|
||||
Current: ctx.Bool(currentFlag.Name),
|
||||
Filter: ctx.String(filterFlag.Name),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sub.Unsubscribe()
|
||||
enc := json.NewEncoder(ctx.App.Writer)
|
||||
for {
|
||||
select {
|
||||
case event := <-events:
|
||||
if err := enc.Encode(event); err != nil {
|
||||
return err
|
||||
}
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createSnapshot(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 0 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
snap, err := client.CreateSnapshot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.NewEncoder(os.Stdout).Encode(snap)
|
||||
}
|
||||
|
||||
func loadSnapshot(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 0 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
snap := &simulations.Snapshot{}
|
||||
if err := json.NewDecoder(os.Stdin).Decode(snap); err != nil {
|
||||
return err
|
||||
}
|
||||
return client.LoadSnapshot(snap)
|
||||
}
|
||||
|
||||
func listNodes(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 0 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
nodes, err := client.GetNodes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0)
|
||||
defer w.Flush()
|
||||
fmt.Fprintf(w, "NAME\tPROTOCOLS\tID\n")
|
||||
for _, node := range nodes {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\n", node.Name, strings.Join(protocolList(node), ","), node.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func protocolList(node *p2p.NodeInfo) []string {
|
||||
protos := make([]string, 0, len(node.Protocols))
|
||||
for name := range node.Protocols {
|
||||
protos = append(protos, name)
|
||||
}
|
||||
return protos
|
||||
}
|
||||
|
||||
func createNode(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 0 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
config := adapters.RandomNodeConfig()
|
||||
config.Name = ctx.String(nameFlag.Name)
|
||||
if key := ctx.String(keyFlag.Name); key != "" {
|
||||
privKey, err := crypto.HexToECDSA(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.ID = enode.PubkeyToIDV4(&privKey.PublicKey)
|
||||
config.PrivateKey = privKey
|
||||
}
|
||||
if services := ctx.String(servicesFlag.Name); services != "" {
|
||||
config.Lifecycles = strings.Split(services, ",")
|
||||
}
|
||||
node, err := client.CreateNode(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "Created", node.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func showNode(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 1 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
nodeName := ctx.Args().First()
|
||||
node, err := client.GetNode(nodeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0)
|
||||
defer w.Flush()
|
||||
fmt.Fprintf(w, "NAME\t%s\n", node.Name)
|
||||
fmt.Fprintf(w, "PROTOCOLS\t%s\n", strings.Join(protocolList(node), ","))
|
||||
fmt.Fprintf(w, "ID\t%s\n", node.ID)
|
||||
fmt.Fprintf(w, "ENODE\t%s\n", node.Enode)
|
||||
for name, proto := range node.Protocols {
|
||||
fmt.Fprintln(w)
|
||||
fmt.Fprintf(w, "--- PROTOCOL INFO: %s\n", name)
|
||||
fmt.Fprintf(w, "%v\n", proto)
|
||||
fmt.Fprintf(w, "---\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func startNode(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 1 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
nodeName := ctx.Args().First()
|
||||
if err := client.StartNode(nodeName); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "Started", nodeName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopNode(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 1 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
nodeName := ctx.Args().First()
|
||||
if err := client.StopNode(nodeName); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "Stopped", nodeName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func connectNode(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 2 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
args := ctx.Args()
|
||||
nodeName := args.Get(0)
|
||||
peerName := args.Get(1)
|
||||
if err := client.ConnectNode(nodeName, peerName); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "Connected", nodeName, "to", peerName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func disconnectNode(ctx *cli.Context) error {
|
||||
args := ctx.Args()
|
||||
if args.Len() != 2 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
nodeName := args.Get(0)
|
||||
peerName := args.Get(1)
|
||||
if err := client.DisconnectNode(nodeName, peerName); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "Disconnected", nodeName, "from", peerName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func rpcNode(ctx *cli.Context) error {
|
||||
args := ctx.Args()
|
||||
if args.Len() < 2 {
|
||||
return cli.ShowCommandHelp(ctx, ctx.Command.Name)
|
||||
}
|
||||
nodeName := args.Get(0)
|
||||
method := args.Get(1)
|
||||
rpcClient, err := client.RPCClient(context.Background(), nodeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ctx.Bool(subscribeFlag.Name) {
|
||||
return rpcSubscribe(rpcClient, ctx.App.Writer, method, args.Slice()[3:]...)
|
||||
}
|
||||
var result interface{}
|
||||
params := make([]interface{}, len(args.Slice()[3:]))
|
||||
for i, v := range args.Slice()[3:] {
|
||||
params[i] = v
|
||||
}
|
||||
if err := rpcClient.Call(&result, method, params...); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.NewEncoder(ctx.App.Writer).Encode(result)
|
||||
}
|
||||
|
||||
func rpcSubscribe(client *rpc.Client, out io.Writer, method string, args ...string) error {
|
||||
namespace, method, _ := strings.Cut(method, "_")
|
||||
ch := make(chan interface{})
|
||||
subArgs := make([]interface{}, len(args)+1)
|
||||
subArgs[0] = method
|
||||
for i, v := range args {
|
||||
subArgs[i+1] = v
|
||||
}
|
||||
sub, err := client.Subscribe(context.Background(), namespace, ch, subArgs...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sub.Unsubscribe()
|
||||
enc := json.NewEncoder(out)
|
||||
for {
|
||||
select {
|
||||
case v := <-ch:
|
||||
if err := enc.Encode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -262,7 +262,6 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ
|
|||
start = time.Now()
|
||||
reported = time.Now()
|
||||
imported = 0
|
||||
forker = core.NewForkChoice(chain, nil)
|
||||
h = sha256.New()
|
||||
buf = bytes.NewBuffer(nil)
|
||||
)
|
||||
|
|
@ -305,7 +304,7 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ
|
|||
if err != nil {
|
||||
return fmt.Errorf("error reading receipts %d: %w", it.Number(), err)
|
||||
}
|
||||
if status, err := chain.HeaderChain().InsertHeaderChain([]*types.Header{block.Header()}, start, forker); err != nil {
|
||||
if status, err := chain.HeaderChain().InsertHeaderChain([]*types.Header{block.Header()}, start); err != nil {
|
||||
return fmt.Errorf("error inserting header %d: %w", it.Number(), err)
|
||||
} else if status != core.CanonStatTy {
|
||||
return fmt.Errorf("error inserting header %d, not canon: %v", it.Number(), status)
|
||||
|
|
|
|||
|
|
@ -29,18 +29,12 @@ import (
|
|||
|
||||
// TestExport does basic sanity checks on the export/import functionality
|
||||
func TestExport(t *testing.T) {
|
||||
f := fmt.Sprintf("%v/tempdump", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump", t.TempDir())
|
||||
testExport(t, f)
|
||||
}
|
||||
|
||||
func TestExportGzip(t *testing.T) {
|
||||
f := fmt.Sprintf("%v/tempdump.gz", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump.gz", t.TempDir())
|
||||
testExport(t, f)
|
||||
}
|
||||
|
||||
|
|
@ -99,20 +93,14 @@ func testExport(t *testing.T, f string) {
|
|||
|
||||
// TestDeletionExport tests if the deletion markers can be exported/imported correctly
|
||||
func TestDeletionExport(t *testing.T) {
|
||||
f := fmt.Sprintf("%v/tempdump", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump", t.TempDir())
|
||||
testDeletion(t, f)
|
||||
}
|
||||
|
||||
// TestDeletionExportGzip tests if the deletion markers can be exported/imported
|
||||
// correctly with gz compression.
|
||||
func TestDeletionExportGzip(t *testing.T) {
|
||||
f := fmt.Sprintf("%v/tempdump.gz", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump.gz", t.TempDir())
|
||||
testDeletion(t, f)
|
||||
}
|
||||
|
||||
|
|
@ -171,10 +159,7 @@ func testDeletion(t *testing.T, f string) {
|
|||
// TestImportFutureFormat tests that we reject unsupported future versions.
|
||||
func TestImportFutureFormat(t *testing.T) {
|
||||
t.Parallel()
|
||||
f := fmt.Sprintf("%v/tempdump-future", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump-future", t.TempDir())
|
||||
fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common/fdlimit"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
||||
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -133,7 +134,7 @@ var (
|
|||
}
|
||||
NetworkIdFlag = &cli.Uint64Flag{
|
||||
Name: "networkid",
|
||||
Usage: "Explicitly set network id (integer)(For testnets: use --goerli, --sepolia, --holesky instead)",
|
||||
Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky instead)",
|
||||
Value: ethconfig.Defaults.NetworkId,
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
|
|
@ -142,11 +143,6 @@ var (
|
|||
Usage: "Ethereum mainnet",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
GoerliFlag = &cli.BoolFlag{
|
||||
Name: "goerli",
|
||||
Usage: "Görli network: pre-configured proof-of-authority test network",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
SepoliaFlag = &cli.BoolFlag{
|
||||
Name: "sepolia",
|
||||
Usage: "Sepolia network: pre-configured proof-of-work test network",
|
||||
|
|
@ -291,7 +287,7 @@ var (
|
|||
}
|
||||
BeaconApiHeaderFlag = &cli.StringSliceFlag{
|
||||
Name: "beacon.api.header",
|
||||
Usage: "Pass custom HTTP header fields to the emote beacon node API in \"key:value\" format. This flag can be given multiple times.",
|
||||
Usage: "Pass custom HTTP header fields to the remote beacon node API in \"key:value\" format. This flag can be given multiple times.",
|
||||
Category: flags.BeaconCategory,
|
||||
}
|
||||
BeaconThresholdFlag = &cli.IntFlag{
|
||||
|
|
@ -604,11 +600,6 @@ var (
|
|||
Usage: "Disables db compaction after import",
|
||||
Category: flags.LoggingCategory,
|
||||
}
|
||||
CollectWitnessFlag = &cli.BoolFlag{
|
||||
Name: "collectwitness",
|
||||
Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.",
|
||||
Category: flags.MiscCategory,
|
||||
}
|
||||
|
||||
// MISC settings
|
||||
SyncTargetFlag = &cli.StringFlag{
|
||||
|
|
@ -811,8 +802,9 @@ var (
|
|||
DiscoveryV5Flag = &cli.BoolFlag{
|
||||
Name: "discovery.v5",
|
||||
Aliases: []string{"discv5"},
|
||||
Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
|
||||
Usage: "Enables the V5 discovery mechanism",
|
||||
Category: flags.NetworkingCategory,
|
||||
Value: true,
|
||||
}
|
||||
NetrestrictFlag = &cli.StringFlag{
|
||||
Name: "netrestrict",
|
||||
|
|
@ -964,7 +956,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
|||
var (
|
||||
// TestnetFlags is the flag group of all built-in supported testnets.
|
||||
TestnetFlags = []cli.Flag{
|
||||
GoerliFlag,
|
||||
SepoliaFlag,
|
||||
HoleskyFlag,
|
||||
}
|
||||
|
|
@ -987,9 +978,6 @@ var (
|
|||
// then a subdirectory of the specified datadir will be used.
|
||||
func MakeDataDir(ctx *cli.Context) string {
|
||||
if path := ctx.String(DataDirFlag.Name); path != "" {
|
||||
if ctx.Bool(GoerliFlag.Name) {
|
||||
return filepath.Join(path, "goerli")
|
||||
}
|
||||
if ctx.Bool(SepoliaFlag.Name) {
|
||||
return filepath.Join(path, "sepolia")
|
||||
}
|
||||
|
|
@ -1041,7 +1029,7 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
|
|||
//
|
||||
// 1. --bootnodes flag
|
||||
// 2. Config file
|
||||
// 3. Network preset flags (e.g. --goerli)
|
||||
// 3. Network preset flags (e.g. --holesky)
|
||||
// 4. default to mainnet nodes
|
||||
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
|
||||
urls := params.MainnetBootnodes
|
||||
|
|
@ -1056,8 +1044,6 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
|
|||
urls = params.HoleskyBootnodes
|
||||
case ctx.Bool(SepoliaFlag.Name):
|
||||
urls = params.SepoliaBootnodes
|
||||
case ctx.Bool(GoerliFlag.Name):
|
||||
urls = params.GoerliBootnodes
|
||||
}
|
||||
}
|
||||
cfg.BootstrapNodes = mustParseBootnodes(urls)
|
||||
|
|
@ -1321,7 +1307,6 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error
|
|||
func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||
if ctx.IsSet(MinerEtherbaseFlag.Name) {
|
||||
log.Warn("Option --miner.etherbase is deprecated as the etherbase is set by the consensus client post-merge")
|
||||
return
|
||||
}
|
||||
if !ctx.IsSet(MinerPendingFeeRecipientFlag.Name) {
|
||||
return
|
||||
|
|
@ -1483,8 +1468,6 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) {
|
|||
cfg.DataDir = ctx.String(DataDirFlag.Name)
|
||||
case ctx.Bool(DeveloperFlag.Name):
|
||||
cfg.DataDir = "" // unless explicitly requested, use memory databases
|
||||
case ctx.Bool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
|
||||
case ctx.Bool(SepoliaFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia")
|
||||
case ctx.Bool(HoleskyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||
|
|
@ -1550,6 +1533,18 @@ func setTxPool(ctx *cli.Context, cfg *legacypool.Config) {
|
|||
}
|
||||
}
|
||||
|
||||
func setBlobPool(ctx *cli.Context, cfg *blobpool.Config) {
|
||||
if ctx.IsSet(BlobPoolDataDirFlag.Name) {
|
||||
cfg.Datadir = ctx.String(BlobPoolDataDirFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(BlobPoolDataCapFlag.Name) {
|
||||
cfg.Datacap = ctx.Uint64(BlobPoolDataCapFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(BlobPoolPriceBumpFlag.Name) {
|
||||
cfg.PriceBump = ctx.Uint64(BlobPoolPriceBumpFlag.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func setMiner(ctx *cli.Context, cfg *miner.Config) {
|
||||
if ctx.Bool(MiningEnabledFlag.Name) {
|
||||
log.Warn("The flag --mine is deprecated and will be removed")
|
||||
|
|
@ -1644,13 +1639,14 @@ 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, GoerliFlag, SepoliaFlag, HoleskyFlag)
|
||||
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag)
|
||||
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
|
||||
|
||||
// Set configurations from CLI flags
|
||||
setEtherbase(ctx, cfg)
|
||||
setGPO(ctx, &cfg.GPO)
|
||||
setTxPool(ctx, &cfg.TxPool)
|
||||
setBlobPool(ctx, &cfg.BlobPool)
|
||||
setMiner(ctx, &cfg.Miner)
|
||||
setRequiredBlocks(ctx, cfg)
|
||||
setLes(ctx, cfg)
|
||||
|
|
@ -1765,9 +1761,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||
// TODO(fjl): force-enable this in --dev mode
|
||||
cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(CollectWitnessFlag.Name) {
|
||||
cfg.EnableWitnessCollection = ctx.Bool(CollectWitnessFlag.Name)
|
||||
}
|
||||
|
||||
if ctx.IsSet(RPCGlobalGasCapFlag.Name) {
|
||||
cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name)
|
||||
|
|
@ -1813,12 +1806,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||
}
|
||||
cfg.Genesis = core.DefaultSepoliaGenesisBlock()
|
||||
SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash)
|
||||
case ctx.Bool(GoerliFlag.Name):
|
||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||
cfg.NetworkId = 5
|
||||
}
|
||||
cfg.Genesis = core.DefaultGoerliGenesisBlock()
|
||||
SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash)
|
||||
case ctx.Bool(DeveloperFlag.Name):
|
||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||
cfg.NetworkId = 1337
|
||||
|
|
@ -2140,8 +2127,6 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
|
|||
genesis = core.DefaultHoleskyGenesisBlock()
|
||||
case ctx.Bool(SepoliaFlag.Name):
|
||||
genesis = core.DefaultSepoliaGenesisBlock()
|
||||
case ctx.Bool(GoerliFlag.Name):
|
||||
genesis = core.DefaultGoerliGenesisBlock()
|
||||
case ctx.Bool(DeveloperFlag.Name):
|
||||
Fatalf("Developer chains are ephemeral")
|
||||
}
|
||||
|
|
@ -2200,7 +2185,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
|||
}
|
||||
vmcfg := vm.Config{
|
||||
EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
|
||||
EnableWitnessCollection: ctx.Bool(CollectWitnessFlag.Name),
|
||||
}
|
||||
if ctx.IsSet(VMTraceFlag.Name) {
|
||||
if name := ctx.String(VMTraceFlag.Name); name != "" {
|
||||
|
|
@ -2216,7 +2200,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
|||
}
|
||||
}
|
||||
// Disable transaction indexing/unindexing by default.
|
||||
chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil)
|
||||
chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil)
|
||||
if err != nil {
|
||||
Fatalf("Can't create BlockChain: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,25 +92,21 @@ var (
|
|||
LightServeFlag = &cli.IntFlag{
|
||||
Name: "light.serve",
|
||||
Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)",
|
||||
Value: ethconfig.Defaults.LightServ,
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
LightIngressFlag = &cli.IntFlag{
|
||||
Name: "light.ingress",
|
||||
Usage: "Incoming bandwidth limit for serving light clients (deprecated)",
|
||||
Value: ethconfig.Defaults.LightIngress,
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
LightEgressFlag = &cli.IntFlag{
|
||||
Name: "light.egress",
|
||||
Usage: "Outgoing bandwidth limit for serving light clients (deprecated)",
|
||||
Value: ethconfig.Defaults.LightEgress,
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
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.DeprecatedCategory,
|
||||
}
|
||||
LightNoPruneFlag = &cli.BoolFlag{
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ func TestHistoryImportAndExport(t *testing.T) {
|
|||
})
|
||||
|
||||
// Initialize BlockChain.
|
||||
chain, err := core.NewBlockChain(db, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
chain, err := core.NewBlockChain(db, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to initialize chain: %v", err)
|
||||
}
|
||||
|
|
@ -171,7 +171,7 @@ func TestHistoryImportAndExport(t *testing.T) {
|
|||
})
|
||||
|
||||
genesis.MustCommit(db2, triedb.NewDatabase(db, triedb.HashDefaults))
|
||||
imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to initialize chain: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Blo
|
|||
// (c) the extradata is limited to 32 bytes
|
||||
func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error {
|
||||
// Ensure that the header's extra-data section is of a reasonable size
|
||||
if len(header.Extra) > 32 {
|
||||
if len(header.Extra) > int(params.MaximumExtraDataSize) {
|
||||
return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra))
|
||||
}
|
||||
// Verify the seal parts. Ensure the nonce and uncle hash are the expected value.
|
||||
|
|
@ -387,8 +387,39 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
|||
// Assign the final state root to header.
|
||||
header.Root = state.IntermediateRoot(true)
|
||||
|
||||
// Assemble and return the final block.
|
||||
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil
|
||||
// Assemble the final block.
|
||||
block := types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
||||
|
||||
// Create the block witness and attach to block.
|
||||
// This step needs to happen as late as possible to catch all access events.
|
||||
if chain.Config().IsVerkle(header.Number, header.Time) {
|
||||
keys := state.AccessEvents().Keys()
|
||||
|
||||
// Open the pre-tree to prove the pre-state against
|
||||
parent := chain.GetHeaderByNumber(header.Number.Uint64() - 1)
|
||||
if parent == nil {
|
||||
return nil, fmt.Errorf("nil parent header for block %d", header.Number)
|
||||
}
|
||||
|
||||
preTrie, err := state.Database().OpenTrie(parent.Root)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
|
||||
}
|
||||
|
||||
vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
|
||||
vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie)
|
||||
if okpre && okpost {
|
||||
if len(keys) > 0 {
|
||||
verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys, vktPreTrie.FlatdbNodeResolver)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err)
|
||||
}
|
||||
block = block.WithWitness(&types.ExecutionWitness{StateDiff: stateDiff, VerkleProof: verkleProof})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// Seal generates a new sealing request for the given input block and pushes
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ import (
|
|||
)
|
||||
|
||||
// This test case is a repro of an annoying bug that took us forever to catch.
|
||||
// In Clique PoA networks (Görli, etc), consecutive blocks might have
|
||||
// the same state root (no block subsidy, empty block). If a node crashes, the
|
||||
// chain ends up losing the recent state and needs to regenerate it from blocks
|
||||
// already in the database. The bug was that processing the block *prior* to an
|
||||
// empty one **also completes** the empty one, ending up in a known-block error.
|
||||
// In Clique PoA networks, consecutive blocks might have the same state root (no
|
||||
// block subsidy, empty block). If a node crashes, the chain ends up losing the
|
||||
// recent state and needs to regenerate it from blocks already in the database.
|
||||
// The bug was that processing the block *prior* to an empty one **also
|
||||
// completes** the empty one, ending up in a known-block error.
|
||||
func TestReimportMirroredState(t *testing.T) {
|
||||
// Initialize a Clique chain with a single signer
|
||||
var (
|
||||
|
|
@ -55,7 +55,7 @@ func TestReimportMirroredState(t *testing.T) {
|
|||
copy(genspec.ExtraData[extraVanity:], addr[:])
|
||||
|
||||
// Generate a batch of blocks, each properly signed
|
||||
chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, engine, vm.Config{}, nil)
|
||||
defer chain.Stop()
|
||||
|
||||
_, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) {
|
||||
|
|
@ -87,7 +87,7 @@ func TestReimportMirroredState(t *testing.T) {
|
|||
}
|
||||
// Insert the first two blocks and make sure the chain is valid
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil)
|
||||
defer chain.Stop()
|
||||
|
||||
if _, err := chain.InsertChain(blocks[:2]); err != nil {
|
||||
|
|
@ -100,7 +100,7 @@ func TestReimportMirroredState(t *testing.T) {
|
|||
// Simulate a crash by creating a new chain on top of the database, without
|
||||
// flushing the dirty states out. Insert the last block, triggering a sidechain
|
||||
// reimport.
|
||||
chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil)
|
||||
defer chain.Stop()
|
||||
|
||||
if _, err := chain.InsertChain(blocks[2:]); err != nil {
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ func (tt *cliqueTest) run(t *testing.T) {
|
|||
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
||||
}
|
||||
// Pass all the headers through clique and ensure tallying succeeds
|
||||
chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test chain: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
|||
|
||||
// Time the insertion of the new chain.
|
||||
// State and blocks are stored in the same DB.
|
||||
chainman, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
chainman, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer chainman.Stop()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
|
@ -312,7 +312,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
|||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||
}
|
||||
chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
if err != nil {
|
||||
b.Fatalf("error creating chain: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
|
|
@ -121,14 +119,17 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||
|
||||
// ValidateState validates the various changes that happen after a state transition,
|
||||
// such as amount of used gas, the receipt roots and the state root itself.
|
||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error {
|
||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
|
||||
if res == nil {
|
||||
return fmt.Errorf("nil ProcessResult value")
|
||||
}
|
||||
header := block.Header()
|
||||
if block.GasUsed() != usedGas {
|
||||
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
|
||||
if block.GasUsed() != res.GasUsed {
|
||||
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), res.GasUsed)
|
||||
}
|
||||
// Validate the received block's bloom with the one derived from the generated receipts.
|
||||
// For valid blocks this should always validate to true.
|
||||
rbloom := types.CreateBloom(receipts)
|
||||
rbloom := types.CreateBloom(res.Receipts)
|
||||
if rbloom != header.Bloom {
|
||||
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
||||
}
|
||||
|
|
@ -138,10 +139,17 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||
return nil
|
||||
}
|
||||
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
|
||||
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
||||
receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
|
||||
if receiptSha != header.ReceiptHash {
|
||||
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
|
||||
}
|
||||
// Validate the parsed requests match the expected header value.
|
||||
if header.RequestsHash != nil {
|
||||
depositSha := types.DeriveSha(res.Requests, trie.NewStackTrie(nil))
|
||||
if depositSha != *header.RequestsHash {
|
||||
return fmt.Errorf("invalid deposit root hash (remote: %x local: %x)", *header.RequestsHash, depositSha)
|
||||
}
|
||||
}
|
||||
// Validate the state root against the received state root and throw
|
||||
// an error if they don't match.
|
||||
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
||||
|
|
@ -150,28 +158,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||
return nil
|
||||
}
|
||||
|
||||
// ValidateWitness cross validates a block execution with stateless remote clients.
|
||||
//
|
||||
// Normally we'd distribute the block witness to remote cross validators, wait
|
||||
// for them to respond and then merge the results. For now, however, it's only
|
||||
// Geth, so do an internal stateless run.
|
||||
func (v *BlockValidator) ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error {
|
||||
// Run the cross client stateless execution
|
||||
// TODO(karalabe): Self-stateless for now, swap with other clients
|
||||
crossReceiptRoot, crossStateRoot, err := ExecuteStateless(v.config, witness)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stateless execution failed: %v", err)
|
||||
}
|
||||
// Stateless cross execution suceeeded, validate the withheld computed fields
|
||||
if crossReceiptRoot != receiptRoot {
|
||||
return fmt.Errorf("cross validator receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, receiptRoot)
|
||||
}
|
||||
if crossStateRoot != stateRoot {
|
||||
return fmt.Errorf("cross validator state root mismatch (cross: %x local: %x)", crossStateRoot, stateRoot)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CalcGasLimit computes the gas limit of the next block after parent. It aims
|
||||
// to keep the baseline gas close to the provided target, and increase it towards
|
||||
// the target if the baseline gas is lower.
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func testHeaderVerification(t *testing.T, scheme string) {
|
|||
headers[i] = block.Header()
|
||||
}
|
||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
||||
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer chain.Stop()
|
||||
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
|
|
@ -160,7 +160,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
|
|||
postHeaders[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, engine, vm.Config{}, nil, nil)
|
||||
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
|
||||
defer chain.Stop()
|
||||
|
||||
// Verify the blocks before the merging
|
||||
|
|
@ -201,7 +201,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
|
|||
t.Fatalf("post-block %d: unexpected result returned: %v", i, result)
|
||||
case <-time.After(25 * time.Millisecond):
|
||||
}
|
||||
chain.InsertBlockWithoutSetHead(postBlocks[i])
|
||||
chain.InsertBlockWithoutSetHead(postBlocks[i], false)
|
||||
}
|
||||
|
||||
// Verify the blocks with pre-merge blocks and post-merge blocks
|
||||
|
|
|
|||
|
|
@ -72,16 +72,17 @@ var (
|
|||
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
||||
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
||||
|
||||
snapshotAccountReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/account/reads", nil)
|
||||
snapshotStorageReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/storage/reads", nil)
|
||||
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
|
||||
accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil)
|
||||
storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil)
|
||||
|
||||
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
|
||||
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
|
||||
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
|
||||
|
||||
blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil)
|
||||
blockValidationTimer = metrics.NewRegisteredResettingTimer("chain/validation", nil)
|
||||
blockExecutionTimer = metrics.NewRegisteredResettingTimer("chain/execution", nil)
|
||||
blockWriteTimer = metrics.NewRegisteredResettingTimer("chain/write", nil)
|
||||
blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil)
|
||||
blockValidationTimer = metrics.NewRegisteredResettingTimer("chain/validation", nil)
|
||||
blockCrossValidationTimer = metrics.NewRegisteredResettingTimer("chain/crossvalidation", nil)
|
||||
blockExecutionTimer = metrics.NewRegisteredResettingTimer("chain/execution", nil)
|
||||
blockWriteTimer = metrics.NewRegisteredResettingTimer("chain/write", nil)
|
||||
|
||||
blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil)
|
||||
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
|
||||
|
|
@ -217,7 +218,7 @@ type BlockChain struct {
|
|||
lastWrite uint64 // Last block when the state was flushed
|
||||
flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state
|
||||
triedb *triedb.Database // The database handler for maintaining trie nodes.
|
||||
stateCache state.Database // State database to reuse between imports (contains state cache)
|
||||
statedb *state.CachingDB // State database to reuse between imports (contains state cache)
|
||||
txIndexer *txIndexer // Transaction indexer, might be nil if not enabled
|
||||
|
||||
hc *HeaderChain
|
||||
|
|
@ -256,7 +257,6 @@ type BlockChain struct {
|
|||
validator Validator // Block and state validator interface
|
||||
prefetcher Prefetcher
|
||||
processor Processor // Block transaction processor interface
|
||||
forker *ForkChoice
|
||||
vmConfig vm.Config
|
||||
logger *tracing.Hooks
|
||||
}
|
||||
|
|
@ -264,7 +264,7 @@ type BlockChain struct {
|
|||
// NewBlockChain returns a fully initialised block chain using information
|
||||
// available in the database. It initialises the default Ethereum Validator
|
||||
// and Processor.
|
||||
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis, overrides *ChainOverrides, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) {
|
||||
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis, overrides *ChainOverrides, engine consensus.Engine, vmConfig vm.Config, txLookupLimit *uint64) (*BlockChain, error) {
|
||||
if cacheConfig == nil {
|
||||
cacheConfig = defaultCacheConfig
|
||||
}
|
||||
|
|
@ -309,8 +309,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||
return nil, err
|
||||
}
|
||||
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
||||
bc.forker = NewForkChoice(bc, shouldPreserve)
|
||||
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
||||
bc.statedb = state.NewDatabase(bc.triedb, nil)
|
||||
bc.validator = NewBlockValidator(chainConfig, bc)
|
||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
||||
bc.processor = NewStateProcessor(chainConfig, bc.hc)
|
||||
|
|
@ -448,7 +447,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||
AsyncBuild: !bc.cacheConfig.SnapshotWait,
|
||||
}
|
||||
bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root)
|
||||
|
||||
// Re-initialize the state database with snapshot
|
||||
bc.statedb = state.NewDatabase(bc.triedb, bc.snaps)
|
||||
}
|
||||
|
||||
// Rewind the chain in case of an incompatible config upgrade.
|
||||
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
||||
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
|
||||
|
|
@ -1240,13 +1243,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
|||
|
||||
// Rewind may have occurred, skip in that case.
|
||||
if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 {
|
||||
reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), head.Header())
|
||||
if err != nil {
|
||||
log.Warn("Reorg failed", "err", err)
|
||||
return false
|
||||
} else if !reorg {
|
||||
return false
|
||||
}
|
||||
rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
|
||||
bc.currentSnapBlock.Store(head.Header())
|
||||
headFastBlockGauge.Update(int64(head.NumberU64()))
|
||||
|
|
@ -1545,42 +1541,30 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
|
|||
return NonStatTy, err
|
||||
}
|
||||
currentBlock := bc.CurrentBlock()
|
||||
reorg, err := bc.forker.ReorgNeeded(currentBlock, block.Header())
|
||||
if err != nil {
|
||||
return NonStatTy, err
|
||||
}
|
||||
if reorg {
|
||||
// Reorganise the chain if the parent is not the head block
|
||||
if block.ParentHash() != currentBlock.Hash() {
|
||||
if err := bc.reorg(currentBlock, block); err != nil {
|
||||
return NonStatTy, err
|
||||
}
|
||||
|
||||
// Reorganise the chain if the parent is not the head block
|
||||
if block.ParentHash() != currentBlock.Hash() {
|
||||
if err := bc.reorg(currentBlock, block); err != nil {
|
||||
return NonStatTy, err
|
||||
}
|
||||
status = CanonStatTy
|
||||
} else {
|
||||
status = SideStatTy
|
||||
}
|
||||
|
||||
// Set new head.
|
||||
if status == CanonStatTy {
|
||||
bc.writeHeadBlock(block)
|
||||
bc.writeHeadBlock(block)
|
||||
|
||||
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
|
||||
if len(logs) > 0 {
|
||||
bc.logsFeed.Send(logs)
|
||||
}
|
||||
if status == CanonStatTy {
|
||||
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
|
||||
if len(logs) > 0 {
|
||||
bc.logsFeed.Send(logs)
|
||||
}
|
||||
// In theory, we should fire a ChainHeadEvent when we inject
|
||||
// a canonical block, but sometimes we can insert a batch of
|
||||
// canonical blocks. Avoid firing too many ChainHeadEvents,
|
||||
// we will fire an accumulated ChainHeadEvent and disable fire
|
||||
// event here.
|
||||
if emitHeadEvent {
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
|
||||
}
|
||||
} else {
|
||||
bc.chainSideFeed.Send(ChainSideEvent{Block: block})
|
||||
// In theory, we should fire a ChainHeadEvent when we inject
|
||||
// a canonical block, but sometimes we can insert a batch of
|
||||
// canonical blocks. Avoid firing too many ChainHeadEvents,
|
||||
// we will fire an accumulated ChainHeadEvent and disable fire
|
||||
// event here.
|
||||
if emitHeadEvent {
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
|
||||
}
|
||||
return status, nil
|
||||
return CanonStatTy, nil
|
||||
}
|
||||
|
||||
// InsertChain attempts to insert the given batch of blocks in to the canonical
|
||||
|
|
@ -1615,7 +1599,9 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
|||
return 0, errChainStopped
|
||||
}
|
||||
defer bc.chainmu.Unlock()
|
||||
return bc.insertChain(chain, true)
|
||||
|
||||
_, n, err := bc.insertChain(chain, true, false) // No witness collection for mass inserts (would get super large)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// insertChain is the internal implementation of InsertChain, which assumes that
|
||||
|
|
@ -1626,12 +1612,11 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
|||
// racey behaviour. If a sidechain import is in progress, and the historic state
|
||||
// is imported, but then new canon-head is added before the actual sidechain
|
||||
// completes, then the historic state could be pruned again
|
||||
func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) {
|
||||
func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness bool) (*stateless.Witness, int, error) {
|
||||
// If the chain is terminating, don't even bother starting up.
|
||||
if bc.insertStopped() {
|
||||
return 0, nil
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
|
||||
SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain)
|
||||
|
||||
|
|
@ -1664,24 +1649,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// 2. The block is stored as a sidechain, and is lying about it's stateroot, and passes a stateroot
|
||||
// from the canonical chain, which has not been verified.
|
||||
// Skip all known blocks that are behind us.
|
||||
var (
|
||||
reorg bool
|
||||
current = bc.CurrentBlock()
|
||||
)
|
||||
current := bc.CurrentBlock()
|
||||
for block != nil && bc.skipBlock(err, it) {
|
||||
reorg, err = bc.forker.ReorgNeeded(current, block.Header())
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
}
|
||||
if reorg {
|
||||
// Switch to import mode if the forker says the reorg is necessary
|
||||
// and also the block is not on the canonical chain.
|
||||
// In eth2 the forker always returns true for reorg decision (blindly trusting
|
||||
// the external consensus engine), but in order to prevent the unnecessary
|
||||
// reorgs when importing known blocks, the special case is handled here.
|
||||
if block.NumberU64() > current.Number.Uint64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() {
|
||||
break
|
||||
}
|
||||
if block.NumberU64() > current.Number.Uint64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() {
|
||||
break
|
||||
}
|
||||
log.Debug("Ignoring already known block", "number", block.Number(), "hash", block.Hash())
|
||||
stats.ignored++
|
||||
|
|
@ -1699,7 +1670,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
for block != nil && bc.skipBlock(err, it) {
|
||||
log.Debug("Writing previously known block", "number", block.Number(), "hash", block.Hash())
|
||||
if err := bc.writeKnownBlock(block); err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
lastCanon = block
|
||||
|
||||
|
|
@ -1713,12 +1684,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
if setHead {
|
||||
// First block is pruned, insert as sidechain and reorg only if TD grows enough
|
||||
log.Debug("Pruned ancestor, inserting as sidechain", "number", block.Number(), "hash", block.Hash())
|
||||
return bc.insertSideChain(block, it)
|
||||
return bc.insertSideChain(block, it, makeWitness)
|
||||
} else {
|
||||
// We're post-merge and the parent is pruned, try to recover the parent state
|
||||
log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash())
|
||||
_, err := bc.recoverAncestors(block)
|
||||
return it.index, err
|
||||
_, err := bc.recoverAncestors(block, makeWitness)
|
||||
return nil, it.index, err
|
||||
}
|
||||
// Some other error(except ErrKnownBlock) occurred, abort.
|
||||
// ErrKnownBlock is allowed here since some known blocks
|
||||
|
|
@ -1726,7 +1697,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
case err != nil && !errors.Is(err, ErrKnownBlock):
|
||||
stats.ignored += len(it.chain)
|
||||
bc.reportBlock(block, nil, err)
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
// No validation errors for the first block (or chain prefix skipped)
|
||||
var activeState *state.StateDB
|
||||
|
|
@ -1740,6 +1711,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
}
|
||||
}()
|
||||
|
||||
// Track the singleton witness from this chain insertion (if any)
|
||||
var witness *stateless.Witness
|
||||
|
||||
for ; block != nil && err == nil || errors.Is(err, ErrKnownBlock); block, err = it.next() {
|
||||
// If the chain is terminating, stop processing blocks
|
||||
if bc.insertStopped() {
|
||||
|
|
@ -1776,7 +1750,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
"hash", block.Hash(), "number", block.NumberU64())
|
||||
}
|
||||
if err := bc.writeKnownBlock(block); err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
stats.processed++
|
||||
if bc.logger != nil && bc.logger.OnSkippedBlock != nil {
|
||||
|
|
@ -1787,22 +1761,20 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
Safe: bc.CurrentSafeBlock(),
|
||||
})
|
||||
}
|
||||
|
||||
// We can assume that logs are empty here, since the only way for consecutive
|
||||
// Clique blocks to have the same state is if there are no transactions.
|
||||
lastCanon = block
|
||||
continue
|
||||
}
|
||||
|
||||
// Retrieve the parent block and it's state to execute on top
|
||||
start := time.Now()
|
||||
parent := it.previous()
|
||||
if parent == nil {
|
||||
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||
}
|
||||
statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps)
|
||||
statedb, err := state.New(parent.Root, bc.statedb)
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
statedb.SetLogger(bc.logger)
|
||||
|
||||
|
|
@ -1810,11 +1782,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// while processing transactions. Before Byzantium the prefetcher is mostly
|
||||
// useless due to the intermediate root hashing after each transaction.
|
||||
if bc.chainConfig.IsByzantium(block.Number()) {
|
||||
var witness *stateless.Witness
|
||||
if bc.vmConfig.EnableWitnessCollection {
|
||||
witness, err = stateless.NewWitness(bc, block)
|
||||
// Generate witnesses either if we're self-testing, or if it's the
|
||||
// only block being inserted. A bit crude, but witnesses are huge,
|
||||
// so we refuse to make an entire chain of them.
|
||||
if bc.vmConfig.StatelessSelfValidation || (makeWitness && len(chain) == 1) {
|
||||
witness, err = stateless.NewWitness(block.Header(), bc)
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
}
|
||||
statedb.StartPrefetcher("chain", witness)
|
||||
|
|
@ -1826,7 +1800,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
var followupInterrupt atomic.Bool
|
||||
if !bc.cacheConfig.TrieCleanNoPrefetch {
|
||||
if followup, err := it.peek(); followup != nil && err == nil {
|
||||
throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps)
|
||||
throwaway, _ := state.New(parent.Root, bc.statedb)
|
||||
|
||||
go func(start time.Time, followup *types.Block, throwaway *state.StateDB) {
|
||||
// Disable tracing for prefetcher executions.
|
||||
|
|
@ -1846,7 +1820,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
res, err := bc.processBlock(block, statedb, start, setHead)
|
||||
followupInterrupt.Store(true)
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
// Report the import stats before returning the various results
|
||||
stats.processed++
|
||||
|
|
@ -1863,7 +1837,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// After merge we expect few side chains. Simply count
|
||||
// all blocks the CL gives us for GC processing time
|
||||
bc.gcproc += res.procTime
|
||||
return it.index, nil // Direct block insertion of a single block
|
||||
return witness, it.index, nil // Direct block insertion of a single block
|
||||
}
|
||||
switch res.status {
|
||||
case CanonStatTy:
|
||||
|
|
@ -1893,7 +1867,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
}
|
||||
}
|
||||
stats.ignored += it.remaining()
|
||||
return it.index, err
|
||||
return witness, it.index, err
|
||||
}
|
||||
|
||||
// blockProcessingResult is a summary of block processing
|
||||
|
|
@ -1924,42 +1898,68 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
|
||||
// Process block using the parent state as reference point
|
||||
pstart := time.Now()
|
||||
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
|
||||
res, err := bc.processor.Process(block, statedb, bc.vmConfig)
|
||||
if err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
bc.reportBlock(block, res, err)
|
||||
return nil, err
|
||||
}
|
||||
ptime := time.Since(pstart)
|
||||
|
||||
vstart := time.Now()
|
||||
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
if err := bc.validator.ValidateState(block, statedb, res, false); err != nil {
|
||||
bc.reportBlock(block, res, err)
|
||||
return nil, err
|
||||
}
|
||||
vtime := time.Since(vstart)
|
||||
|
||||
if witness := statedb.Witness(); witness != nil {
|
||||
if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
return nil, fmt.Errorf("cross verification failed: %v", err)
|
||||
// If witnesses was generated and stateless self-validation requested, do
|
||||
// that now. Self validation should *never* run in production, it's more of
|
||||
// a tight integration to enable running *all* consensus tests through the
|
||||
// witness builder/runner, which would otherwise be impossible due to the
|
||||
// various invalid chain states/behaviors being contained in those tests.
|
||||
xvstart := time.Now()
|
||||
if witness := statedb.Witness(); witness != nil && bc.vmConfig.StatelessSelfValidation {
|
||||
log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash())
|
||||
|
||||
// Remove critical computed fields from the block to force true recalculation
|
||||
context := block.Header()
|
||||
context.Root = common.Hash{}
|
||||
context.ReceiptHash = common.Hash{}
|
||||
|
||||
task := types.NewBlockWithHeader(context).WithBody(*block.Body())
|
||||
|
||||
// Run the stateless self-cross-validation
|
||||
crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, task, witness)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stateless self-validation failed: %v", err)
|
||||
}
|
||||
if crossStateRoot != block.Root() {
|
||||
return nil, fmt.Errorf("stateless self-validation root mismatch (cross: %x local: %x)", crossStateRoot, block.Root())
|
||||
}
|
||||
if crossReceiptRoot != block.ReceiptHash() {
|
||||
return nil, fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, block.ReceiptHash())
|
||||
}
|
||||
}
|
||||
proctime := time.Since(start) // processing + validation
|
||||
xvtime := time.Since(xvstart)
|
||||
proctime := time.Since(start) // processing + validation + cross validation
|
||||
|
||||
// Update the metrics touched during block processing and validation
|
||||
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
||||
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
|
||||
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
|
||||
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
|
||||
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
|
||||
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
|
||||
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
||||
triehash := statedb.AccountHashes // The time spent on tries hashing
|
||||
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
|
||||
trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
|
||||
trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
|
||||
blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing
|
||||
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
|
||||
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
||||
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
|
||||
if statedb.AccountLoaded != 0 {
|
||||
accountReadSingleTimer.Update(statedb.AccountReads / time.Duration(statedb.AccountLoaded))
|
||||
}
|
||||
if statedb.StorageLoaded != 0 {
|
||||
storageReadSingleTimer.Update(statedb.StorageReads / time.Duration(statedb.StorageLoaded))
|
||||
}
|
||||
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
|
||||
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
|
||||
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
||||
triehash := statedb.AccountHashes // The time spent on tries hashing
|
||||
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
|
||||
blockExecutionTimer.Update(ptime - (statedb.AccountReads + statedb.StorageReads)) // The time spent on EVM processing
|
||||
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
|
||||
blockCrossValidationTimer.Update(xvtime) // The time spent on stateless cross validation
|
||||
|
||||
// Write the block to the chain and get the status.
|
||||
var (
|
||||
|
|
@ -1968,9 +1968,9 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
)
|
||||
if !setHead {
|
||||
// Don't set the head, only insert the block
|
||||
err = bc.writeBlockWithState(block, receipts, statedb)
|
||||
err = bc.writeBlockWithState(block, res.Receipts, statedb)
|
||||
} else {
|
||||
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
|
||||
status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -1984,7 +1984,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
||||
blockInsertTimer.UpdateSince(start)
|
||||
|
||||
return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil
|
||||
return &blockProcessingResult{usedGas: res.GasUsed, procTime: proctime, status: status}, nil
|
||||
}
|
||||
|
||||
// insertSideChain is called when an import batch hits upon a pruned ancestor
|
||||
|
|
@ -1994,11 +1994,10 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
// The method writes all (header-and-body-valid) blocks to disk, then tries to
|
||||
// switch over to the new chain if the TD exceeded the current chain.
|
||||
// insertSideChain is only used pre-merge.
|
||||
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, error) {
|
||||
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, makeWitness bool) (*stateless.Witness, int, error) {
|
||||
var (
|
||||
externTd *big.Int
|
||||
lastBlock = block
|
||||
current = bc.CurrentBlock()
|
||||
externTd *big.Int
|
||||
current = bc.CurrentBlock()
|
||||
)
|
||||
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
||||
// Since we don't import them here, we expect ErrUnknownAncestor for the remaining
|
||||
|
|
@ -2031,7 +2030,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
// If someone legitimately side-mines blocks, they would still be imported as usual. However,
|
||||
// we cannot risk writing unverified blocks to disk when they obviously target the pruning
|
||||
// mechanism.
|
||||
return it.index, errors.New("sidechain ghost-state attack")
|
||||
return nil, it.index, errors.New("sidechain ghost-state attack")
|
||||
}
|
||||
}
|
||||
if externTd == nil {
|
||||
|
|
@ -2042,29 +2041,13 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
if !bc.HasBlock(block.Hash(), block.NumberU64()) {
|
||||
start := time.Now()
|
||||
if err := bc.writeBlockWithoutState(block, externTd); err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(),
|
||||
"diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)),
|
||||
"txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()),
|
||||
"root", block.Root())
|
||||
}
|
||||
lastBlock = block
|
||||
}
|
||||
// At this point, we've written all sidechain blocks to database. Loop ended
|
||||
// either on some other error or all were processed. If there was some other
|
||||
// error, we can ignore the rest of those blocks.
|
||||
//
|
||||
// If the externTd was larger than our local TD, we now need to reimport the previous
|
||||
// blocks to regenerate the required state
|
||||
reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header())
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
}
|
||||
if !reorg {
|
||||
localTd := bc.GetTd(current.Hash(), current.Number.Uint64())
|
||||
log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd)
|
||||
return it.index, err
|
||||
}
|
||||
// Gather all the sidechain hashes (full blocks may be memory heavy)
|
||||
var (
|
||||
|
|
@ -2075,7 +2058,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
for parent != nil && !bc.HasState(parent.Root) {
|
||||
if bc.stateRecoverable(parent.Root) {
|
||||
if err := bc.triedb.Recover(parent.Root); err != nil {
|
||||
return 0, err
|
||||
return nil, 0, err
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
@ -2085,7 +2068,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
parent = bc.GetHeader(parent.ParentHash, parent.Number.Uint64()-1)
|
||||
}
|
||||
if parent == nil {
|
||||
return it.index, errors.New("missing parent")
|
||||
return nil, it.index, errors.New("missing parent")
|
||||
}
|
||||
// Import all the pruned blocks to make the state available
|
||||
var (
|
||||
|
|
@ -2104,30 +2087,30 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
// memory here.
|
||||
if len(blocks) >= 2048 || memory > 64*1024*1024 {
|
||||
log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64())
|
||||
if _, err := bc.insertChain(blocks, true); err != nil {
|
||||
return 0, err
|
||||
if _, _, err := bc.insertChain(blocks, true, false); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
blocks, memory = blocks[:0], 0
|
||||
|
||||
// If the chain is terminating, stop processing blocks
|
||||
if bc.insertStopped() {
|
||||
log.Debug("Abort during blocks processing")
|
||||
return 0, nil
|
||||
return nil, 0, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(blocks) > 0 {
|
||||
log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64())
|
||||
return bc.insertChain(blocks, true)
|
||||
return bc.insertChain(blocks, true, makeWitness)
|
||||
}
|
||||
return 0, nil
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
// recoverAncestors finds the closest ancestor with available state and re-execute
|
||||
// all the ancestor blocks since that.
|
||||
// recoverAncestors is only used post-merge.
|
||||
// We return the hash of the latest block that we could correctly validate.
|
||||
func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) {
|
||||
func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (common.Hash, error) {
|
||||
// Gather all the sidechain hashes (full blocks may be memory heavy)
|
||||
var (
|
||||
hashes []common.Hash
|
||||
|
|
@ -2167,7 +2150,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error)
|
|||
} else {
|
||||
b = bc.GetBlock(hashes[i], numbers[i])
|
||||
}
|
||||
if _, err := bc.insertChain(types.Blocks{b}, false); err != nil {
|
||||
if _, _, err := bc.insertChain(types.Blocks{b}, false, makeWitness && i == 0); err != nil {
|
||||
return b.ParentHash(), err
|
||||
}
|
||||
}
|
||||
|
|
@ -2383,14 +2366,14 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
|
|||
// The key difference between the InsertChain is it won't do the canonical chain
|
||||
// updating. It relies on the additional SetCanonical call to finalize the entire
|
||||
// procedure.
|
||||
func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block) error {
|
||||
func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block, makeWitness bool) (*stateless.Witness, error) {
|
||||
if !bc.chainmu.TryLock() {
|
||||
return errChainStopped
|
||||
return nil, errChainStopped
|
||||
}
|
||||
defer bc.chainmu.Unlock()
|
||||
|
||||
_, err := bc.insertChain(types.Blocks{block}, false)
|
||||
return err
|
||||
witness, _, err := bc.insertChain(types.Blocks{block}, false, makeWitness)
|
||||
return witness, err
|
||||
}
|
||||
|
||||
// SetCanonical rewinds the chain to set the new head block as the specified
|
||||
|
|
@ -2404,7 +2387,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
|
|||
|
||||
// Re-execute the reorged chain in case the head state is missing.
|
||||
if !bc.HasState(head.Root()) {
|
||||
if latestValidHash, err := bc.recoverAncestors(head); err != nil {
|
||||
if latestValidHash, err := bc.recoverAncestors(head, false); err != nil {
|
||||
return latestValidHash, err
|
||||
}
|
||||
log.Info("Recovered head state", "number", head.Number(), "hash", head.Hash())
|
||||
|
|
@ -2481,7 +2464,11 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool {
|
|||
}
|
||||
|
||||
// reportBlock logs a bad block error.
|
||||
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
|
||||
func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err error) {
|
||||
var receipts types.Receipts
|
||||
if res != nil {
|
||||
receipts = res.Receipts
|
||||
}
|
||||
rawdb.WriteBadBlock(bc.db, block)
|
||||
log.Error(summarizeBadBlock(block, receipts, bc.Config(), err))
|
||||
}
|
||||
|
|
@ -2527,7 +2514,7 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header) (int, error) {
|
|||
return 0, errChainStopped
|
||||
}
|
||||
defer bc.chainmu.Unlock()
|
||||
_, err := bc.hc.InsertHeaderChain(chain, start, bc.forker)
|
||||
_, err := bc.hc.InsertHeaderChain(chain, start)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,11 +170,6 @@ func (it *insertIterator) current() *types.Header {
|
|||
return it.chain[it.index].Header()
|
||||
}
|
||||
|
||||
// first returns the first block in it.
|
||||
func (it *insertIterator) first() *types.Block {
|
||||
return it.chain[0]
|
||||
}
|
||||
|
||||
// remaining returns the number of remaining blocks.
|
||||
func (it *insertIterator) remaining() int {
|
||||
return len(it.chain) - it.index
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
|||
|
||||
// HasState checks if state trie is fully present in the database or not.
|
||||
func (bc *BlockChain) HasState(hash common.Hash) bool {
|
||||
_, err := bc.stateCache.OpenTrie(hash)
|
||||
_, err := bc.statedb.OpenTrie(hash)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
|
|
@ -341,12 +341,9 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool {
|
|||
// If the code doesn't exist in the in-memory cache, check the storage with
|
||||
// new code scheme.
|
||||
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
|
||||
type codeReader interface {
|
||||
ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error)
|
||||
}
|
||||
// TODO(rjl493456442) The associated account address is also required
|
||||
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
|
||||
return bc.stateCache.(codeReader).ContractCodeWithPrefix(common.Address{}, hash)
|
||||
return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)
|
||||
}
|
||||
|
||||
// State returns a new mutable state based on the current HEAD block.
|
||||
|
|
@ -356,7 +353,7 @@ func (bc *BlockChain) State() (*state.StateDB, error) {
|
|||
|
||||
// StateAt returns a new mutable state based on a particular point in time.
|
||||
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
|
||||
return state.New(root, bc.stateCache, bc.snaps)
|
||||
return state.New(root, bc.statedb)
|
||||
}
|
||||
|
||||
// Config retrieves the chain's fork configuration.
|
||||
|
|
@ -382,7 +379,7 @@ func (bc *BlockChain) Processor() Processor {
|
|||
|
||||
// StateCache returns the caching database underpinning the blockchain instance.
|
||||
func (bc *BlockChain) StateCache() state.Database {
|
||||
return bc.stateCache
|
||||
return bc.statedb
|
||||
}
|
||||
|
||||
// GasLimit returns the gas limit of the current HEAD block.
|
||||
|
|
|
|||
|
|
@ -1757,8 +1757,8 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
|
||||
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))
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(tt.dump(false))
|
||||
|
||||
// Create a temporary persistent database
|
||||
datadir := t.TempDir()
|
||||
|
|
@ -1794,7 +1794,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
|
|||
config.SnapshotLimit = 256
|
||||
config.SnapshotWait = true
|
||||
}
|
||||
chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
|
|
@ -1859,7 +1859,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
|
|||
}
|
||||
defer db.Close()
|
||||
|
||||
newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -1908,7 +1908,7 @@ func TestIssue23496(t *testing.T) {
|
|||
|
||||
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))))
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
|
||||
// Create a temporary persistent database
|
||||
datadir := t.TempDir()
|
||||
|
|
@ -1931,7 +1931,7 @@ func testIssue23496(t *testing.T, scheme string) {
|
|||
}
|
||||
engine = ethash.NewFullFaker()
|
||||
)
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
|
|
@ -1981,7 +1981,7 @@ func testIssue23496(t *testing.T, scheme string) {
|
|||
}
|
||||
defer db.Close()
|
||||
|
||||
chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1961,7 +1961,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
|
||||
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))))
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(tt.dump(false))
|
||||
|
||||
// Create a temporary persistent database
|
||||
|
|
@ -1997,7 +1997,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
|
|||
config.SnapshotLimit = 256
|
||||
config.SnapshotWait = true
|
||||
}
|
||||
chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
|
|
@ -2040,7 +2040,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
|
|||
dbconfig.HashDB = hashdb.Defaults
|
||||
}
|
||||
chain.triedb = triedb.NewDatabase(chain.db, dbconfig)
|
||||
chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb)
|
||||
chain.statedb = state.NewDatabase(chain.triedb, chain.snaps)
|
||||
|
||||
// Force run a freeze cycle
|
||||
type freezer interface {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
|||
}
|
||||
engine = ethash.NewFullFaker()
|
||||
)
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create chain: %v", err)
|
||||
}
|
||||
|
|
@ -222,13 +222,13 @@ type snapshotTest struct {
|
|||
|
||||
func (snaptest *snapshotTest) test(t *testing.T) {
|
||||
// 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())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Restart the chain normally
|
||||
chain.Stop()
|
||||
newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), 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)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -245,8 +245,8 @@ type crashSnapshotTest struct {
|
|||
|
||||
func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||
// 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())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Pull the plug on the database, simulating a hard crash
|
||||
|
|
@ -270,13 +270,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, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err := NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
newchain.Stop()
|
||||
|
||||
newchain, err = NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err = NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -297,8 +297,8 @@ type gappedSnapshotTest struct {
|
|||
|
||||
func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||
// 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())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Insert blocks without enabling snapshot if gapping is required.
|
||||
|
|
@ -313,7 +313,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
|||
SnapshotLimit: 0,
|
||||
StateScheme: snaptest.scheme,
|
||||
}
|
||||
newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -321,7 +321,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
|||
newchain.Stop()
|
||||
|
||||
// Restart the chain with enabling the snapshot
|
||||
newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), 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)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -341,15 +341,15 @@ type setHeadSnapshotTest struct {
|
|||
|
||||
func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
|
||||
// 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())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Rewind the chain if setHead operation is required.
|
||||
chain.SetHead(snaptest.setHead)
|
||||
chain.Stop()
|
||||
|
||||
newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), 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)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -370,8 +370,8 @@ type wipeCrashSnapshotTest struct {
|
|||
|
||||
func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||
// 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())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Firstly, stop the chain properly, with all snapshot journal
|
||||
|
|
@ -385,7 +385,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
|||
SnapshotLimit: 0,
|
||||
StateScheme: snaptest.scheme,
|
||||
}
|
||||
newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -402,7 +402,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
|||
SnapshotWait: false, // Don't wait rebuild
|
||||
StateScheme: snaptest.scheme,
|
||||
}
|
||||
tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil)
|
||||
tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
@ -411,7 +411,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
|||
tmp.triedb.Close()
|
||||
tmp.stopWithoutSaving()
|
||||
|
||||
newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), 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)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to recreate chain: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"math/big"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -61,7 +62,7 @@ func newCanonical(engine consensus.Engine, n int, full bool, scheme string) (eth
|
|||
}
|
||||
)
|
||||
// Initialize a fresh chain with only a genesis block
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
|
||||
|
||||
// Create and inject the requested chain
|
||||
if n == 0 {
|
||||
|
|
@ -159,17 +160,18 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
|||
}
|
||||
return err
|
||||
}
|
||||
statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.stateCache, nil)
|
||||
statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.statedb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{})
|
||||
res, err := blockchain.processor.Process(block, statedb, vm.Config{})
|
||||
if err != nil {
|
||||
blockchain.reportBlock(block, receipts, err)
|
||||
blockchain.reportBlock(block, res, err)
|
||||
return err
|
||||
}
|
||||
if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
||||
blockchain.reportBlock(block, receipts, err)
|
||||
err = blockchain.validator.ValidateState(block, statedb, res, false)
|
||||
if err != nil {
|
||||
blockchain.reportBlock(block, res, err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -762,7 +764,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
|
|||
})
|
||||
// Import the chain as an archive node for the comparison baseline
|
||||
archiveDb := rawdb.NewMemoryDatabase()
|
||||
archive, _ := NewBlockChain(archiveDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
archive, _ := NewBlockChain(archiveDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer archive.Stop()
|
||||
|
||||
if n, err := archive.InsertChain(blocks); err != nil {
|
||||
|
|
@ -770,7 +772,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
|
|||
}
|
||||
// Fast import the chain as a non-archive node to test
|
||||
fastDb := rawdb.NewMemoryDatabase()
|
||||
fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer fast.Stop()
|
||||
|
||||
headers := make([]*types.Header, len(blocks))
|
||||
|
|
@ -790,7 +792,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
|
|||
}
|
||||
defer ancientDb.Close()
|
||||
|
||||
ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer ancient.Stop()
|
||||
|
||||
if n, err := ancient.InsertHeaderChain(headers); err != nil {
|
||||
|
|
@ -910,7 +912,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
|
|||
archiveCaching.TrieDirtyDisabled = true
|
||||
archiveCaching.StateScheme = scheme
|
||||
|
||||
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
if n, err := archive.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("failed to process block %d: %v", n, err)
|
||||
}
|
||||
|
|
@ -923,7 +925,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
|
|||
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||
fastDb := makeDb()
|
||||
defer fastDb.Close()
|
||||
fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer fast.Stop()
|
||||
|
||||
headers := make([]*types.Header, len(blocks))
|
||||
|
|
@ -943,7 +945,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
|
|||
// Import the chain as a ancient-first node and ensure all pointers are updated
|
||||
ancientDb := makeDb()
|
||||
defer ancientDb.Close()
|
||||
ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer ancient.Stop()
|
||||
|
||||
if n, err := ancient.InsertHeaderChain(headers); err != nil {
|
||||
|
|
@ -962,7 +964,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
|
|||
// Import the chain as a light node and ensure all pointers are updated
|
||||
lightDb := makeDb()
|
||||
defer lightDb.Close()
|
||||
light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
if n, err := light.InsertHeaderChain(headers); err != nil {
|
||||
t.Fatalf("failed to insert header %d: %v", n, err)
|
||||
}
|
||||
|
|
@ -1035,7 +1037,7 @@ func testChainTxReorgs(t *testing.T, scheme string) {
|
|||
})
|
||||
// Import the chain. This runs all block validation rules.
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
||||
}
|
||||
|
|
@ -1109,7 +1111,7 @@ func testLogReorgs(t *testing.T, scheme string) {
|
|||
signer = types.LatestSigner(gspec.Config)
|
||||
)
|
||||
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
rmLogsCh := make(chan RemovedLogsEvent)
|
||||
|
|
@ -1165,7 +1167,7 @@ func testLogRebirth(t *testing.T, scheme string) {
|
|||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
engine = ethash.NewFaker()
|
||||
blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
|
||||
)
|
||||
defer blockchain.Stop()
|
||||
|
||||
|
|
@ -1246,7 +1248,7 @@ func testSideLogRebirth(t *testing.T, scheme string) {
|
|||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
)
|
||||
defer blockchain.Stop()
|
||||
|
||||
|
|
@ -1265,7 +1267,7 @@ func testSideLogRebirth(t *testing.T, scheme string) {
|
|||
}
|
||||
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
|
||||
|
||||
// Generate side chain with lower difficulty
|
||||
// Generate side chain with lower difficulty, after the merge, the chain will be accepted even if it is lower difficulty
|
||||
genDb, sideChain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *BlockGen) {
|
||||
if i == 1 {
|
||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1)
|
||||
|
|
@ -1278,14 +1280,14 @@ func testSideLogRebirth(t *testing.T, scheme string) {
|
|||
if _, err := blockchain.InsertChain(sideChain); err != nil {
|
||||
t.Fatalf("failed to insert forked chain: %v", err)
|
||||
}
|
||||
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
|
||||
checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
|
||||
|
||||
// Generate a new block based on side chain.
|
||||
// Generate a new block based on side chain. Should not emit any events anymore.
|
||||
newBlocks, _ := GenerateChain(gspec.Config, sideChain[len(sideChain)-1], ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
if _, err := blockchain.InsertChain(newBlocks); err != nil {
|
||||
t.Fatalf("failed to insert forked chain: %v", err)
|
||||
}
|
||||
checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
|
||||
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
|
||||
}
|
||||
|
||||
func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan RemovedLogsEvent, wantNew, wantRemoved int) {
|
||||
|
|
@ -1345,7 +1347,7 @@ func testReorgSideEvent(t *testing.T, scheme string) {
|
|||
}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
)
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
_, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {})
|
||||
|
|
@ -1369,15 +1371,10 @@ func testReorgSideEvent(t *testing.T, scheme string) {
|
|||
t.Fatalf("failed to insert chain: %v", err)
|
||||
}
|
||||
|
||||
// first two block of the secondary chain are for a brief moment considered
|
||||
// side chains because up to that point the first one is considered the
|
||||
// heavier chain.
|
||||
expectedSideHashes := map[common.Hash]bool{
|
||||
replacementBlocks[0].Hash(): true,
|
||||
replacementBlocks[1].Hash(): true,
|
||||
chain[0].Hash(): true,
|
||||
chain[1].Hash(): true,
|
||||
chain[2].Hash(): true,
|
||||
chain[0].Hash(): true,
|
||||
chain[1].Hash(): true,
|
||||
chain[2].Hash(): true,
|
||||
}
|
||||
|
||||
i := 0
|
||||
|
|
@ -1402,7 +1399,7 @@ done:
|
|||
timeout.Reset(timeoutDura)
|
||||
|
||||
case <-timeout.C:
|
||||
t.Fatal("Timeout. Possibly not all blocks were triggered for sideevent")
|
||||
t.Fatalf("Timeout. Possibly not all blocks were triggered for sideevent: %v", i)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1529,7 +1526,7 @@ func testEIP155Transition(t *testing.T, scheme string) {
|
|||
}
|
||||
})
|
||||
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
if _, err := blockchain.InsertChain(blocks); err != nil {
|
||||
|
|
@ -1622,7 +1619,7 @@ func testEIP161AccountRemoval(t *testing.T, scheme string) {
|
|||
block.AddTx(tx)
|
||||
})
|
||||
// account must exist pre eip 161
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil {
|
||||
|
|
@ -1680,7 +1677,7 @@ func testBlockchainHeaderchainReorgConsistency(t *testing.T, scheme string) {
|
|||
}
|
||||
// Import the canonical and fork chain side by side, verifying the current block
|
||||
// and current header consistency
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -1724,7 +1721,7 @@ func TestTrieForkGC(t *testing.T) {
|
|||
forks[i] = fork[0]
|
||||
}
|
||||
// Import the canonical and fork chain side by side, forcing the trie cache to cache both
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -1770,7 +1767,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
|
|||
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
defer db.Close()
|
||||
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -1786,18 +1783,15 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
|
|||
if chain.HasState(shared[len(shared)-1].Root()) {
|
||||
t.Fatalf("common-but-old ancestor still cache")
|
||||
}
|
||||
// Import the competitor chain without exceeding the canonical's TD and ensure
|
||||
// we have not processed any of the blocks (protection against malicious blocks)
|
||||
// Import the competitor chain without exceeding the canonical's TD.
|
||||
// Post-merge the side chain should be executed
|
||||
if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil {
|
||||
t.Fatalf("failed to insert competitor chain: %v", err)
|
||||
}
|
||||
for i, block := range competitor[:len(competitor)-2] {
|
||||
if chain.HasState(block.Root()) {
|
||||
t.Fatalf("competitor %d: low TD chain became processed", i)
|
||||
}
|
||||
if !chain.HasState(competitor[len(competitor)-3].Root()) {
|
||||
t.Fatalf("failed to insert low-TD chain")
|
||||
}
|
||||
// Import the head of the competitor chain, triggering the reorg and ensure we
|
||||
// successfully reprocess all the stashed away blocks.
|
||||
// Import the head of the competitor chain.
|
||||
if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil {
|
||||
t.Fatalf("failed to finalize competitor chain: %v", err)
|
||||
}
|
||||
|
|
@ -1841,7 +1835,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) {
|
|||
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||
}
|
||||
defer ancientDb.Close()
|
||||
ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
|
||||
headers := make([]*types.Header, len(blocks))
|
||||
for i, block := range blocks {
|
||||
|
|
@ -1861,7 +1855,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) {
|
|||
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
|
||||
|
||||
// Reopen broken blockchain again
|
||||
ancient, _ = NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
ancient, _ = NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer ancient.Stop()
|
||||
if num := ancient.CurrentBlock().Number.Uint64(); num != 0 {
|
||||
t.Errorf("head block mismatch: have #%v, want #%v", num, 0)
|
||||
|
|
@ -1913,7 +1907,7 @@ func testInsertReceiptChainRollback(t *testing.T, scheme string) {
|
|||
}
|
||||
defer ancientDb.Close()
|
||||
|
||||
ancientChain, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
ancientChain, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer ancientChain.Stop()
|
||||
|
||||
// Import the canonical header chain.
|
||||
|
|
@ -1980,7 +1974,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
|
|||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
defer diskdb.Close()
|
||||
|
||||
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -2041,7 +2035,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
|||
mergeBlock = math.MaxInt32
|
||||
)
|
||||
// Generate and import the canonical chain
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -2132,9 +2126,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
|||
// [ Cn, Cn+1, Cc, Sn+3 ... Sm]
|
||||
// ^ ^ ^ pruned
|
||||
func TestPrunedImportSide(t *testing.T) {
|
||||
//glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false)))
|
||||
//glogger.Verbosity(3)
|
||||
//log.Root().SetHandler(log.Handler(glogger))
|
||||
// glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
|
||||
// glogger.Verbosity(3)
|
||||
// log.SetDefault(log.NewLogger(glogger))
|
||||
testSideImport(t, 3, 3, -1)
|
||||
testSideImport(t, 3, -3, -1)
|
||||
testSideImport(t, 10, 0, -1)
|
||||
|
|
@ -2143,9 +2137,9 @@ func TestPrunedImportSide(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPrunedImportSideWithMerging(t *testing.T) {
|
||||
//glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false)))
|
||||
//glogger.Verbosity(3)
|
||||
//log.Root().SetHandler(log.Handler(glogger))
|
||||
// glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
|
||||
// glogger.Verbosity(3)
|
||||
// log.SetDefault(log.NewLogger(glogger))
|
||||
testSideImport(t, 3, 3, 0)
|
||||
testSideImport(t, 3, -3, 0)
|
||||
testSideImport(t, 10, 0, 0)
|
||||
|
|
@ -2195,7 +2189,7 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) {
|
|||
}
|
||||
defer chaindb.Close()
|
||||
|
||||
chain, err := NewBlockChain(chaindb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(chaindb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -2279,10 +2273,10 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) {
|
|||
if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
||||
t.Fatalf("failed to insert chain data: %v", err)
|
||||
}
|
||||
// The head shouldn't change.
|
||||
asserter(t, blocks3[len(blocks3)-1])
|
||||
// Post-merge the chain should change even if td is lower.
|
||||
asserter(t, blocks2[len(blocks2)-1])
|
||||
|
||||
// Rollback the heavier chain and re-insert the longer chain again
|
||||
// Rollback the heavier chain and re-insert the longer chain again.
|
||||
chain.SetHead(rollback - 1)
|
||||
if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
||||
t.Fatalf("failed to insert chain data: %v", err)
|
||||
|
|
@ -2366,7 +2360,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
|
|||
}
|
||||
defer chaindb.Close()
|
||||
|
||||
chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -2480,7 +2474,7 @@ func getLongAndShortChains(scheme string) (*BlockChain, []*types.Block, []*types
|
|||
genDb, longChain, _ := GenerateChainWithGenesis(genesis, engine, 80, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{1})
|
||||
})
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -2656,7 +2650,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
|
|||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Import the shared chain and the original canonical one
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
b.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -2743,7 +2737,21 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
|
|||
// Generate and import the canonical chain
|
||||
_, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil)
|
||||
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
// Construct a database with freezer enabled
|
||||
datadir := t.TempDir()
|
||||
ancient := path.Join(datadir, "ancient")
|
||||
|
||||
db, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
Ephemeral: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -2770,7 +2778,6 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
|
|||
if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) {
|
||||
t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64())
|
||||
}
|
||||
// Now re-import some old blocks
|
||||
blockToReimport := blocks[5:8]
|
||||
_, err = chain.InsertChain(blockToReimport)
|
||||
if err != nil {
|
||||
|
|
@ -2843,7 +2850,7 @@ func testDeleteCreateRevert(t *testing.T, scheme string) {
|
|||
b.AddTx(tx)
|
||||
})
|
||||
// Import the canonical chain
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -2958,7 +2965,7 @@ func testDeleteRecreateSlots(t *testing.T, scheme string) {
|
|||
// Import the canonical chain
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
||||
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
||||
}, nil, nil)
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -3040,7 +3047,7 @@ func testDeleteRecreateAccount(t *testing.T, scheme string) {
|
|||
// Import the canonical chain
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
||||
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
||||
}, nil, nil)
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -3216,7 +3223,7 @@ func testDeleteRecreateSlotsAcrossManyBlocks(t *testing.T, scheme string) {
|
|||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
||||
//Debug: true,
|
||||
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
||||
}, nil, nil)
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -3354,7 +3361,7 @@ func testInitThenFailCreateContract(t *testing.T, scheme string) {
|
|||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
||||
//Debug: true,
|
||||
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
||||
}, nil, nil)
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -3441,7 +3448,7 @@ func testEIP2718Transition(t *testing.T, scheme string) {
|
|||
})
|
||||
|
||||
// Import the canonical chain
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -3535,7 +3542,7 @@ func testEIP1559Transition(t *testing.T, scheme string) {
|
|||
|
||||
b.AddTx(tx)
|
||||
})
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -3622,7 +3629,7 @@ func TestSetCanonical(t *testing.T) {
|
|||
}
|
||||
|
||||
func testSetCanonical(t *testing.T, scheme string) {
|
||||
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
|
||||
var (
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
|
|
@ -3648,7 +3655,7 @@ func testSetCanonical(t *testing.T, scheme string) {
|
|||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
defer diskdb.Close()
|
||||
|
||||
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -3667,7 +3674,7 @@ func testSetCanonical(t *testing.T, scheme string) {
|
|||
gen.AddTx(tx)
|
||||
})
|
||||
for _, block := range side {
|
||||
err := chain.InsertBlockWithoutSetHead(block)
|
||||
_, err := chain.InsertBlockWithoutSetHead(block, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to insert into chain: %v", err)
|
||||
}
|
||||
|
|
@ -3757,7 +3764,7 @@ func testCanonicalHashMarker(t *testing.T, scheme string) {
|
|||
_, forkB, _ := GenerateChainWithGenesis(gspec, engine, c.forkB, func(i int, gen *BlockGen) {})
|
||||
|
||||
// Initialize test chain
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -3894,7 +3901,7 @@ func testCreateThenDelete(t *testing.T, config *params.ChainConfig) {
|
|||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{
|
||||
//Debug: true,
|
||||
//Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
||||
}, nil, nil)
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -4006,7 +4013,7 @@ func TestDeleteThenCreate(t *testing.T) {
|
|||
}
|
||||
})
|
||||
// Import the canonical chain
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -4091,7 +4098,7 @@ func TestTransientStorageReset(t *testing.T) {
|
|||
})
|
||||
|
||||
// Initialize the blockchain with 1153 enabled.
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vmConfig, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vmConfig, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -4186,7 +4193,7 @@ func TestEIP3651(t *testing.T) {
|
|||
|
||||
b.AddTx(tx)
|
||||
})
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil)
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -4220,3 +4227,90 @@ func TestEIP3651(t *testing.T) {
|
|||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEIP6110(t *testing.T) {
|
||||
var (
|
||||
engine = beacon.NewFaker()
|
||||
|
||||
// A sender who makes transactions, has some funds
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
config = *params.AllEthashProtocolChanges
|
||||
gspec = &Genesis{
|
||||
Config: &config,
|
||||
Alloc: types.GenesisAlloc{
|
||||
addr: {Balance: funds},
|
||||
config.DepositContractAddress: {
|
||||
// Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7
|
||||
Code: common.Hex2Bytes("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033"),
|
||||
Nonce: 0,
|
||||
Balance: big.NewInt(0),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
gspec.Config.BerlinBlock = common.Big0
|
||||
gspec.Config.LondonBlock = common.Big0
|
||||
gspec.Config.TerminalTotalDifficulty = common.Big0
|
||||
gspec.Config.TerminalTotalDifficultyPassed = true
|
||||
gspec.Config.ShanghaiTime = u64(0)
|
||||
gspec.Config.CancunTime = u64(0)
|
||||
gspec.Config.PragueTime = u64(0)
|
||||
signer := types.LatestSigner(gspec.Config)
|
||||
|
||||
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
|
||||
for i := 0; i < 5; i++ {
|
||||
txdata := &types.DynamicFeeTx{
|
||||
ChainID: gspec.Config.ChainID,
|
||||
Nonce: uint64(i),
|
||||
To: &config.DepositContractAddress,
|
||||
Gas: 500000,
|
||||
GasFeeCap: newGwei(5),
|
||||
GasTipCap: big.NewInt(2),
|
||||
AccessList: nil,
|
||||
Data: []byte{},
|
||||
}
|
||||
tx := types.NewTx(txdata)
|
||||
tx, _ = types.SignTx(tx, signer, key)
|
||||
b.AddTx(tx)
|
||||
}
|
||||
})
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{DisableStack: true}, os.Stderr).Hooks()}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
defer chain.Stop()
|
||||
if n, err := chain.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
|
||||
block := chain.GetBlockByNumber(1)
|
||||
if len(block.Requests()) != 5 {
|
||||
t.Fatalf("failed to retrieve deposits: have %d, want %d", len(block.Requests()), 5)
|
||||
}
|
||||
|
||||
// Verify each index is correct.
|
||||
for want, req := range block.Requests() {
|
||||
d, ok := req.Inner().(*types.Deposit)
|
||||
if !ok {
|
||||
t.Fatalf("expected deposit object")
|
||||
}
|
||||
if got := int(d.PublicKey[0]); got != want {
|
||||
t.Fatalf("invalid pubkey: have %d, want %d", got, want)
|
||||
}
|
||||
if got := int(d.WithdrawalCredentials[0]); got != want {
|
||||
t.Fatalf("invalid withdrawal credentials: have %d, want %d", got, want)
|
||||
}
|
||||
if d.Amount != uint64(want) {
|
||||
t.Fatalf("invalid amounbt: have %d, want %d", d.Amount, want)
|
||||
}
|
||||
if got := int(d.Signature[0]); got != want {
|
||||
t.Fatalf("invalid signature: have %d, want %d", got, want)
|
||||
}
|
||||
if d.Index != uint64(want) {
|
||||
t.Fatalf("invalid index: have %d, want %d", d.Index, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -346,7 +346,18 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
gen(i, b)
|
||||
}
|
||||
|
||||
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals}
|
||||
var requests types.Requests
|
||||
if config.IsPrague(b.header.Number, b.header.Time) {
|
||||
for _, r := range b.receipts {
|
||||
d, err := ParseDepositLogs(r.Logs, config)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
|
||||
}
|
||||
requests = append(requests, d...)
|
||||
}
|
||||
}
|
||||
|
||||
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: requests}
|
||||
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -368,7 +379,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
defer triedb.Close()
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabase(triedb, nil))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -467,15 +478,14 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
|
|||
panic(fmt.Sprintf("trie write error: %v", err))
|
||||
}
|
||||
|
||||
// TODO uncomment when proof generation is merged
|
||||
// proofs = append(proofs, block.ExecutionWitness().VerkleProof)
|
||||
// keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
|
||||
proofs = append(proofs, block.ExecutionWitness().VerkleProof)
|
||||
keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
|
||||
|
||||
return block, b.receipts
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, trdb), nil)
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabase(trdb, nil))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ func TestGeneratePOSChain(t *testing.T) {
|
|||
})
|
||||
|
||||
// Import the chain. This runs all block validation rules.
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil)
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
if i, err := blockchain.InsertChain(genchain); err != nil {
|
||||
|
|
@ -238,7 +238,7 @@ func ExampleGenerateChain() {
|
|||
})
|
||||
|
||||
// Import the chain. This runs all block validation rules.
|
||||
blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Config: &proConf,
|
||||
}
|
||||
proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer proBc.Stop()
|
||||
|
||||
conDb := rawdb.NewMemoryDatabase()
|
||||
|
|
@ -62,7 +62,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Config: &conConf,
|
||||
}
|
||||
conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer conBc.Stop()
|
||||
|
||||
if _, err := proBc.InsertChain(prefix); err != nil {
|
||||
|
|
@ -74,7 +74,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
// Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks
|
||||
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
|
||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
||||
bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
|
||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64()))
|
||||
for j := 0; j < len(blocks)/2; j++ {
|
||||
|
|
@ -97,7 +97,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err)
|
||||
}
|
||||
// Create a no-fork block, and try to feed into the pro-fork chain
|
||||
bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
|
||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64()))
|
||||
for j := 0; j < len(blocks)/2; j++ {
|
||||
|
|
@ -121,7 +121,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
}
|
||||
}
|
||||
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
||||
bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer bc.Stop()
|
||||
|
||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64()))
|
||||
|
|
@ -139,7 +139,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err)
|
||||
}
|
||||
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
||||
bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer bc.Stop()
|
||||
|
||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64()))
|
||||
|
|
|
|||
|
|
@ -1,113 +0,0 @@
|
|||
// Copyright 2021 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"errors"
|
||||
"math/big"
|
||||
mrand "math/rand"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// ChainReader defines a small collection of methods needed to access the local
|
||||
// blockchain during header verification. It's implemented by both blockchain
|
||||
// and lightchain.
|
||||
type ChainReader interface {
|
||||
// Config retrieves the header chain's chain configuration.
|
||||
Config() *params.ChainConfig
|
||||
|
||||
// GetTd returns the total difficulty of a local block.
|
||||
GetTd(common.Hash, uint64) *big.Int
|
||||
}
|
||||
|
||||
// ForkChoice is the fork chooser based on the highest total difficulty of the
|
||||
// chain(the fork choice used in the eth1) and the external fork choice (the fork
|
||||
// choice used in the eth2). This main goal of this ForkChoice is not only for
|
||||
// offering fork choice during the eth1/2 merge phase, but also keep the compatibility
|
||||
// for all other proof-of-work networks.
|
||||
type ForkChoice struct {
|
||||
chain ChainReader
|
||||
rand *mrand.Rand
|
||||
|
||||
// preserve is a helper function used in td fork choice.
|
||||
// Miners will prefer to choose the local mined block if the
|
||||
// local td is equal to the extern one. It can be nil for light
|
||||
// client
|
||||
preserve func(header *types.Header) bool
|
||||
}
|
||||
|
||||
func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) bool) *ForkChoice {
|
||||
// Seed a fast but crypto originating random generator
|
||||
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
|
||||
if err != nil {
|
||||
log.Crit("Failed to initialize random seed", "err", err)
|
||||
}
|
||||
return &ForkChoice{
|
||||
chain: chainReader,
|
||||
rand: mrand.New(mrand.NewSource(seed.Int64())),
|
||||
preserve: preserve,
|
||||
}
|
||||
}
|
||||
|
||||
// ReorgNeeded returns whether the reorg should be applied
|
||||
// based on the given external header and local canonical chain.
|
||||
// In the td mode, the new head is chosen if the corresponding
|
||||
// total difficulty is higher. In the extern mode, the trusted
|
||||
// header is always selected as the head.
|
||||
func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (bool, error) {
|
||||
var (
|
||||
localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64())
|
||||
externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64())
|
||||
)
|
||||
if localTD == nil || externTd == nil {
|
||||
return false, errors.New("missing td")
|
||||
}
|
||||
// Accept the new header as the chain head if the transition
|
||||
// is already triggered. We assume all the headers after the
|
||||
// transition come from the trusted consensus layer.
|
||||
if ttd := f.chain.Config().TerminalTotalDifficulty; ttd != nil && ttd.Cmp(externTd) <= 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// If the total difficulty is higher than our known, add it to the canonical chain
|
||||
if diff := externTd.Cmp(localTD); diff > 0 {
|
||||
return true, nil
|
||||
} else if diff < 0 {
|
||||
return false, nil
|
||||
}
|
||||
// Local and external difficulty is identical.
|
||||
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
||||
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
||||
reorg := false
|
||||
externNum, localNum := extern.Number.Uint64(), current.Number.Uint64()
|
||||
if externNum < localNum {
|
||||
reorg = true
|
||||
} else if externNum == localNum {
|
||||
var currentPreserve, externPreserve bool
|
||||
if f.preserve != nil {
|
||||
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
|
||||
}
|
||||
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
|
||||
}
|
||||
return reorg, nil
|
||||
}
|
||||
|
|
@ -80,25 +80,6 @@ func TestCreation(t *testing.T) {
|
|||
{50000000, 2000000000, ID{Hash: checksumToBytes(0x9f3d2254), Next: 0}}, // Future Cancun block
|
||||
},
|
||||
},
|
||||
// Goerli test cases
|
||||
{
|
||||
params.GoerliChainConfig,
|
||||
core.DefaultGoerliGenesisBlock().ToBlock(),
|
||||
[]testcase{
|
||||
{0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
|
||||
{1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block
|
||||
{1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block
|
||||
{4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block
|
||||
{4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block
|
||||
{5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block
|
||||
{5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // First London block
|
||||
{6000000, 1678832735, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // Last London block
|
||||
{6000001, 1678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // First Shanghai block
|
||||
{6500002, 1705473119, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // Last Shanghai block
|
||||
{6500003, 1705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // First Cancun block
|
||||
{6500003, 2705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // Future Cancun block
|
||||
},
|
||||
},
|
||||
// Sepolia test cases
|
||||
{
|
||||
params.SepoliaChainConfig,
|
||||
|
|
|
|||
|
|
@ -127,8 +127,8 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (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.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config)
|
||||
statedb, err := state.New(types.EmptyRootHash, db, nil)
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb.NewDatabase(db, config), nil))
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
|
@ -145,13 +145,12 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
|
|||
return statedb.Commit(0, false)
|
||||
}
|
||||
|
||||
// flushAlloc 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 flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database, blockhash common.Hash) error {
|
||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
// flushAlloc is very similar with hash, but the main difference is all the
|
||||
// generated states will be persisted into the given database.
|
||||
func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) {
|
||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb, nil))
|
||||
if err != nil {
|
||||
return err
|
||||
return common.Hash{}, err
|
||||
}
|
||||
for addr, account := range *ga {
|
||||
if account.Balance != nil {
|
||||
|
|
@ -167,21 +166,15 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
|
|||
}
|
||||
root, err := statedb.Commit(0, false)
|
||||
if err != nil {
|
||||
return err
|
||||
return common.Hash{}, err
|
||||
}
|
||||
// Commit newly generated states into disk if it's not empty.
|
||||
if root != types.EmptyRootHash {
|
||||
if err := triedb.Commit(root, true); err != nil {
|
||||
return err
|
||||
return common.Hash{}, err
|
||||
}
|
||||
}
|
||||
// Marshal the genesis state specification and persist.
|
||||
blob, err := json.Marshal(ga)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rawdb.WriteGenesisStateSpec(db, blockhash, blob)
|
||||
return nil
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) {
|
||||
|
|
@ -203,8 +196,6 @@ func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.Gene
|
|||
switch blockhash {
|
||||
case params.MainnetGenesisHash:
|
||||
genesis = DefaultGenesisBlock()
|
||||
case params.GoerliGenesisHash:
|
||||
genesis = DefaultGoerliGenesisBlock()
|
||||
case params.SepoliaGenesisHash:
|
||||
genesis = DefaultSepoliaGenesisBlock()
|
||||
case params.HoleskyGenesisHash:
|
||||
|
|
@ -407,8 +398,6 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
|
|||
return params.HoleskyChainConfig
|
||||
case ghash == params.SepoliaGenesisHash:
|
||||
return params.SepoliaChainConfig
|
||||
case ghash == params.GoerliGenesisHash:
|
||||
return params.GoerliChainConfig
|
||||
default:
|
||||
return params.AllEthashProtocolChanges
|
||||
}
|
||||
|
|
@ -426,6 +415,11 @@ func (g *Genesis) ToBlock() *types.Block {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return g.toBlockWithRoot(root)
|
||||
}
|
||||
|
||||
// toBlockWithRoot constructs the genesis block with the given genesis state root.
|
||||
func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
|
||||
head := &types.Header{
|
||||
Number: new(big.Int).SetUint64(g.Number),
|
||||
Nonce: types.EncodeNonce(g.Nonce),
|
||||
|
|
@ -453,7 +447,10 @@ func (g *Genesis) ToBlock() *types.Block {
|
|||
head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee)
|
||||
}
|
||||
}
|
||||
var withdrawals []*types.Withdrawal
|
||||
var (
|
||||
withdrawals []*types.Withdrawal
|
||||
requests types.Requests
|
||||
)
|
||||
if conf := g.Config; conf != nil {
|
||||
num := big.NewInt(int64(g.Number))
|
||||
if conf.IsShanghai(num, g.Timestamp) {
|
||||
|
|
@ -475,15 +472,18 @@ func (g *Genesis) ToBlock() *types.Block {
|
|||
head.BlobGasUsed = new(uint64)
|
||||
}
|
||||
}
|
||||
if conf.IsPrague(num, g.Timestamp) {
|
||||
head.RequestsHash = &types.EmptyRequestsHash
|
||||
requests = make(types.Requests, 0)
|
||||
}
|
||||
}
|
||||
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil))
|
||||
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals, Requests: requests}, nil, trie.NewStackTrie(nil))
|
||||
}
|
||||
|
||||
// Commit writes the block and state of a genesis specification to the database.
|
||||
// The block is committed as the canonical head block.
|
||||
func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) {
|
||||
block := g.ToBlock()
|
||||
if block.Number().Sign() != 0 {
|
||||
if g.Number != 0 {
|
||||
return nil, errors.New("can't commit genesis block with number > 0")
|
||||
}
|
||||
config := g.Config
|
||||
|
|
@ -493,15 +493,22 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
|
|||
if err := config.CheckConfigForkOrder(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength {
|
||||
if config.Clique != nil && len(g.ExtraData) < 32+crypto.SignatureLength {
|
||||
return nil, errors.New("can't start clique chain without signers")
|
||||
}
|
||||
// All the checks has passed, flushAlloc the states derived from the genesis
|
||||
// specification as well as the specification itself into the provided
|
||||
// database.
|
||||
if err := flushAlloc(&g.Alloc, db, triedb, block.Hash()); err != nil {
|
||||
// flush the data to disk and compute the state root
|
||||
root, err := flushAlloc(&g.Alloc, triedb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block := g.toBlockWithRoot(root)
|
||||
|
||||
// Marshal the genesis state specification and persist.
|
||||
blob, err := json.Marshal(g.Alloc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawdb.WriteGenesisStateSpec(db, block.Hash(), blob)
|
||||
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
|
||||
rawdb.WriteBlock(db, block)
|
||||
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
|
||||
|
|
@ -535,18 +542,6 @@ func DefaultGenesisBlock() *Genesis {
|
|||
}
|
||||
}
|
||||
|
||||
// DefaultGoerliGenesisBlock returns the Görli network genesis block.
|
||||
func DefaultGoerliGenesisBlock() *Genesis {
|
||||
return &Genesis{
|
||||
Config: params.GoerliChainConfig,
|
||||
Timestamp: 1548854791,
|
||||
ExtraData: hexutil.MustDecode("0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
|
||||
GasLimit: 10485760,
|
||||
Difficulty: big.NewInt(1),
|
||||
Alloc: decodePrealloc(goerliAllocData),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultSepoliaGenesisBlock returns the Sepolia network genesis block.
|
||||
func DefaultSepoliaGenesisBlock() *Genesis {
|
||||
return &Genesis{
|
||||
|
|
@ -595,6 +590,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
|||
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
||||
// Pre-deploy EIP-4788 system contract
|
||||
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
||||
// Pre-deploy EIP-2935 history contract.
|
||||
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
|
||||
},
|
||||
}
|
||||
if faucet != nil {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -35,15 +35,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/triedb/pathdb"
|
||||
)
|
||||
|
||||
func TestInvalidCliqueConfig(t *testing.T) {
|
||||
block := DefaultGoerliGenesisBlock()
|
||||
block.ExtraData = []byte{}
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
if _, err := block.Commit(db, triedb.NewDatabase(db, nil)); err == nil {
|
||||
t.Fatal("Expected error on invalid clique config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupGenesis(t *testing.T) {
|
||||
testSetupGenesis(t, rawdb.HashScheme)
|
||||
testSetupGenesis(t, rawdb.PathScheme)
|
||||
|
|
@ -105,15 +96,15 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
|||
wantConfig: customg.Config,
|
||||
},
|
||||
{
|
||||
name: "custom block in DB, genesis == goerli",
|
||||
name: "custom block in DB, genesis == sepolia",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||
customg.Commit(db, tdb)
|
||||
return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock())
|
||||
return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock())
|
||||
},
|
||||
wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash},
|
||||
wantHash: params.GoerliGenesisHash,
|
||||
wantConfig: params.GoerliChainConfig,
|
||||
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
|
||||
wantHash: params.SepoliaGenesisHash,
|
||||
wantConfig: params.SepoliaChainConfig,
|
||||
},
|
||||
{
|
||||
name: "compatible config in DB",
|
||||
|
|
@ -133,7 +124,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
|||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||
oldcustomg.Commit(db, tdb)
|
||||
|
||||
bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
||||
bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil)
|
||||
defer bc.Stop()
|
||||
|
||||
_, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil)
|
||||
|
|
@ -184,7 +175,6 @@ func TestGenesisHashes(t *testing.T) {
|
|||
want common.Hash
|
||||
}{
|
||||
{DefaultGenesisBlock(), params.MainnetGenesisHash},
|
||||
{DefaultGoerliGenesisBlock(), params.GoerliGenesisHash},
|
||||
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
|
||||
} {
|
||||
// Test via MustCommit
|
||||
|
|
@ -304,14 +294,14 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
expected := common.FromHex("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b")
|
||||
expected := common.FromHex("4a83dc39eb688dbcfaf581d60e82de18f875e38786ebce5833342011d6fef37b")
|
||||
got := genesis.ToBlock().Root().Bytes()
|
||||
if !bytes.Equal(got, expected) {
|
||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
||||
}
|
||||
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults})
|
||||
triedb := triedb.NewDatabase(db, triedb.VerkleDefaults)
|
||||
block := genesis.MustCommit(db, triedb)
|
||||
if !bytes.Equal(block.Root().Bytes(), expected) {
|
||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, block.Root())
|
||||
|
|
@ -321,8 +311,8 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
|||
if !triedb.IsVerkle() {
|
||||
t.Fatalf("expected trie to be verkle")
|
||||
}
|
||||
|
||||
if !rawdb.HasAccountTrieNode(db, nil) {
|
||||
vdb := rawdb.NewTable(db, string(rawdb.VerklePrefix))
|
||||
if !rawdb.HasAccountTrieNode(vdb, nil) {
|
||||
t.Fatal("could not find node")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ func (hc *HeaderChain) WriteHeaders(headers []*types.Header) (int, error) {
|
|||
// without the real blocks. Hence, writing headers directly should only be done
|
||||
// in two scenarios: pure-header mode of operation (light clients), or properly
|
||||
// separated header/block phases (non-archive clients).
|
||||
func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *ForkChoice) (*headerWriteResult, error) {
|
||||
func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header) (*headerWriteResult, error) {
|
||||
inserted, err := hc.WriteHeaders(headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -270,15 +270,6 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F
|
|||
lastHeader: lastHeader,
|
||||
}
|
||||
)
|
||||
// Ask the fork choicer if the reorg is necessary
|
||||
if reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader); err != nil {
|
||||
return nil, err
|
||||
} else if !reorg {
|
||||
if inserted != 0 {
|
||||
result.status = SideStatTy
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
// Special case, all the inserted headers are already on the canonical
|
||||
// header chain, skip the reorg operation.
|
||||
if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() {
|
||||
|
|
@ -336,11 +327,11 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header) (int, error) {
|
|||
//
|
||||
// The returned 'write status' says if the inserted headers are part of the canonical chain
|
||||
// or a side chain.
|
||||
func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, start time.Time, forker *ForkChoice) (WriteStatus, error) {
|
||||
func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, start time.Time) (WriteStatus, error) {
|
||||
if hc.procInterrupt() {
|
||||
return 0, errors.New("aborted")
|
||||
}
|
||||
res, err := hc.writeHeadersAndSetHead(chain, forker)
|
||||
res, err := hc.writeHeadersAndSetHead(chain)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ func verifyUnbrokenCanonchain(hc *HeaderChain) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func testInsert(t *testing.T, hc *HeaderChain, chain []*types.Header, wantStatus WriteStatus, wantErr error, forker *ForkChoice) {
|
||||
func testInsert(t *testing.T, hc *HeaderChain, chain []*types.Header, wantStatus WriteStatus, wantErr error) {
|
||||
t.Helper()
|
||||
|
||||
status, err := hc.InsertHeaderChain(chain, time.Now(), forker)
|
||||
status, err := hc.InsertHeaderChain(chain, time.Now())
|
||||
if status != wantStatus {
|
||||
t.Errorf("wrong write status from InsertHeaderChain: got %v, want %v", status, wantStatus)
|
||||
}
|
||||
|
|
@ -83,34 +83,33 @@ func TestHeaderInsertion(t *testing.T) {
|
|||
// chain B: G->A1->B1...B128
|
||||
chainB := makeHeaderChain(gspec.Config, chainA[0], 128, ethash.NewFaker(), genDb, 10)
|
||||
|
||||
forker := NewForkChoice(hc, nil)
|
||||
// Inserting 64 headers on an empty chain, expecting
|
||||
// 1 callbacks, 1 canon-status, 0 sidestatus,
|
||||
testInsert(t, hc, chainA[:64], CanonStatTy, nil, forker)
|
||||
testInsert(t, hc, chainA[:64], CanonStatTy, nil)
|
||||
|
||||
// Inserting 64 identical headers, expecting
|
||||
// 0 callbacks, 0 canon-status, 0 sidestatus,
|
||||
testInsert(t, hc, chainA[:64], NonStatTy, nil, forker)
|
||||
testInsert(t, hc, chainA[:64], NonStatTy, nil)
|
||||
|
||||
// Inserting the same some old, some new headers
|
||||
// 1 callbacks, 1 canon, 0 side
|
||||
testInsert(t, hc, chainA[32:96], CanonStatTy, nil, forker)
|
||||
testInsert(t, hc, chainA[32:96], CanonStatTy, nil)
|
||||
|
||||
// Inserting side blocks, but not overtaking the canon chain
|
||||
testInsert(t, hc, chainB[0:32], SideStatTy, nil, forker)
|
||||
// Inserting headers from chain B, overtaking the canon chain blindly
|
||||
testInsert(t, hc, chainB[0:32], CanonStatTy, nil)
|
||||
|
||||
// Inserting more side blocks, but we don't have the parent
|
||||
testInsert(t, hc, chainB[34:36], NonStatTy, consensus.ErrUnknownAncestor, forker)
|
||||
// Inserting more headers on chain B, but we don't have the parent
|
||||
testInsert(t, hc, chainB[34:36], NonStatTy, consensus.ErrUnknownAncestor)
|
||||
|
||||
// Inserting more sideblocks, overtaking the canon chain
|
||||
testInsert(t, hc, chainB[32:97], CanonStatTy, nil, forker)
|
||||
// Inserting more headers on chain B, extend the canon chain
|
||||
testInsert(t, hc, chainB[32:97], CanonStatTy, nil)
|
||||
|
||||
// Inserting more A-headers, taking back the canonicality
|
||||
testInsert(t, hc, chainA[90:100], CanonStatTy, nil, forker)
|
||||
// Inserting more headers on chain A, taking back the canonicality
|
||||
testInsert(t, hc, chainA[90:100], CanonStatTy, nil)
|
||||
|
||||
// And B becomes canon again
|
||||
testInsert(t, hc, chainB[97:107], CanonStatTy, nil, forker)
|
||||
testInsert(t, hc, chainB[97:107], CanonStatTy, nil)
|
||||
|
||||
// And B becomes even longer
|
||||
testInsert(t, hc, chainB[107:128], CanonStatTy, nil, forker)
|
||||
testInsert(t, hc, chainB[107:128], CanonStatTy, nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has
|
|||
|
||||
// ReadStateScheme reads the state scheme of persistent state, or none
|
||||
// if the state is not present in database.
|
||||
func ReadStateScheme(db ethdb.Reader) string {
|
||||
func ReadStateScheme(db ethdb.Database) string {
|
||||
// Check if state in path-based scheme is present.
|
||||
if HasAccountTrieNode(db, nil) {
|
||||
return PathScheme
|
||||
|
|
@ -255,6 +255,16 @@ func ReadStateScheme(db ethdb.Reader) string {
|
|||
if id := ReadPersistentStateID(db); id != 0 {
|
||||
return PathScheme
|
||||
}
|
||||
// Check if verkle state in path-based scheme is present.
|
||||
vdb := NewTable(db, string(VerklePrefix))
|
||||
if HasAccountTrieNode(vdb, nil) {
|
||||
return PathScheme
|
||||
}
|
||||
// The root node of verkle might be deleted during the initial snap sync,
|
||||
// check the persistent state id then.
|
||||
if id := ReadPersistentStateID(vdb); id != 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.
|
||||
|
|
@ -292,6 +302,10 @@ func ParseStateScheme(provided string, disk ethdb.Database) (string, error) {
|
|||
log.Info("State scheme set to already existing", "scheme", stored)
|
||||
return stored, nil // reuse scheme of persistent scheme
|
||||
}
|
||||
// If state scheme is specified, ensure it's valid.
|
||||
if provided != HashScheme && provided != PathScheme {
|
||||
return "", fmt.Errorf("invalid state scheme %s", provided)
|
||||
}
|
||||
// If state scheme is specified, ensure it's compatible with
|
||||
// persistent state.
|
||||
if stored == "" || provided == stored {
|
||||
|
|
|
|||
|
|
@ -72,12 +72,13 @@ var stateFreezerNoSnappy = map[string]bool{
|
|||
|
||||
// The list of identifiers of ancient stores.
|
||||
var (
|
||||
ChainFreezerName = "chain" // the folder name of chain segment ancient store.
|
||||
StateFreezerName = "state" // the folder name of reverse diff ancient store.
|
||||
ChainFreezerName = "chain" // the folder name of chain segment ancient store.
|
||||
MerkleStateFreezerName = "state" // the folder name of state history ancient store.
|
||||
VerkleStateFreezerName = "state_verkle" // the folder name of state history ancient store.
|
||||
)
|
||||
|
||||
// freezers the collections of all builtin freezers.
|
||||
var freezers = []string{ChainFreezerName, StateFreezerName}
|
||||
var freezers = []string{ChainFreezerName, MerkleStateFreezerName, VerkleStateFreezerName}
|
||||
|
||||
// NewStateFreezer initializes the ancient store for state history.
|
||||
//
|
||||
|
|
@ -85,9 +86,15 @@ var freezers = []string{ChainFreezerName, StateFreezerName}
|
|||
// state freezer (e.g. dev mode).
|
||||
// - if non-empty directory is given, initializes the regular file-based
|
||||
// state freezer.
|
||||
func NewStateFreezer(ancientDir string, readOnly bool) (ethdb.ResettableAncientStore, error) {
|
||||
func NewStateFreezer(ancientDir string, verkle bool, readOnly bool) (ethdb.ResettableAncientStore, error) {
|
||||
if ancientDir == "" {
|
||||
return NewMemoryFreezer(readOnly, stateFreezerNoSnappy), nil
|
||||
}
|
||||
return newResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
|
||||
var name string
|
||||
if verkle {
|
||||
name = filepath.Join(ancientDir, VerkleStateFreezerName)
|
||||
} else {
|
||||
name = filepath.Join(ancientDir, MerkleStateFreezerName)
|
||||
}
|
||||
return newResettableFreezer(name, "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,12 +88,12 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
|
|||
}
|
||||
infos = append(infos, info)
|
||||
|
||||
case StateFreezerName:
|
||||
case MerkleStateFreezerName, VerkleStateFreezerName:
|
||||
datadir, err := db.AncientDatadir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := NewStateFreezer(datadir, true)
|
||||
f, err := NewStateFreezer(datadir, freezer == VerkleStateFreezerName, true)
|
||||
if err != nil {
|
||||
continue // might be possible the state freezer is not existent
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
|
|||
switch freezerName {
|
||||
case ChainFreezerName:
|
||||
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
|
||||
case StateFreezerName:
|
||||
case MerkleStateFreezerName, VerkleStateFreezerName:
|
||||
path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy
|
||||
default:
|
||||
return fmt.Errorf("unknown freezer, supported ones: %v", freezers)
|
||||
|
|
|
|||
|
|
@ -149,12 +149,6 @@ func (db *nofreezedb) ReadAncients(fn func(reader ethdb.AncientReaderOp) error)
|
|||
return fn(db)
|
||||
}
|
||||
|
||||
// MigrateTable processes the entries in a given table in sequence
|
||||
// converting them to a new format if they're of an old format.
|
||||
func (db *nofreezedb) MigrateTable(kind string, convert convertLegacyFn) error {
|
||||
return errNotSupported
|
||||
}
|
||||
|
||||
// AncientDatadir returns an error as we don't have a backing chain freezer.
|
||||
func (db *nofreezedb) AncientDatadir() (string, error) {
|
||||
return "", errNotSupported
|
||||
|
|
@ -481,6 +475,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
|||
beaconHeaders stat
|
||||
cliqueSnaps stat
|
||||
|
||||
// Verkle statistics
|
||||
verkleTries stat
|
||||
verkleStateLookups stat
|
||||
|
||||
// Les statistic
|
||||
chtTrieNodes stat
|
||||
bloomTrieNodes stat
|
||||
|
|
@ -550,6 +548,24 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
|||
bytes.HasPrefix(key, BloomTrieIndexPrefix) ||
|
||||
bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub
|
||||
bloomTrieNodes.Add(size)
|
||||
|
||||
// Verkle trie data is detected, determine the sub-category
|
||||
case bytes.HasPrefix(key, VerklePrefix):
|
||||
remain := key[len(VerklePrefix):]
|
||||
switch {
|
||||
case IsAccountTrieNode(remain):
|
||||
verkleTries.Add(size)
|
||||
case bytes.HasPrefix(remain, stateIDPrefix) && len(remain) == len(stateIDPrefix)+common.HashLength:
|
||||
verkleStateLookups.Add(size)
|
||||
case bytes.Equal(remain, persistentStateIDKey):
|
||||
metadata.Add(size)
|
||||
case bytes.Equal(remain, trieJournalKey):
|
||||
metadata.Add(size)
|
||||
case bytes.Equal(remain, snapSyncStatusFlagKey):
|
||||
metadata.Add(size)
|
||||
default:
|
||||
unaccounted.Add(size)
|
||||
}
|
||||
default:
|
||||
var accounted bool
|
||||
for _, meta := range [][]byte{
|
||||
|
|
@ -590,6 +606,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
|||
{"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", "Verkle trie nodes", verkleTries.Size(), verkleTries.Count()},
|
||||
{"Key-Value store", "Verkle trie state lookups", verkleStateLookups.Size(), verkleStateLookups.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()},
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@ import (
|
|||
"path/filepath"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
|
|
@ -54,13 +52,11 @@ var (
|
|||
// freezerTableSize defines the maximum size of freezer data files.
|
||||
const freezerTableSize = 2 * 1000 * 1000 * 1000
|
||||
|
||||
// Freezer is a memory mapped append-only database to store immutable ordered
|
||||
// data into flat files:
|
||||
// Freezer is an append-only database to store immutable ordered data into
|
||||
// flat files:
|
||||
//
|
||||
// - The append-only nature ensures that disk writes are minimized.
|
||||
// - The memory mapping ensures we can max out system memory for caching without
|
||||
// reserving it for go-ethereum. This would also reduce the memory requirements
|
||||
// of Geth, and thus also GC overhead.
|
||||
// - The append-only nature ensures that disk writes are minimized.
|
||||
// - The in-order data ensures that disk reads are always optimized.
|
||||
type Freezer struct {
|
||||
frozen atomic.Uint64 // Number of items already frozen
|
||||
tail atomic.Uint64 // Number of the first stored item in the freezer
|
||||
|
|
@ -154,7 +150,7 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui
|
|||
return freezer, nil
|
||||
}
|
||||
|
||||
// Close terminates the chain freezer, unmapping all the data files.
|
||||
// Close terminates the chain freezer, closing all the data files.
|
||||
func (f *Freezer) Close() error {
|
||||
f.writeLock.Lock()
|
||||
defer f.writeLock.Unlock()
|
||||
|
|
@ -389,115 +385,3 @@ func (f *Freezer) repair() error {
|
|||
f.tail.Store(tail)
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertLegacyFn takes a raw freezer entry in an older format and
|
||||
// returns it in the new format.
|
||||
type convertLegacyFn = func([]byte) ([]byte, error)
|
||||
|
||||
// MigrateTable processes the entries in a given table in sequence
|
||||
// converting them to a new format if they're of an old format.
|
||||
func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error {
|
||||
if f.readonly {
|
||||
return errReadOnly
|
||||
}
|
||||
f.writeLock.Lock()
|
||||
defer f.writeLock.Unlock()
|
||||
|
||||
table, ok := f.tables[kind]
|
||||
if !ok {
|
||||
return errUnknownTable
|
||||
}
|
||||
// forEach iterates every entry in the table serially and in order, calling `fn`
|
||||
// with the item as argument. If `fn` returns an error the iteration stops
|
||||
// and that error will be returned.
|
||||
forEach := func(t *freezerTable, offset uint64, fn func(uint64, []byte) error) error {
|
||||
var (
|
||||
items = t.items.Load()
|
||||
batchSize = uint64(1024)
|
||||
maxBytes = uint64(1024 * 1024)
|
||||
)
|
||||
for i := offset; i < items; {
|
||||
if i+batchSize > items {
|
||||
batchSize = items - i
|
||||
}
|
||||
data, err := t.RetrieveItems(i, batchSize, maxBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for j, item := range data {
|
||||
if err := fn(i+uint64(j), item); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
i += uint64(len(data))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// TODO(s1na): This is a sanity-check since as of now no process does tail-deletion. But the migration
|
||||
// process assumes no deletion at tail and needs to be modified to account for that.
|
||||
if table.itemOffset.Load() > 0 || table.itemHidden.Load() > 0 {
|
||||
return errors.New("migration not supported for tail-deleted freezers")
|
||||
}
|
||||
ancientsPath := filepath.Dir(table.index.Name())
|
||||
// Set up new dir for the migrated table, the content of which
|
||||
// we'll at the end move over to the ancients dir.
|
||||
migrationPath := filepath.Join(ancientsPath, "migration")
|
||||
newTable, err := newFreezerTable(migrationPath, kind, table.noCompression, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
batch = newTable.newBatch()
|
||||
out []byte
|
||||
start = time.Now()
|
||||
logged = time.Now()
|
||||
offset = newTable.items.Load()
|
||||
)
|
||||
if offset > 0 {
|
||||
log.Info("found previous migration attempt", "migrated", offset)
|
||||
}
|
||||
// Iterate through entries and transform them
|
||||
if err := forEach(table, offset, func(i uint64, blob []byte) error {
|
||||
if i%10000 == 0 && time.Since(logged) > 16*time.Second {
|
||||
log.Info("Processing legacy elements", "count", i, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
logged = time.Now()
|
||||
}
|
||||
out, err = convert(blob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := batch.AppendRaw(i, out); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := batch.commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Replacing old table files with migrated ones", "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
// Release and delete old table files. Note this won't
|
||||
// delete the index file.
|
||||
table.releaseFilesAfter(0, true)
|
||||
|
||||
if err := newTable.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
files, err := os.ReadDir(migrationPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Move migrated files to ancients dir.
|
||||
for _, f := range files {
|
||||
// This will replace the old index file as a side-effect.
|
||||
if err := os.Rename(filepath.Join(migrationPath, f.Name()), filepath.Join(ancientsPath, f.Name())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Delete by now empty dir.
|
||||
if err := os.Remove(migrationPath); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,13 +394,6 @@ func (f *MemoryFreezer) Sync() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// MigrateTable processes and migrates entries of a given table to a new format.
|
||||
// The second argument is a function that takes a raw entry and returns it
|
||||
// in the newest format.
|
||||
func (f *MemoryFreezer) MigrateTable(string, func([]byte) ([]byte, error)) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
// Close releases all the sources held by the memory freezer. It will panic if
|
||||
// any following invocation is made to a closed freezer.
|
||||
func (f *MemoryFreezer) Close() error {
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ import (
|
|||
)
|
||||
|
||||
func TestReadWriteFreezerTableMeta(t *testing.T) {
|
||||
f, err := os.CreateTemp(os.TempDir(), "*")
|
||||
f, err := os.CreateTemp(t.TempDir(), "*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create file %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
err = writeMetadata(f, newMetadata(100))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write metadata %v", err)
|
||||
|
|
@ -43,10 +44,11 @@ func TestReadWriteFreezerTableMeta(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInitializeFreezerTableMeta(t *testing.T) {
|
||||
f, err := os.CreateTemp(os.TempDir(), "*")
|
||||
f, err := os.CreateTemp(t.TempDir(), "*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create file %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
meta, err := loadMetadata(f, uint64(100))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read metadata %v", err)
|
||||
|
|
|
|||
|
|
@ -202,15 +202,6 @@ func (f *resettableFreezer) Sync() error {
|
|||
return f.freezer.Sync()
|
||||
}
|
||||
|
||||
// MigrateTable processes the entries in a given table in sequence
|
||||
// converting them to a new format if they're of an old format.
|
||||
func (f *resettableFreezer) MigrateTable(kind string, convert convertLegacyFn) error {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
return f.freezer.MigrateTable(kind, convert)
|
||||
}
|
||||
|
||||
// cleanup removes the directory located in the specified path
|
||||
// has the name with deletion marker suffix.
|
||||
func cleanup(path string) error {
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
|
|
@ -379,87 +377,6 @@ func checkAncientCount(t *testing.T, f *Freezer, kind string, n uint64) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRenameWindows(t *testing.T) {
|
||||
var (
|
||||
fname = "file.bin"
|
||||
fname2 = "file2.bin"
|
||||
data = []byte{1, 2, 3, 4}
|
||||
data2 = []byte{2, 3, 4, 5}
|
||||
data3 = []byte{3, 5, 6, 7}
|
||||
dataLen = 4
|
||||
)
|
||||
|
||||
// Create 2 temp dirs
|
||||
dir1 := t.TempDir()
|
||||
dir2 := t.TempDir()
|
||||
|
||||
// Create file in dir1 and fill with data
|
||||
f, err := os.Create(filepath.Join(dir1, fname))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f2, err := os.Create(filepath.Join(dir1, fname2))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f3, err := os.Create(filepath.Join(dir2, fname2))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := f.Write(data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := f2.Write(data2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := f3.Write(data3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := f2.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := f3.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Rename(f.Name(), filepath.Join(dir2, fname)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Rename(f2.Name(), filepath.Join(dir2, fname2)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check file contents
|
||||
f, err = os.Open(filepath.Join(dir2, fname))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
buf := make([]byte, dataLen)
|
||||
if _, err := f.Read(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(buf, data) {
|
||||
t.Errorf("unexpected file contents. Got %v\n", buf)
|
||||
}
|
||||
|
||||
f, err = os.Open(filepath.Join(dir2, fname2))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
if _, err := f.Read(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(buf, data2) {
|
||||
t.Errorf("unexpected file contents. Got %v\n", buf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFreezerCloseSync(t *testing.T) {
|
||||
t.Parallel()
|
||||
f, _ := newFreezerForTesting(t, map[string]bool{"a": true, "b": true})
|
||||
|
|
|
|||
|
|
@ -117,6 +117,13 @@ var (
|
|||
TrieNodeStoragePrefix = []byte("O") // TrieNodeStoragePrefix + accountHash + hexPath -> trie node
|
||||
stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id
|
||||
|
||||
// VerklePrefix is the database prefix for Verkle trie data, which includes:
|
||||
// (a) Trie nodes
|
||||
// (b) In-memory trie node journal
|
||||
// (c) Persistent state ID
|
||||
// (d) State ID lookups, etc.
|
||||
VerklePrefix = []byte("v")
|
||||
|
||||
PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage
|
||||
configPrefix = []byte("ethereum-config-") // config prefix for the db
|
||||
genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db
|
||||
|
|
|
|||
|
|
@ -113,12 +113,6 @@ func (t *table) Sync() error {
|
|||
return t.db.Sync()
|
||||
}
|
||||
|
||||
// MigrateTable processes the entries in a given table in sequence
|
||||
// converting them to a new format if they're of an old format.
|
||||
func (t *table) MigrateTable(kind string, convert convertLegacyFn) error {
|
||||
return t.db.MigrateTable(kind, convert)
|
||||
}
|
||||
|
||||
// AncientDatadir returns the ancient datadir of the underlying database.
|
||||
func (t *table) AncientDatadir() (string, error) {
|
||||
return t.db.AncientDatadir()
|
||||
|
|
@ -200,13 +194,6 @@ func (t *table) NewBatchWithSize(size int) ethdb.Batch {
|
|||
return &tableBatch{t.db.NewBatchWithSize(size), t.prefix}
|
||||
}
|
||||
|
||||
// NewSnapshot creates a database snapshot based on the current state.
|
||||
// The created snapshot will not be affected by all following mutations
|
||||
// happened on the database.
|
||||
func (t *table) NewSnapshot() (ethdb.Snapshot, error) {
|
||||
return t.db.NewSnapshot()
|
||||
}
|
||||
|
||||
// tableBatch is a wrapper around a database batch that prefixes each key access
|
||||
// with a pre-configured string.
|
||||
type tableBatch struct {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import (
|
|||
|
||||
// mode specifies how a tree location has been accessed
|
||||
// for the byte value:
|
||||
// * the first bit is set if the branch has been edited
|
||||
// * the second bit is set if the branch has been read
|
||||
// * the first bit is set if the branch has been read
|
||||
// * the second bit is set if the branch has been edited
|
||||
type mode byte
|
||||
|
||||
const (
|
||||
|
|
@ -94,11 +94,8 @@ func (ae *AccessEvents) Copy() *AccessEvents {
|
|||
// member fields of an account.
|
||||
func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite)
|
||||
return gas
|
||||
}
|
||||
|
||||
|
|
@ -107,8 +104,7 @@ func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
|||
// call to that account.
|
||||
func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.BasicDataLeafKey, false)
|
||||
return gas
|
||||
}
|
||||
|
||||
|
|
@ -116,41 +112,43 @@ func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
|||
// cold balance member fields of the caller and the callee accounts.
|
||||
func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
return gas
|
||||
}
|
||||
|
||||
// ContractCreateCPreheck charges access costs before
|
||||
// a contract creation is initiated. It is just reads, because the
|
||||
// address collision is done before the transfer, and so no write
|
||||
// are guaranteed to happen at this point.
|
||||
func (ae *AccessEvents) ContractCreatePreCheckGas(addr common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||
return gas
|
||||
}
|
||||
|
||||
// ContractCreateInitGas returns the access gas costs for the initialization of
|
||||
// a contract creation.
|
||||
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 {
|
||||
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true)
|
||||
if createSendsValue {
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
}
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, true)
|
||||
return gas
|
||||
}
|
||||
|
||||
// AddTxOrigin adds the member fields of the sender account to the access event list,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) {
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey, true)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||
}
|
||||
|
||||
// AddTxDestination adds the member fields of the sender account to the access event list,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) {
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, sendsValue)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, sendsValue)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||
}
|
||||
|
||||
// SlotGas returns the amount of gas to be charged for a cold storage access.
|
||||
|
|
@ -275,39 +273,12 @@ func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC,
|
|||
return statelessGasCharged
|
||||
}
|
||||
|
||||
// VersionGas adds the account's version to the accessed data, and returns the
|
||||
// BasicDataGas adds the account's basic data to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an
|
||||
// access in read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// BalanceGas adds the account's balance to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) BalanceGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// NonceGas adds the account's nonce to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) NonceGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// CodeSizeGas adds the account's code size to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
||||
func (ae *AccessEvents) BasicDataGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// CodeHashGas adds the account's code hash to the accessed data, and returns the
|
||||
|
|
@ -316,5 +287,5 @@ func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
|
|||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,55 +40,43 @@ func TestAccountHeaderGas(t *testing.T) {
|
|||
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||
|
||||
// Check cold read cost
|
||||
gas := ae.VersionGas(testAddr, false)
|
||||
gas := ae.BasicDataGas(testAddr, false)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.VersionGas(testAddr, false)
|
||||
gas = ae.BasicDataGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check cold read costs in the same group no longer incur the branch read cost
|
||||
gas = ae.BalanceGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.NonceGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.CodeSizeGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.CodeHashGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
|
||||
// Check cold write cost
|
||||
gas = ae.VersionGas(testAddr, true)
|
||||
gas = ae.BasicDataGas(testAddr, true)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm write cost
|
||||
gas = ae.VersionGas(testAddr, true)
|
||||
gas = ae.BasicDataGas(testAddr, true)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check a write without a read charges both read and write costs
|
||||
gas = ae.BalanceGas(testAddr2, true)
|
||||
gas = ae.BasicDataGas(testAddr2, true)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check that a write followed by a read charges nothing
|
||||
gas = ae.BalanceGas(testAddr2, false)
|
||||
gas = ae.BasicDataGas(testAddr2, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
|
@ -112,13 +100,13 @@ func TestContractCreateInitGas(t *testing.T) {
|
|||
}
|
||||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.ContractCreateInitGas(testAddr, false)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*2; gas != want {
|
||||
gas := ae.ContractCreateInitGas(testAddr)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + 2*params.WitnessChunkWriteCost + 2*params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.ContractCreateInitGas(testAddr, false)
|
||||
gas = ae.ContractCreateInitGas(testAddr)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
|
@ -131,17 +119,17 @@ func TestMessageCallGas(t *testing.T) {
|
|||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.MessageCallGas(testAddr)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost*2; gas != want {
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check that reading the version and code size of the same account does not incur the branch read cost
|
||||
gas = ae.VersionGas(testAddr, false)
|
||||
// Check that reading the basic data and code hash of the same account does not incur the branch read cost
|
||||
gas = ae.BasicDataGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
gas = ae.CodeSizeGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
gas = ae.CodeHashGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
|
|
@ -45,29 +46,29 @@ const (
|
|||
|
||||
// Database wraps access to tries and contract code.
|
||||
type Database interface {
|
||||
// Reader returns a state reader associated with the specified state root.
|
||||
Reader(root common.Hash) (Reader, error)
|
||||
|
||||
// OpenTrie opens the main account trie.
|
||||
OpenTrie(root common.Hash) (Trie, error)
|
||||
|
||||
// OpenStorageTrie opens the storage trie of an account.
|
||||
OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error)
|
||||
|
||||
// CopyTrie returns an independent copy of the given trie.
|
||||
CopyTrie(Trie) Trie
|
||||
|
||||
// ContractCode retrieves a particular contract's code.
|
||||
ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error)
|
||||
|
||||
// ContractCodeSize retrieves a particular contracts code's size.
|
||||
ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error)
|
||||
|
||||
// DiskDB returns the underlying key-value disk database.
|
||||
DiskDB() ethdb.KeyValueStore
|
||||
|
||||
// PointCache returns the cache holding points used in verkle tree key computation
|
||||
PointCache() *utils.PointCache
|
||||
|
||||
// TrieDB returns the underlying trie database for managing trie nodes.
|
||||
TrieDB() *triedb.Database
|
||||
|
||||
// Snapshot returns the underlying state snapshot.
|
||||
Snapshot() *snapshot.Tree
|
||||
}
|
||||
|
||||
// Trie is a Ethereum Merkle Patricia trie.
|
||||
|
|
@ -94,7 +95,7 @@ type Trie interface {
|
|||
// UpdateAccount abstracts an account write to the trie. It encodes the
|
||||
// provided account object with associated algorithm and then updates it
|
||||
// in the trie with provided address.
|
||||
UpdateAccount(address common.Address, account *types.StateAccount) error
|
||||
UpdateAccount(address common.Address, account *types.StateAccount, codeLen int) error
|
||||
|
||||
// UpdateStorage associates key with value in the trie. If value has length zero,
|
||||
// any existing value is deleted from the trie. The value bytes must not be modified
|
||||
|
|
@ -147,47 +148,62 @@ type Trie interface {
|
|||
IsVerkle() bool
|
||||
}
|
||||
|
||||
// NewDatabase creates a backing store for state. The returned database is safe for
|
||||
// concurrent use, but does not retain any recent trie nodes in memory. To keep some
|
||||
// historical state in memory, use the NewDatabaseWithConfig constructor.
|
||||
func NewDatabase(db ethdb.Database) Database {
|
||||
return NewDatabaseWithConfig(db, nil)
|
||||
}
|
||||
|
||||
// NewDatabaseWithConfig creates a backing store for state. The returned database
|
||||
// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a
|
||||
// large memory cache.
|
||||
func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database {
|
||||
return &cachingDB{
|
||||
disk: db,
|
||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
||||
triedb: triedb.NewDatabase(db, config),
|
||||
pointCache: utils.NewPointCache(pointCacheSize),
|
||||
}
|
||||
}
|
||||
|
||||
// NewDatabaseWithNodeDB creates a state database with an already initialized node database.
|
||||
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database {
|
||||
return &cachingDB{
|
||||
disk: db,
|
||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
||||
triedb: triedb,
|
||||
pointCache: utils.NewPointCache(pointCacheSize),
|
||||
}
|
||||
}
|
||||
|
||||
type cachingDB struct {
|
||||
// CachingDB is an implementation of Database interface. It leverages both trie and
|
||||
// state snapshot to provide functionalities for state access. It's meant to be a
|
||||
// long-live object and has a few caches inside for sharing between blocks.
|
||||
type CachingDB struct {
|
||||
disk ethdb.KeyValueStore
|
||||
codeSizeCache *lru.Cache[common.Hash, int]
|
||||
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
||||
triedb *triedb.Database
|
||||
snap *snapshot.Tree
|
||||
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
||||
codeSizeCache *lru.Cache[common.Hash, int]
|
||||
pointCache *utils.PointCache
|
||||
}
|
||||
|
||||
// NewDatabase creates a state database with the provided data sources.
|
||||
func NewDatabase(triedb *triedb.Database, snap *snapshot.Tree) *CachingDB {
|
||||
return &CachingDB{
|
||||
disk: triedb.Disk(),
|
||||
triedb: triedb,
|
||||
snap: snap,
|
||||
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||
pointCache: utils.NewPointCache(pointCacheSize),
|
||||
}
|
||||
}
|
||||
|
||||
// NewDatabaseForTesting is similar to NewDatabase, but it initializes the caching
|
||||
// db by using an ephemeral memory db with default config for testing.
|
||||
func NewDatabaseForTesting() *CachingDB {
|
||||
return NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil)
|
||||
}
|
||||
|
||||
// Reader returns a state reader associated with the specified state root.
|
||||
func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||
var readers []Reader
|
||||
|
||||
// Set up the state snapshot reader if available. This feature
|
||||
// is optional and may be partially useful if it's not fully
|
||||
// generated.
|
||||
if db.snap != nil {
|
||||
sr, err := newStateReader(stateRoot, db.snap)
|
||||
if err == nil {
|
||||
readers = append(readers, sr) // snap reader is optional
|
||||
}
|
||||
}
|
||||
// Set up the trie reader, which is expected to always be available
|
||||
// as the gatekeeper unless the state is corrupted.
|
||||
tr, err := newTrieReader(stateRoot, db.triedb, db.pointCache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
readers = append(readers, tr)
|
||||
|
||||
return newMultiReader(readers...)
|
||||
}
|
||||
|
||||
// OpenTrie opens the main account trie at a specific root hash.
|
||||
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
||||
func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
||||
if db.triedb.IsVerkle() {
|
||||
return trie.NewVerkleTrie(root, db.triedb, db.pointCache)
|
||||
}
|
||||
|
|
@ -199,7 +215,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
|||
}
|
||||
|
||||
// OpenStorageTrie opens the storage trie of an account.
|
||||
func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) {
|
||||
func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) {
|
||||
// In the verkle case, there is only one tree. But the two-tree structure
|
||||
// is hardcoded in the codebase. So we need to return the same trie in this
|
||||
// case.
|
||||
|
|
@ -213,20 +229,8 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
|
|||
return tr, nil
|
||||
}
|
||||
|
||||
// CopyTrie returns an independent copy of the given trie.
|
||||
func (db *cachingDB) CopyTrie(t Trie) Trie {
|
||||
switch t := t.(type) {
|
||||
case *trie.StateTrie:
|
||||
return t.Copy()
|
||||
case *trie.VerkleTrie:
|
||||
return t.Copy()
|
||||
default:
|
||||
panic(fmt.Errorf("unknown trie type %T", t))
|
||||
}
|
||||
}
|
||||
|
||||
// ContractCode retrieves a particular contract's code.
|
||||
func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
|
||||
func (db *CachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
|
||||
code, _ := db.codeCache.Get(codeHash)
|
||||
if len(code) > 0 {
|
||||
return code, nil
|
||||
|
|
@ -243,7 +247,7 @@ func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash)
|
|||
// ContractCodeWithPrefix retrieves a particular contract's code. If the
|
||||
// code can't be found in the cache, then check the existence with **new**
|
||||
// db scheme.
|
||||
func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
|
||||
func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
|
||||
code, _ := db.codeCache.Get(codeHash)
|
||||
if len(code) > 0 {
|
||||
return code, nil
|
||||
|
|
@ -258,7 +262,7 @@ func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash com
|
|||
}
|
||||
|
||||
// ContractCodeSize retrieves a particular contracts code's size.
|
||||
func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
||||
func (db *CachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
||||
if cached, ok := db.codeSizeCache.Get(codeHash); ok {
|
||||
return cached, nil
|
||||
}
|
||||
|
|
@ -266,17 +270,29 @@ func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash)
|
|||
return len(code), err
|
||||
}
|
||||
|
||||
// DiskDB returns the underlying key-value disk database.
|
||||
func (db *cachingDB) DiskDB() ethdb.KeyValueStore {
|
||||
return db.disk
|
||||
}
|
||||
|
||||
// TrieDB retrieves any intermediate trie-node caching layer.
|
||||
func (db *cachingDB) TrieDB() *triedb.Database {
|
||||
func (db *CachingDB) TrieDB() *triedb.Database {
|
||||
return db.triedb
|
||||
}
|
||||
|
||||
// PointCache returns the cache of evaluated curve points.
|
||||
func (db *cachingDB) PointCache() *utils.PointCache {
|
||||
func (db *CachingDB) PointCache() *utils.PointCache {
|
||||
return db.pointCache
|
||||
}
|
||||
|
||||
// Snapshot returns the underlying state snapshot.
|
||||
func (db *CachingDB) Snapshot() *snapshot.Tree {
|
||||
return db.snap
|
||||
}
|
||||
|
||||
// mustCopyTrie returns a deep-copied trie.
|
||||
func mustCopyTrie(t Trie) Trie {
|
||||
switch t := t.(type) {
|
||||
case *trie.StateTrie:
|
||||
return t.Copy()
|
||||
case *trie.VerkleTrie:
|
||||
return t.Copy()
|
||||
default:
|
||||
panic(fmt.Errorf("unknown trie type %T", t))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func testNodeIteratorCoverage(t *testing.T, scheme string) {
|
|||
db, sdb, ndb, root, _ := makeTestState(scheme)
|
||||
ndb.Commit(root, false)
|
||||
|
||||
state, err := New(root, sdb, nil)
|
||||
state, err := New(root, sdb)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create state trie at %x: %v", root, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,21 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type revision struct {
|
||||
id int
|
||||
journalIndex int
|
||||
}
|
||||
|
||||
// journalEntry is a modification entry in the state change journal that can be
|
||||
// reverted on demand.
|
||||
type journalEntry interface {
|
||||
|
|
@ -42,6 +51,9 @@ type journalEntry interface {
|
|||
type journal struct {
|
||||
entries []journalEntry // Current changes tracked by the journal
|
||||
dirties map[common.Address]int // Dirty accounts and the number of changes
|
||||
|
||||
validRevisions []revision
|
||||
nextRevisionId int
|
||||
}
|
||||
|
||||
// newJournal creates a new initialized journal.
|
||||
|
|
@ -51,6 +63,40 @@ func newJournal() *journal {
|
|||
}
|
||||
}
|
||||
|
||||
// reset clears the journal, after this operation the journal can be used anew.
|
||||
// It is semantically similar to calling 'newJournal', but the underlying slices
|
||||
// can be reused.
|
||||
func (j *journal) reset() {
|
||||
j.entries = j.entries[:0]
|
||||
j.validRevisions = j.validRevisions[:0]
|
||||
clear(j.dirties)
|
||||
j.nextRevisionId = 0
|
||||
}
|
||||
|
||||
// snapshot returns an identifier for the current revision of the state.
|
||||
func (j *journal) snapshot() int {
|
||||
id := j.nextRevisionId
|
||||
j.nextRevisionId++
|
||||
j.validRevisions = append(j.validRevisions, revision{id, j.length()})
|
||||
return id
|
||||
}
|
||||
|
||||
// revertToSnapshot reverts all state changes made since the given revision.
|
||||
func (j *journal) revertToSnapshot(revid int, s *StateDB) {
|
||||
// Find the snapshot in the stack of valid snapshots.
|
||||
idx := sort.Search(len(j.validRevisions), func(i int) bool {
|
||||
return j.validRevisions[i].id >= revid
|
||||
})
|
||||
if idx == len(j.validRevisions) || j.validRevisions[idx].id != revid {
|
||||
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
|
||||
}
|
||||
snapshot := j.validRevisions[idx].journalIndex
|
||||
|
||||
// Replay the journal to undo changes and remove invalidated snapshots
|
||||
j.revert(s, snapshot)
|
||||
j.validRevisions = j.validRevisions[:idx]
|
||||
}
|
||||
|
||||
// append inserts a new modification entry to the end of the change journal.
|
||||
func (j *journal) append(entry journalEntry) {
|
||||
j.entries = append(j.entries, entry)
|
||||
|
|
@ -95,48 +141,122 @@ func (j *journal) copy() *journal {
|
|||
entries = append(entries, j.entries[i].copy())
|
||||
}
|
||||
return &journal{
|
||||
entries: entries,
|
||||
dirties: maps.Clone(j.dirties),
|
||||
entries: entries,
|
||||
dirties: maps.Clone(j.dirties),
|
||||
validRevisions: slices.Clone(j.validRevisions),
|
||||
nextRevisionId: j.nextRevisionId,
|
||||
}
|
||||
}
|
||||
|
||||
func (j *journal) logChange(txHash common.Hash) {
|
||||
j.append(addLogChange{txhash: txHash})
|
||||
}
|
||||
|
||||
func (j *journal) createObject(addr common.Address) {
|
||||
j.append(createObjectChange{account: addr})
|
||||
}
|
||||
|
||||
func (j *journal) createContract(addr common.Address) {
|
||||
j.append(createContractChange{account: addr})
|
||||
}
|
||||
|
||||
func (j *journal) destruct(addr common.Address) {
|
||||
j.append(selfDestructChange{account: addr})
|
||||
}
|
||||
|
||||
func (j *journal) storageChange(addr common.Address, key, prev, origin common.Hash) {
|
||||
j.append(storageChange{
|
||||
account: addr,
|
||||
key: key,
|
||||
prevvalue: prev,
|
||||
origvalue: origin,
|
||||
})
|
||||
}
|
||||
|
||||
func (j *journal) transientStateChange(addr common.Address, key, prev common.Hash) {
|
||||
j.append(transientStorageChange{
|
||||
account: addr,
|
||||
key: key,
|
||||
prevalue: prev,
|
||||
})
|
||||
}
|
||||
|
||||
func (j *journal) refundChange(previous uint64) {
|
||||
j.append(refundChange{prev: previous})
|
||||
}
|
||||
|
||||
func (j *journal) balanceChange(addr common.Address, previous *uint256.Int) {
|
||||
j.append(balanceChange{
|
||||
account: addr,
|
||||
prev: previous.Clone(),
|
||||
})
|
||||
}
|
||||
|
||||
func (j *journal) setCode(address common.Address) {
|
||||
j.append(codeChange{account: address})
|
||||
}
|
||||
|
||||
func (j *journal) nonceChange(address common.Address, prev uint64) {
|
||||
j.append(nonceChange{
|
||||
account: address,
|
||||
prev: prev,
|
||||
})
|
||||
}
|
||||
|
||||
func (j *journal) touchChange(address common.Address) {
|
||||
j.append(touchChange{
|
||||
account: address,
|
||||
})
|
||||
if address == ripemd {
|
||||
// Explicitly put it in the dirty-cache, which is otherwise generated from
|
||||
// flattened journals.
|
||||
j.dirty(address)
|
||||
}
|
||||
}
|
||||
|
||||
func (j *journal) accessListAddAccount(addr common.Address) {
|
||||
j.append(accessListAddAccountChange{addr})
|
||||
}
|
||||
|
||||
func (j *journal) accessListAddSlot(addr common.Address, slot common.Hash) {
|
||||
j.append(accessListAddSlotChange{
|
||||
address: addr,
|
||||
slot: slot,
|
||||
})
|
||||
}
|
||||
|
||||
type (
|
||||
// Changes to the account trie.
|
||||
createObjectChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
}
|
||||
|
||||
// createContractChange represents an account becoming a contract-account.
|
||||
// This event happens prior to executing initcode. The journal-event simply
|
||||
// manages the created-flag, in order to allow same-tx destruction.
|
||||
createContractChange struct {
|
||||
account common.Address
|
||||
}
|
||||
|
||||
selfDestructChange struct {
|
||||
account *common.Address
|
||||
prev bool // whether account had already self-destructed
|
||||
prevbalance *uint256.Int
|
||||
account common.Address
|
||||
}
|
||||
|
||||
// Changes to individual accounts.
|
||||
balanceChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
prev *uint256.Int
|
||||
}
|
||||
nonceChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
prev uint64
|
||||
}
|
||||
storageChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
key common.Hash
|
||||
prevvalue common.Hash
|
||||
origvalue common.Hash
|
||||
}
|
||||
codeChange struct {
|
||||
account *common.Address
|
||||
prevcode, prevhash []byte
|
||||
account common.Address
|
||||
}
|
||||
|
||||
// Changes to other state values.
|
||||
|
|
@ -146,35 +266,32 @@ type (
|
|||
addLogChange struct {
|
||||
txhash common.Hash
|
||||
}
|
||||
addPreimageChange struct {
|
||||
hash common.Hash
|
||||
}
|
||||
touchChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
}
|
||||
|
||||
// Changes to the access list
|
||||
accessListAddAccountChange struct {
|
||||
address *common.Address
|
||||
address common.Address
|
||||
}
|
||||
accessListAddSlotChange struct {
|
||||
address *common.Address
|
||||
slot *common.Hash
|
||||
address common.Address
|
||||
slot common.Hash
|
||||
}
|
||||
|
||||
// Changes to transient storage
|
||||
transientStorageChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
key, prevalue common.Hash
|
||||
}
|
||||
)
|
||||
|
||||
func (ch createObjectChange) revert(s *StateDB) {
|
||||
delete(s.stateObjects, *ch.account)
|
||||
delete(s.stateObjects, ch.account)
|
||||
}
|
||||
|
||||
func (ch createObjectChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch createObjectChange) copy() journalEntry {
|
||||
|
|
@ -198,22 +315,19 @@ func (ch createContractChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch selfDestructChange) revert(s *StateDB) {
|
||||
obj := s.getStateObject(*ch.account)
|
||||
obj := s.getStateObject(ch.account)
|
||||
if obj != nil {
|
||||
obj.selfDestructed = ch.prev
|
||||
obj.setBalance(ch.prevbalance)
|
||||
obj.selfDestructed = false
|
||||
}
|
||||
}
|
||||
|
||||
func (ch selfDestructChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch selfDestructChange) copy() journalEntry {
|
||||
return selfDestructChange{
|
||||
account: ch.account,
|
||||
prev: ch.prev,
|
||||
prevbalance: new(uint256.Int).Set(ch.prevbalance),
|
||||
account: ch.account,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -223,7 +337,7 @@ func (ch touchChange) revert(s *StateDB) {
|
|||
}
|
||||
|
||||
func (ch touchChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch touchChange) copy() journalEntry {
|
||||
|
|
@ -233,11 +347,11 @@ func (ch touchChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch balanceChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setBalance(ch.prev)
|
||||
s.getStateObject(ch.account).setBalance(ch.prev)
|
||||
}
|
||||
|
||||
func (ch balanceChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch balanceChange) copy() journalEntry {
|
||||
|
|
@ -248,11 +362,11 @@ func (ch balanceChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch nonceChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setNonce(ch.prev)
|
||||
s.getStateObject(ch.account).setNonce(ch.prev)
|
||||
}
|
||||
|
||||
func (ch nonceChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch nonceChange) copy() journalEntry {
|
||||
|
|
@ -263,27 +377,23 @@ func (ch nonceChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch codeChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
|
||||
s.getStateObject(ch.account).setCode(types.EmptyCodeHash, nil)
|
||||
}
|
||||
|
||||
func (ch codeChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch codeChange) copy() journalEntry {
|
||||
return codeChange{
|
||||
account: ch.account,
|
||||
prevhash: common.CopyBytes(ch.prevhash),
|
||||
prevcode: common.CopyBytes(ch.prevcode),
|
||||
}
|
||||
return codeChange{account: ch.account}
|
||||
}
|
||||
|
||||
func (ch storageChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue, ch.origvalue)
|
||||
s.getStateObject(ch.account).setState(ch.key, ch.prevvalue, ch.origvalue)
|
||||
}
|
||||
|
||||
func (ch storageChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch storageChange) copy() journalEntry {
|
||||
|
|
@ -295,7 +405,7 @@ func (ch storageChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch transientStorageChange) revert(s *StateDB) {
|
||||
s.setTransientState(*ch.account, ch.key, ch.prevalue)
|
||||
s.setTransientState(ch.account, ch.key, ch.prevalue)
|
||||
}
|
||||
|
||||
func (ch transientStorageChange) dirtied() *common.Address {
|
||||
|
|
@ -344,20 +454,6 @@ func (ch addLogChange) copy() journalEntry {
|
|||
}
|
||||
}
|
||||
|
||||
func (ch addPreimageChange) revert(s *StateDB) {
|
||||
delete(s.preimages, ch.hash)
|
||||
}
|
||||
|
||||
func (ch addPreimageChange) dirtied() *common.Address {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch addPreimageChange) copy() journalEntry {
|
||||
return addPreimageChange{
|
||||
hash: ch.hash,
|
||||
}
|
||||
}
|
||||
|
||||
func (ch accessListAddAccountChange) revert(s *StateDB) {
|
||||
/*
|
||||
One important invariant here, is that whenever a (addr, slot) is added, if the
|
||||
|
|
@ -368,7 +464,7 @@ func (ch accessListAddAccountChange) revert(s *StateDB) {
|
|||
(addr) at this point, since no storage adds can remain when come upon
|
||||
a single (addr) change.
|
||||
*/
|
||||
s.accessList.DeleteAddress(*ch.address)
|
||||
s.accessList.DeleteAddress(ch.address)
|
||||
}
|
||||
|
||||
func (ch accessListAddAccountChange) dirtied() *common.Address {
|
||||
|
|
@ -382,7 +478,7 @@ func (ch accessListAddAccountChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch accessListAddSlotChange) revert(s *StateDB) {
|
||||
s.accessList.DeleteSlot(*ch.address, *ch.slot)
|
||||
s.accessList.DeleteSlot(ch.address, ch.slot)
|
||||
}
|
||||
|
||||
func (ch accessListAddSlotChange) dirtied() *common.Address {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package state
|
|||
import "github.com/ethereum/go-ethereum/metrics"
|
||||
|
||||
var (
|
||||
accountReadMeters = metrics.NewRegisteredMeter("state/read/accounts", nil)
|
||||
storageReadMeters = metrics.NewRegisteredMeter("state/read/storage", nil)
|
||||
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
|
||||
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
|
||||
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)
|
||||
|
|
@ -27,10 +29,4 @@ var (
|
|||
storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil)
|
||||
accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil)
|
||||
storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil)
|
||||
|
||||
slotDeletionMaxCount = metrics.NewRegisteredGauge("state/delete/storage/max/slot", nil)
|
||||
slotDeletionMaxSize = metrics.NewRegisteredGauge("state/delete/storage/max/size", nil)
|
||||
slotDeletionTimer = metrics.NewRegisteredResettingTimer("state/delete/storage/timer", nil)
|
||||
slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil)
|
||||
slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -270,11 +270,10 @@ func (p *Pruner) Prune(root common.Hash) error {
|
|||
// is the presence of root can indicate the presence of the
|
||||
// entire trie.
|
||||
if !rawdb.HasLegacyTrieNode(p.db, root) {
|
||||
// The special case is for clique based networks(goerli
|
||||
// and some other private networks), it's possible that two
|
||||
// consecutive blocks will have same root. In this case snapshot
|
||||
// difflayer won't be created. So HEAD-127 may not paired with
|
||||
// head-127 layer. Instead the paired layer is higher than the
|
||||
// The special case is for clique based networks, it's possible
|
||||
// that two consecutive blocks will have same root. In this case
|
||||
// snapshot difflayer won't be created. So HEAD-127 may not paired
|
||||
// with head-127 layer. Instead the paired layer is higher than the
|
||||
// bottom-most diff layer. Try to find the bottom-most snapshot
|
||||
// layer with state available.
|
||||
//
|
||||
|
|
|
|||
313
core/state/reader.go
Normal file
313
core/state/reader.go
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"maps"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/utils"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
)
|
||||
|
||||
// Reader defines the interface for accessing accounts and storage slots
|
||||
// associated with a specific state.
|
||||
type Reader interface {
|
||||
// Account retrieves the account associated with a particular address.
|
||||
//
|
||||
// - Returns a nil account if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned account is safe to modify after the call
|
||||
Account(addr common.Address) (*types.StateAccount, error)
|
||||
|
||||
// Storage retrieves the storage slot associated with a particular account
|
||||
// address and slot key.
|
||||
//
|
||||
// - Returns an empty slot if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned storage slot is safe to modify after the call
|
||||
Storage(addr common.Address, slot common.Hash) (common.Hash, error)
|
||||
|
||||
// Copy returns a deep-copied state reader.
|
||||
Copy() Reader
|
||||
}
|
||||
|
||||
// stateReader is a wrapper over the state snapshot and implements the Reader
|
||||
// interface. It provides an efficient way to access flat state.
|
||||
type stateReader struct {
|
||||
snap snapshot.Snapshot
|
||||
buff crypto.KeccakState
|
||||
}
|
||||
|
||||
// newStateReader constructs a flat state reader with on the specified state root.
|
||||
func newStateReader(root common.Hash, snaps *snapshot.Tree) (*stateReader, error) {
|
||||
snap := snaps.Snapshot(root)
|
||||
if snap == nil {
|
||||
return nil, errors.New("snapshot is not available")
|
||||
}
|
||||
return &stateReader{
|
||||
snap: snap,
|
||||
buff: crypto.NewKeccakState(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Account implements Reader, retrieving the account specified by the address.
|
||||
//
|
||||
// An error will be returned if the associated snapshot is already stale or
|
||||
// the requested account is not yet covered by the snapshot.
|
||||
//
|
||||
// The returned account might be nil if it's not existent.
|
||||
func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||
ret, err := r.snap.Account(crypto.HashData(r.buff, addr.Bytes()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret == nil {
|
||||
return nil, nil
|
||||
}
|
||||
acct := &types.StateAccount{
|
||||
Nonce: ret.Nonce,
|
||||
Balance: ret.Balance,
|
||||
CodeHash: ret.CodeHash,
|
||||
Root: common.BytesToHash(ret.Root),
|
||||
}
|
||||
if len(acct.CodeHash) == 0 {
|
||||
acct.CodeHash = types.EmptyCodeHash.Bytes()
|
||||
}
|
||||
if acct.Root == (common.Hash{}) {
|
||||
acct.Root = types.EmptyRootHash
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
// Storage implements Reader, retrieving the storage slot specified by the
|
||||
// address and slot key.
|
||||
//
|
||||
// An error will be returned if the associated snapshot is already stale or
|
||||
// the requested storage slot is not yet covered by the snapshot.
|
||||
//
|
||||
// The returned storage slot might be empty if it's not existent.
|
||||
func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
||||
addrHash := crypto.HashData(r.buff, addr.Bytes())
|
||||
slotHash := crypto.HashData(r.buff, key.Bytes())
|
||||
ret, err := r.snap.Storage(addrHash, slotHash)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
if len(ret) == 0 {
|
||||
return common.Hash{}, nil
|
||||
}
|
||||
// Perform the rlp-decode as the slot value is RLP-encoded in the state
|
||||
// snapshot.
|
||||
_, content, _, err := rlp.Split(ret)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
var value common.Hash
|
||||
value.SetBytes(content)
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// Copy implements Reader, returning a deep-copied snap reader.
|
||||
func (r *stateReader) Copy() Reader {
|
||||
return &stateReader{
|
||||
snap: r.snap,
|
||||
buff: crypto.NewKeccakState(),
|
||||
}
|
||||
}
|
||||
|
||||
// trieReader implements the Reader interface, providing functions to access
|
||||
// state from the referenced trie.
|
||||
type trieReader struct {
|
||||
root common.Hash // State root which uniquely represent a state
|
||||
db *triedb.Database // Database for loading trie
|
||||
buff crypto.KeccakState // Buffer for keccak256 hashing
|
||||
mainTrie Trie // Main trie, resolved in constructor
|
||||
subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved
|
||||
subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved
|
||||
}
|
||||
|
||||
// trieReader constructs a trie reader of the specific state. An error will be
|
||||
// returned if the associated trie specified by root is not existent.
|
||||
func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCache) (*trieReader, error) {
|
||||
var (
|
||||
tr Trie
|
||||
err error
|
||||
)
|
||||
if !db.IsVerkle() {
|
||||
tr, err = trie.NewStateTrie(trie.StateTrieID(root), db)
|
||||
} else {
|
||||
tr, err = trie.NewVerkleTrie(root, db, cache)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &trieReader{
|
||||
root: root,
|
||||
db: db,
|
||||
buff: crypto.NewKeccakState(),
|
||||
mainTrie: tr,
|
||||
subRoots: make(map[common.Address]common.Hash),
|
||||
subTries: make(map[common.Address]Trie),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Account implements Reader, retrieving the account specified by the address.
|
||||
//
|
||||
// An error will be returned if the trie state is corrupted. An nil account
|
||||
// will be returned if it's not existent in the trie.
|
||||
func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||
account, err := r.mainTrie.GetAccount(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if account == nil {
|
||||
r.subRoots[addr] = types.EmptyRootHash
|
||||
} else {
|
||||
r.subRoots[addr] = account.Root
|
||||
}
|
||||
return account, nil
|
||||
}
|
||||
|
||||
// Storage implements Reader, retrieving the storage slot specified by the
|
||||
// address and slot key.
|
||||
//
|
||||
// An error will be returned if the trie state is corrupted. An empty storage
|
||||
// slot will be returned if it's not existent in the trie.
|
||||
func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
||||
var (
|
||||
tr Trie
|
||||
found bool
|
||||
value common.Hash
|
||||
)
|
||||
if r.db.IsVerkle() {
|
||||
tr = r.mainTrie
|
||||
} else {
|
||||
tr, found = r.subTries[addr]
|
||||
if !found {
|
||||
root, ok := r.subRoots[addr]
|
||||
|
||||
// The storage slot is accessed without account caching. It's unexpected
|
||||
// behavior but try to resolve the account first anyway.
|
||||
if !ok {
|
||||
_, err := r.Account(addr)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
root = r.subRoots[addr]
|
||||
}
|
||||
var err error
|
||||
tr, err = trie.NewStateTrie(trie.StorageTrieID(r.root, crypto.HashData(r.buff, addr.Bytes()), root), r.db)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
r.subTries[addr] = tr
|
||||
}
|
||||
}
|
||||
ret, err := tr.GetStorage(addr, key.Bytes())
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
value.SetBytes(ret)
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// Copy implements Reader, returning a deep-copied trie reader.
|
||||
func (r *trieReader) Copy() Reader {
|
||||
tries := make(map[common.Address]Trie)
|
||||
for addr, tr := range r.subTries {
|
||||
tries[addr] = mustCopyTrie(tr)
|
||||
}
|
||||
return &trieReader{
|
||||
root: r.root,
|
||||
db: r.db,
|
||||
buff: crypto.NewKeccakState(),
|
||||
mainTrie: mustCopyTrie(r.mainTrie),
|
||||
subRoots: maps.Clone(r.subRoots),
|
||||
subTries: tries,
|
||||
}
|
||||
}
|
||||
|
||||
// multiReader is the aggregation of a list of Reader interface, providing state
|
||||
// access by leveraging all readers. The checking priority is determined by the
|
||||
// position in the reader list.
|
||||
type multiReader struct {
|
||||
readers []Reader // List of readers, sorted by checking priority
|
||||
}
|
||||
|
||||
// newMultiReader constructs a multiReader instance with the given readers. The
|
||||
// priority among readers is assumed to be sorted. Note, it must contain at least
|
||||
// one reader for constructing a multiReader.
|
||||
func newMultiReader(readers ...Reader) (*multiReader, error) {
|
||||
if len(readers) == 0 {
|
||||
return nil, errors.New("empty reader set")
|
||||
}
|
||||
return &multiReader{
|
||||
readers: readers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Account implementing Reader interface, retrieving the account associated with
|
||||
// a particular address.
|
||||
//
|
||||
// - Returns a nil account if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned account is safe to modify after the call
|
||||
func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||
var errs []error
|
||||
for _, reader := range r.readers {
|
||||
acct, err := reader.Account(addr)
|
||||
if err == nil {
|
||||
return acct, nil
|
||||
}
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return nil, errors.Join(errs...)
|
||||
}
|
||||
|
||||
// Storage implementing Reader interface, retrieving the storage slot associated
|
||||
// with a particular account address and slot key.
|
||||
//
|
||||
// - Returns an empty slot if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned storage slot is safe to modify after the call
|
||||
func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||
var errs []error
|
||||
for _, reader := range r.readers {
|
||||
slot, err := reader.Storage(addr, slot)
|
||||
if err == nil {
|
||||
return slot, nil
|
||||
}
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return common.Hash{}, errors.Join(errs...)
|
||||
}
|
||||
|
||||
// Copy implementing Reader interface, returning a deep-copied state reader.
|
||||
func (r *multiReader) Copy() Reader {
|
||||
var readers []Reader
|
||||
for _, reader := range r.readers {
|
||||
readers = append(readers, reader.Copy())
|
||||
}
|
||||
return &multiReader{readers: readers}
|
||||
}
|
||||
|
|
@ -74,6 +74,14 @@ func (dl *diskLayer) Stale() bool {
|
|||
return dl.stale
|
||||
}
|
||||
|
||||
// markStale sets the stale flag as true.
|
||||
func (dl *diskLayer) markStale() {
|
||||
dl.lock.Lock()
|
||||
defer dl.lock.Unlock()
|
||||
|
||||
dl.stale = true
|
||||
}
|
||||
|
||||
// Account directly retrieves the account associated with a particular hash in
|
||||
// the snapshot slim data format.
|
||||
func (dl *diskLayer) Account(hash common.Hash) (*types.SlimAccount, error) {
|
||||
|
|
@ -175,3 +183,18 @@ func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
|
|||
func (dl *diskLayer) Update(blockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer {
|
||||
return newDiffLayer(dl, blockHash, destructs, accounts, storage)
|
||||
}
|
||||
|
||||
// stopGeneration aborts the state snapshot generation if it is currently running.
|
||||
func (dl *diskLayer) stopGeneration() {
|
||||
dl.lock.RLock()
|
||||
generating := dl.genMarker != nil
|
||||
dl.lock.RUnlock()
|
||||
if !generating {
|
||||
return
|
||||
}
|
||||
if dl.genAbort != nil {
|
||||
abort := make(chan *generatorStats)
|
||||
dl.genAbort <- abort
|
||||
<-abort
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -631,16 +631,10 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
|
|||
accMarker = nil
|
||||
return nil
|
||||
}
|
||||
// Always reset the initial account range as 1 whenever recover from the
|
||||
// interruption. TODO(rjl493456442) can we remove it?
|
||||
var accountRange = accountCheckRange
|
||||
if len(accMarker) > 0 {
|
||||
accountRange = 1
|
||||
}
|
||||
origin := common.CopyBytes(accMarker)
|
||||
for {
|
||||
id := trie.StateTrieID(dl.root)
|
||||
exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, types.FullAccountRLP)
|
||||
exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountCheckRange, onAccount, types.FullAccountRLP)
|
||||
if err != nil {
|
||||
return err // The procedure it aborted, either by external signal or internal error.
|
||||
}
|
||||
|
|
@ -652,7 +646,6 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
|
|||
ctx.removeStorageLeft()
|
||||
break
|
||||
}
|
||||
accountRange = accountCheckRange
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,24 +258,11 @@ func (t *Tree) Disable() {
|
|||
for _, layer := range t.layers {
|
||||
switch layer := layer.(type) {
|
||||
case *diskLayer:
|
||||
|
||||
layer.lock.RLock()
|
||||
generating := layer.genMarker != nil
|
||||
layer.lock.RUnlock()
|
||||
if !generating {
|
||||
// Generator is already aborted or finished
|
||||
break
|
||||
}
|
||||
// If the base layer is generating, abort it
|
||||
if layer.genAbort != nil {
|
||||
abort := make(chan *generatorStats)
|
||||
layer.genAbort <- abort
|
||||
<-abort
|
||||
}
|
||||
// Layer should be inactive now, mark it as stale
|
||||
layer.lock.Lock()
|
||||
layer.stale = true
|
||||
layer.lock.Unlock()
|
||||
// TODO this function will hang if it's called twice. Will
|
||||
// fix it in the following PRs.
|
||||
layer.stopGeneration()
|
||||
layer.markStale()
|
||||
layer.Release()
|
||||
|
||||
case *diffLayer:
|
||||
// If the layer is a simple diff, simply mark as stale
|
||||
|
|
@ -730,16 +717,11 @@ func (t *Tree) Rebuild(root common.Hash) {
|
|||
for _, layer := range t.layers {
|
||||
switch layer := layer.(type) {
|
||||
case *diskLayer:
|
||||
// If the base layer is generating, abort it and save
|
||||
if layer.genAbort != nil {
|
||||
abort := make(chan *generatorStats)
|
||||
layer.genAbort <- abort
|
||||
<-abort
|
||||
}
|
||||
// Layer should be inactive now, mark it as stale
|
||||
layer.lock.Lock()
|
||||
layer.stale = true
|
||||
layer.lock.Unlock()
|
||||
// TODO this function will hang if it's called twice. Will
|
||||
// fix it in the following PRs.
|
||||
layer.stopGeneration()
|
||||
layer.markStale()
|
||||
layer.Release()
|
||||
|
||||
case *diffLayer:
|
||||
// If the layer is a simple diff, simply mark as stale
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue