Merge pull request #30456 from ethereum/master
Merge branch 'master' into release/1.14
This commit is contained in:
commit
c350d3acd5
|
@ -15,7 +15,7 @@ jobs:
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.21.4
|
go-version: 1.23.0
|
||||||
cache: false
|
cache: false
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: go test -short ./...
|
run: go test -short ./...
|
||||||
|
|
|
@ -28,6 +28,14 @@ build/_vendor/pkg
|
||||||
/build/bin/
|
/build/bin/
|
||||||
/geth*.zip
|
/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
|
# travis
|
||||||
profile.tmp
|
profile.tmp
|
||||||
profile.cov
|
profile.cov
|
||||||
|
|
|
@ -60,6 +60,10 @@ issues:
|
||||||
- path: crypto/bn256/
|
- path: crypto/bn256/
|
||||||
linters:
|
linters:
|
||||||
- revive
|
- 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
|
- path: internal/build/pgp.go
|
||||||
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
|
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
|
||||||
- path: core/vm/contracts.go
|
- path: core/vm/contracts.go
|
||||||
|
|
35
.travis.yml
35
.travis.yml
|
@ -15,8 +15,8 @@ jobs:
|
||||||
if: type = push
|
if: type = push
|
||||||
os: linux
|
os: linux
|
||||||
arch: amd64
|
arch: amd64
|
||||||
dist: noble
|
dist: focal
|
||||||
go: 1.22.x
|
go: 1.23.x
|
||||||
env:
|
env:
|
||||||
- docker
|
- docker
|
||||||
services:
|
services:
|
||||||
|
@ -32,8 +32,8 @@ jobs:
|
||||||
if: type = push
|
if: type = push
|
||||||
os: linux
|
os: linux
|
||||||
arch: arm64
|
arch: arm64
|
||||||
dist: noble
|
dist: focal
|
||||||
go: 1.22.x
|
go: 1.23.x
|
||||||
env:
|
env:
|
||||||
- docker
|
- docker
|
||||||
services:
|
services:
|
||||||
|
@ -49,9 +49,9 @@ jobs:
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = push
|
if: type = push
|
||||||
os: linux
|
os: linux
|
||||||
dist: noble
|
dist: focal
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.22.x
|
go: 1.23.x
|
||||||
env:
|
env:
|
||||||
- azure-linux
|
- azure-linux
|
||||||
git:
|
git:
|
||||||
|
@ -63,6 +63,7 @@ jobs:
|
||||||
|
|
||||||
# build 386
|
# build 386
|
||||||
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
- 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 install -dlgo -arch 386
|
||||||
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||||
|
|
||||||
|
@ -84,7 +85,7 @@ jobs:
|
||||||
if: type = push
|
if: type = push
|
||||||
os: osx
|
os: osx
|
||||||
osx_image: xcode14.2
|
osx_image: xcode14.2
|
||||||
go: 1.22.x
|
go: 1.23.x
|
||||||
env:
|
env:
|
||||||
- azure-osx
|
- azure-osx
|
||||||
git:
|
git:
|
||||||
|
@ -100,16 +101,16 @@ jobs:
|
||||||
if: type = push
|
if: type = push
|
||||||
os: linux
|
os: linux
|
||||||
arch: amd64
|
arch: amd64
|
||||||
dist: noble
|
dist: focal
|
||||||
go: 1.22.x
|
go: 1.23.x
|
||||||
script:
|
script:
|
||||||
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||||
|
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = push
|
if: type = push
|
||||||
os: linux
|
os: linux
|
||||||
dist: noble
|
dist: focal
|
||||||
go: 1.21.x
|
go: 1.22.x
|
||||||
script:
|
script:
|
||||||
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||||
|
|
||||||
|
@ -117,8 +118,8 @@ jobs:
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
||||||
os: linux
|
os: linux
|
||||||
dist: noble
|
dist: focal
|
||||||
go: 1.22.x
|
go: 1.23.x
|
||||||
env:
|
env:
|
||||||
- ubuntu-ppa
|
- ubuntu-ppa
|
||||||
git:
|
git:
|
||||||
|
@ -133,8 +134,8 @@ jobs:
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = cron
|
if: type = cron
|
||||||
os: linux
|
os: linux
|
||||||
dist: noble
|
dist: focal
|
||||||
go: 1.22.x
|
go: 1.23.x
|
||||||
env:
|
env:
|
||||||
- azure-purge
|
- azure-purge
|
||||||
git:
|
git:
|
||||||
|
@ -146,8 +147,8 @@ jobs:
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = cron
|
if: type = cron
|
||||||
os: linux
|
os: linux
|
||||||
dist: noble
|
dist: focal
|
||||||
go: 1.22.x
|
go: 1.23.x
|
||||||
env:
|
env:
|
||||||
- racetests
|
- racetests
|
||||||
script:
|
script:
|
||||||
|
|
|
@ -4,7 +4,7 @@ ARG VERSION=""
|
||||||
ARG BUILDNUM=""
|
ARG BUILDNUM=""
|
||||||
|
|
||||||
# Build Geth in a stock Go builder container
|
# 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
|
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ ARG VERSION=""
|
||||||
ARG BUILDNUM=""
|
ARG BUILDNUM=""
|
||||||
|
|
||||||
# Build Geth in a stock Go builder container
|
# 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
|
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||||
|
|
||||||
|
|
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).
|
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
|
them using your favourite package manager. Once the dependencies are installed, run
|
||||||
|
|
||||||
```shell
|
```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
|
This tool is optional and if you leave it out you can always attach it to an already running
|
||||||
`geth` instance with `geth attach`.
|
`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
|
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
|
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.
|
the main network, but with play-Ether only.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ geth --goerli console
|
$ geth --holesky console
|
||||||
```
|
```
|
||||||
|
|
||||||
The `console` subcommand has the same meaning as above and is equally
|
The `console` subcommand has the same meaning as above and is equally
|
||||||
useful on the testnet too.
|
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
|
test network, which uses different P2P bootnodes, different network IDs and genesis
|
||||||
states.
|
states.
|
||||||
* Instead of using the default data directory (`~/.ethereum` on Linux for example), `geth`
|
* 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
|
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
|
requires the use of a custom endpoint since `geth attach` will try to attach to a
|
||||||
production node endpoint by default, e.g.,
|
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.
|
this.
|
||||||
|
|
||||||
*Note: Although some internal protective measures prevent transactions from
|
*Note: Although some internal protective measures prevent transactions from
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -82,7 +82,9 @@ func TestWaitDeployed(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Send and mine the transaction.
|
// 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()
|
backend.Commit()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
@ -116,7 +118,9 @@ func TestWaitDeployedCornerCases(t *testing.T) {
|
||||||
tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey)
|
tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
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()
|
backend.Commit()
|
||||||
notContractCreation := errors.New("tx is not contract creation")
|
notContractCreation := errors.New("tx is not contract creation")
|
||||||
if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != notContractCreation.Error() {
|
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()
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,8 +219,13 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
|
||||||
typ.T = FunctionTy
|
typ.T = FunctionTy
|
||||||
typ.Size = 24
|
typ.Size = 24
|
||||||
default:
|
default:
|
||||||
|
if strings.HasPrefix(internalType, "contract ") {
|
||||||
|
typ.Size = 20
|
||||||
|
typ.T = AddressTy
|
||||||
|
} else {
|
||||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,10 @@ func TestBlockSync(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
var expNumber, headNumber uint64
|
var expNumber, headNumber uint64
|
||||||
if expHead != nil {
|
if expHead != nil {
|
||||||
p, _ := expHead.ExecutionPayload()
|
p, err := expHead.ExecutionPayload()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expHead.ExecutionPayload() failed: %v", err)
|
||||||
|
}
|
||||||
expNumber = p.NumberU64()
|
expNumber = p.NumberU64()
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
|
|
|
@ -56,32 +56,17 @@ var (
|
||||||
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}),
|
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}),
|
||||||
Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"),
|
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 {
|
func makeChainConfig(ctx *cli.Context) lightClientConfig {
|
||||||
var config lightClientConfig
|
var config lightClientConfig
|
||||||
customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name)
|
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 {
|
switch {
|
||||||
case ctx.Bool(utils.MainnetFlag.Name):
|
case ctx.Bool(utils.MainnetFlag.Name):
|
||||||
config = MainnetConfig
|
config = MainnetConfig
|
||||||
case ctx.Bool(utils.SepoliaFlag.Name):
|
case ctx.Bool(utils.SepoliaFlag.Name):
|
||||||
config = SepoliaConfig
|
config = SepoliaConfig
|
||||||
case ctx.Bool(utils.GoerliFlag.Name):
|
|
||||||
config = GoerliConfig
|
|
||||||
default:
|
default:
|
||||||
if !customConfig {
|
if !customConfig {
|
||||||
config = MainnetConfig
|
config = MainnetConfig
|
||||||
|
|
|
@ -34,6 +34,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||||
|
Deposits types.Deposits `json:"depositRequests"`
|
||||||
|
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||||
}
|
}
|
||||||
var enc ExecutableData
|
var enc ExecutableData
|
||||||
enc.ParentHash = e.ParentHash
|
enc.ParentHash = e.ParentHash
|
||||||
|
@ -58,6 +60,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
||||||
enc.Withdrawals = e.Withdrawals
|
enc.Withdrawals = e.Withdrawals
|
||||||
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
|
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
|
||||||
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
|
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
|
||||||
|
enc.Deposits = e.Deposits
|
||||||
|
enc.ExecutionWitness = e.ExecutionWitness
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +85,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||||
|
Deposits *types.Deposits `json:"depositRequests"`
|
||||||
|
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||||
}
|
}
|
||||||
var dec ExecutableData
|
var dec ExecutableData
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
@ -154,5 +160,11 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
||||||
if dec.ExcessBlobGas != nil {
|
if dec.ExcessBlobGas != nil {
|
||||||
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
|
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
|
||||||
}
|
}
|
||||||
|
if dec.Deposits != nil {
|
||||||
|
e.Deposits = *dec.Deposits
|
||||||
|
}
|
||||||
|
if dec.ExecutionWitness != nil {
|
||||||
|
e.ExecutionWitness = dec.ExecutionWitness
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,8 @@ type ExecutableData struct {
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
||||||
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
||||||
|
Deposits types.Deposits `json:"depositRequests"`
|
||||||
|
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON type overrides for executableData.
|
// JSON type overrides for executableData.
|
||||||
|
@ -230,6 +232,19 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
||||||
h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil))
|
h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil))
|
||||||
withdrawalsRoot = &h
|
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{
|
header := &types.Header{
|
||||||
ParentHash: data.ParentHash,
|
ParentHash: data.ParentHash,
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
|
@ -250,8 +265,11 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
||||||
ExcessBlobGas: data.ExcessBlobGas,
|
ExcessBlobGas: data.ExcessBlobGas,
|
||||||
BlobGasUsed: data.BlobGasUsed,
|
BlobGasUsed: data.BlobGasUsed,
|
||||||
ParentBeaconRoot: beaconRoot,
|
ParentBeaconRoot: beaconRoot,
|
||||||
|
RequestsHash: requestsHash,
|
||||||
}
|
}
|
||||||
block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals})
|
block := types.NewBlockWithHeader(header)
|
||||||
|
block = block.WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests})
|
||||||
|
block = block.WithWitness(data.ExecutionWitness)
|
||||||
if block.Hash() != data.BlockHash {
|
if block.Hash() != data.BlockHash {
|
||||||
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
|
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
|
||||||
}
|
}
|
||||||
|
@ -279,6 +297,7 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
|
||||||
Withdrawals: block.Withdrawals(),
|
Withdrawals: block.Withdrawals(),
|
||||||
BlobGasUsed: block.BlobGasUsed(),
|
BlobGasUsed: block.BlobGasUsed(),
|
||||||
ExcessBlobGas: block.ExcessBlobGas(),
|
ExcessBlobGas: block.ExcessBlobGas(),
|
||||||
|
ExecutionWitness: block.ExecutionWitness(),
|
||||||
}
|
}
|
||||||
bundle := BlobsBundleV1{
|
bundle := BlobsBundleV1{
|
||||||
Commitments: make([]hexutil.Bytes, 0),
|
Commitments: make([]hexutil.Bytes, 0),
|
||||||
|
@ -292,13 +311,30 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
|
||||||
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
|
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setRequests(block.Requests(), data)
|
||||||
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
|
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
|
// setRequests differentiates the different request types and
|
||||||
type ExecutionPayloadBodyV1 struct {
|
// 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"`
|
TransactionData []hexutil.Bytes `json:"transactions"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
|
Deposits types.Deposits `json:"depositRequests"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client identifiers to support ClientVersionV1.
|
// Client identifiers to support ClientVersionV1.
|
||||||
|
|
|
@ -23,6 +23,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -120,8 +122,12 @@ func NewBeaconLightApi(url string, customHeaders map[string]string) *BeaconLight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *BeaconLightApi) httpGet(path string) ([]byte, error) {
|
func (api *BeaconLightApi) httpGet(path string, params url.Values) ([]byte, error) {
|
||||||
req, err := http.NewRequest("GET", api.url+path, nil)
|
uri, err := api.buildURL(path, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("GET", uri, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// GetBestUpdatesAndCommittees fetches and validates LightClientUpdate for given
|
||||||
// period and full serialized committee for the next period (committee root hash
|
// period and full serialized committee for the next period (committee root hash
|
||||||
// equals update.NextSyncCommitteeRoot).
|
// equals update.NextSyncCommitteeRoot).
|
||||||
// Note that the results are validated but the update signature should be verified
|
// Note that the results are validated but the update signature should be verified
|
||||||
// by the caller as its validity depends on the update chain.
|
// by the caller as its validity depends on the update chain.
|
||||||
func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64) ([]*types.LightClientUpdate, []*types.SerializedSyncCommittee, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -192,7 +197,7 @@ func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64
|
||||||
// See data structure definition here:
|
// See data structure definition here:
|
||||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
|
||||||
func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error) {
|
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 {
|
if err != nil {
|
||||||
return types.OptimisticUpdate{}, err
|
return types.OptimisticUpdate{}, err
|
||||||
}
|
}
|
||||||
|
@ -245,7 +250,7 @@ func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) {
|
||||||
// See data structure definition here:
|
// See data structure definition here:
|
||||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
|
||||||
func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) {
|
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 {
|
if err != nil {
|
||||||
return types.FinalityUpdate{}, err
|
return types.FinalityUpdate{}, err
|
||||||
}
|
}
|
||||||
|
@ -311,7 +316,7 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool,
|
||||||
} else {
|
} else {
|
||||||
blockId = blockRoot.Hex()
|
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 {
|
if err != nil {
|
||||||
return types.Header{}, false, false, err
|
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.
|
// GetCheckpointData fetches and validates bootstrap data belonging to the given checkpoint.
|
||||||
func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types.BootstrapData, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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.
|
// established. It can only return nil when the context is canceled.
|
||||||
func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream {
|
func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream {
|
||||||
for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) {
|
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")
|
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 {
|
if err != nil {
|
||||||
listener.OnError(fmt.Errorf("error creating event subscription request: %v", err))
|
listener.OnError(fmt.Errorf("error creating event subscription request: %v", err))
|
||||||
continue
|
continue
|
||||||
|
@ -576,3 +585,15 @@ func ctxSleep(ctx context.Context, timeout time.Duration) (ok bool) {
|
||||||
return false
|
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)
|
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 {
|
func testRespUpdate(request requestWithID) request.Response {
|
||||||
var resp RespUpdates
|
var resp RespUpdates
|
||||||
if request.request == nil {
|
if request.request == nil {
|
||||||
|
|
|
@ -5,55 +5,56 @@
|
||||||
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
||||||
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
||||||
|
|
||||||
# version:golang 1.22.6
|
# version:golang 1.23.1
|
||||||
# https://go.dev/dl/
|
# https://go.dev/dl/
|
||||||
9e48d99d519882579917d8189c17e98c373ce25abaebb98772e2927088992a51 go1.22.6.src.tar.gz
|
6ee44e298379d146a5e5aa6b1c5b5d5f5d0a3365eabdd70741e6e21340ec3b0d go1.23.1.src.tar.gz
|
||||||
eeb0cc42120cbae6d3695dae2e5420fa0e93a5db957db139b55efdb879dd9856 go1.22.6.aix-ppc64.tar.gz
|
f17f2791717c15728ec63213a014e244c35f9c8846fb29f5a1b63d0c0556f756 go1.23.1.aix-ppc64.tar.gz
|
||||||
b47ac340f0b072943fed1f558a26eb260cc23bd21b8af175582e9103141d465b go1.22.6.darwin-amd64.pkg
|
dd9e772686ed908bcff94b6144322d4e2473a7dcd7c696b7e8b6d12f23c887fd go1.23.1.darwin-amd64.pkg
|
||||||
9c3c0124b01b5365f73a1489649f78f971ecf84844ad9ca58fde133096ddb61b go1.22.6.darwin-amd64.tar.gz
|
488d9e4ca3e3ed513ee4edd91bef3a2360c65fa6d6be59cf79640bf840130a58 go1.23.1.darwin-amd64.tar.gz
|
||||||
14d0355ec1c0eeb213a16efa8635fac1f16067ef78a8173abf9a8c7b805e551e go1.22.6.darwin-arm64.pkg
|
be34b488157ec69d94e26e1554558219a2c90789bcb7e3686965a7f9c8cfcbe7 go1.23.1.darwin-arm64.pkg
|
||||||
ebac39fd44fc22feed1bb519af431c84c55776e39b30f4fd62930da9c0cfd1e3 go1.22.6.darwin-arm64.tar.gz
|
e223795ca340e285a760a6446ce57a74500b30e57469a4109961d36184d3c05a go1.23.1.darwin-arm64.tar.gz
|
||||||
3695b10c722a4920c8a736284f8820c142e1e752f3a87f797a45c64366f7a173 go1.22.6.dragonfly-amd64.tar.gz
|
6af626176923a6ae6c5de6dc1c864f38365793c0e4ecd0d6eab847bdc23953e5 go1.23.1.dragonfly-amd64.tar.gz
|
||||||
a9b9570c80294a664d50b566d6bd1aa42465997d2d76a57936b32f55f5c69c63 go1.22.6.freebsd-386.tar.gz
|
cc957c1a019702e6cdc2e257202d42799011ebc1968b6c3bcd6b1965952607d5 go1.23.1.freebsd-386.tar.gz
|
||||||
424a5618406800365fe3ad96a795fb55ce394bea3ff48eaf56d292bf7a916d1e go1.22.6.freebsd-amd64.tar.gz
|
a7d57781c50bb80886a8f04066791956d45aa3eea0f83070c5268b6223afb2ff go1.23.1.freebsd-amd64.tar.gz
|
||||||
e0dce3a6dbe8e7e054d329dd4cb403935c63c0f7e22e693077aa60e12018b883 go1.22.6.freebsd-arm.tar.gz
|
c7b09f3fef456048e596db9bea746eb66796aeb82885622b0388feee18f36a3e go1.23.1.freebsd-arm.tar.gz
|
||||||
34930b01f58889c71f7a78c51c6c3bd2ce289ac7862c76dab691303cfa935fd1 go1.22.6.freebsd-arm64.tar.gz
|
b05cd6a77995a0c8439d88df124811c725fb78b942d0b6dd1643529d7ba62f1f go1.23.1.freebsd-arm64.tar.gz
|
||||||
4c9d630e55d4d600a5b4297e59620c3bdfe63a441981682b3638e2fdda228a44 go1.22.6.freebsd-riscv64.tar.gz
|
56236ae70be1613f2915943b94f53c96be5bffc0719314078facd778a89bc57e go1.23.1.freebsd-riscv64.tar.gz
|
||||||
9ed63feaf2ef56c56f1cf0d9d3fab4006efd22a38e2f1f5252e95c6ac09332f3 go1.22.6.illumos-amd64.tar.gz
|
8644c52df4e831202114fd67c9fcaf1f7233ad27bf945ac53fa7217cf1a0349f go1.23.1.illumos-amd64.tar.gz
|
||||||
9e680027b058beab10ce5938607660964b6d2c564bf50bdb01aa090dc5beda98 go1.22.6.linux-386.tar.gz
|
cdee2f4e2efa001f7ee75c90f2efc310b63346cfbba7b549987e9139527c6b17 go1.23.1.linux-386.tar.gz
|
||||||
999805bed7d9039ec3da1a53bfbcafc13e367da52aa823cb60b68ba22d44c616 go1.22.6.linux-amd64.tar.gz
|
49bbb517cfa9eee677e1e7897f7cf9cfdbcf49e05f61984a2789136de359f9bd go1.23.1.linux-amd64.tar.gz
|
||||||
c15fa895341b8eaf7f219fada25c36a610eb042985dc1a912410c1c90098eaf2 go1.22.6.linux-arm64.tar.gz
|
faec7f7f8ae53fda0f3d408f52182d942cc89ef5b7d3d9f23ff117437d4b2d2f go1.23.1.linux-arm64.tar.gz
|
||||||
b566484fe89a54c525dd1a4cbfec903c1f6e8f0b7b3dbaf94c79bc9145391083 go1.22.6.linux-armv6l.tar.gz
|
6c7832c7dcd8fb6d4eb308f672a725393403c74ee7be1aeccd8a443015df99de go1.23.1.linux-armv6l.tar.gz
|
||||||
1ee6e1896aea856142d2af7045cea118995b39404aa61afd12677d023d47ee69 go1.22.6.linux-loong64.tar.gz
|
649ce3856ddc808c00b14a46232eab0bf95e7911cdf497010b17d76656f5ca4e go1.23.1.linux-loong64.tar.gz
|
||||||
fdd0e1a3e178f9bc79adf6ff1e3de4554ce581b4c468fd6e113c43fbbbe1eec6 go1.22.6.linux-mips.tar.gz
|
201911048f234e5a0c51ec94b1a11d4e47062fee4398b1d2faa6c820dc026724 go1.23.1.linux-mips.tar.gz
|
||||||
d3e5a621fc5a07759e503a971af0b28ded6a7d6f5604ab511f51f930a18dd3e4 go1.22.6.linux-mips64.tar.gz
|
2bce3743df463915e45d2612f9476ffb03d0b3750b1cb3879347de08715b5fc6 go1.23.1.linux-mips64.tar.gz
|
||||||
01547606c5b5c1b0e5587b3afd65172860d2f4755e523785832905759ecce2d7 go1.22.6.linux-mips64le.tar.gz
|
54e301f266e33431b0703136e0bbd4cf02461b1ecedd37b7cbd90cb862a98e5f go1.23.1.linux-mips64le.tar.gz
|
||||||
2cd771416ae03c11240cfdb551d66ab9a941077664f3727b966f94386c23b0fa go1.22.6.linux-mipsle.tar.gz
|
8efd495e93d17408c0803595cdc3bf13cb28e0f957aeabd9cc18245fb8e64019 go1.23.1.linux-mipsle.tar.gz
|
||||||
6ef61d517777925e6bdb0321ea42d5f60acc20c1314dd902b9d0bfa3a5fd4fca go1.22.6.linux-ppc64.tar.gz
|
52bd68689095831ad9af7160844c23b28bb8d0acd268de7e300ff5f0662b7a07 go1.23.1.linux-ppc64.tar.gz
|
||||||
9d99fce3f6f72a76630fe91ec0884dfe3db828def4713368424900fa98bb2bd6 go1.22.6.linux-ppc64le.tar.gz
|
042888cae54b5fbfd9dd1e3b6bc4a5134879777fe6497fc4c62ec394b5ecf2da go1.23.1.linux-ppc64le.tar.gz
|
||||||
30be9c9b9cc4f044d4da9a33ee601ab7b3aff4246107d323a79e08888710754e go1.22.6.linux-riscv64.tar.gz
|
1a4a609f0391bea202d9095453cbfaf7368fa88a04c206bf9dd715a738664dc3 go1.23.1.linux-riscv64.tar.gz
|
||||||
82f3bae3ddb4ede45b848db48c5486fadb58551e74507bda45484257e7194a95 go1.22.6.linux-s390x.tar.gz
|
47dc49ad45c45e192efa0df7dc7bc5403f5f2d15b5d0dc74ef3018154b616f4d go1.23.1.linux-s390x.tar.gz
|
||||||
85b2eb9d40a930bd3e75d0096a6eb5847aac86c5085e6d13a5845e9ef03f8d4b go1.22.6.netbsd-386.tar.gz
|
fbfbd5efa6a5d581ea7f5e65015f927db0e52135cab057e43d39d5482da54b61 go1.23.1.netbsd-386.tar.gz
|
||||||
6e9acbdc34fb2a942d547c47c9c1989bb6e32b4a37d57fb312499e2bb33b46b7 go1.22.6.netbsd-amd64.tar.gz
|
e96e1cc5cf36113ee6099d1a7306b22cd9c3f975a36bdff954c59f104f22b853 go1.23.1.netbsd-amd64.tar.gz
|
||||||
e6eff3cf0038f2a9b0c9e01e228577a783bddcd8051222a3d949e24ee392e769 go1.22.6.netbsd-arm.tar.gz
|
c394dfc06bfc276a591209a37e09cd39089ec9a9cc3db30b94814ce2e39eb1d4 go1.23.1.netbsd-arm.tar.gz
|
||||||
43a7e2ba22da700b844f7561e3dd5434540ed6c9781be2e9c42e8a8cbf558f8e go1.22.6.netbsd-arm64.tar.gz
|
b3b35d64f32821a68b3e2994032dbefb81978f2ec3f218c7a770623b82d36b8e go1.23.1.netbsd-arm64.tar.gz
|
||||||
a90b758ccb45d8a17af8e140fafa1e97607de5a7ecd53a4c55f69258bfb043d0 go1.22.6.openbsd-386.tar.gz
|
3c775c4c16c182e33c2c4ac090d9a247a93b3fb18a3df01d87d490f29599faff go1.23.1.openbsd-386.tar.gz
|
||||||
cc13436c4a644e55bedcea65981eb80ca8317b39b129f5563ab3b6da1391bd47 go1.22.6.openbsd-amd64.tar.gz
|
5edbe53b47c57b32707fd7154536fbe9eaa79053fea01650c93b54cdba13fc0f go1.23.1.openbsd-amd64.tar.gz
|
||||||
aee34f61ba2b0a8f2618f5c7065e20da7714ce7651680509eda30728fe01ee88 go1.22.6.openbsd-arm.tar.gz
|
c30903dd8fa98b8aca8e9db0962ce9f55502aed93e0ef41e5ae148aaa0088de1 go1.23.1.openbsd-arm.tar.gz
|
||||||
c67d57daf8baada93c69c8fb02401270cd33159730b1f2d70d9e724ba1a918cf go1.22.6.openbsd-arm64.tar.gz
|
12da183489e58f9c6b357bc1b626f85ed7d4220cab31a49d6a49e6ac6a718b67 go1.23.1.openbsd-arm64.tar.gz
|
||||||
03e1f96002e94a6b381bcf66a0a62b9d5f63148682a780d727840ad540185c7c go1.22.6.openbsd-ppc64.tar.gz
|
9cc9aad37696a4a10c31dcec9e35a308de0b369dad354d54cf07406ac6fa7c6f go1.23.1.openbsd-ppc64.tar.gz
|
||||||
0ac2b5bbe2c8a293d284512630e629bf0578aaa7b7b1f39ac4ee182c7924aaad go1.22.6.plan9-386.tar.gz
|
e1d740dda062ce5a276a0c3ed7d8b6353238bc8ff405f63e2e3480bfd26a5ec5 go1.23.1.openbsd-riscv64.tar.gz
|
||||||
f9afdab8a72a8d874f023f5605482cc94160843ac768dbd840e6f772d16578c7 go1.22.6.plan9-amd64.tar.gz
|
da2a37f9987f01f096859230aa13ecc4ad2e7884465bce91004bc78c64435d65 go1.23.1.plan9-386.tar.gz
|
||||||
4b9f01a47e6a29d57cbb3097b6770583336cef9c8f0d51d3d1451e42a851002e go1.22.6.plan9-arm.tar.gz
|
fd8fff8b0697d55c4a4d02a8dc998192b80a9dc2a057647373d6ff607cad29de go1.23.1.plan9-amd64.tar.gz
|
||||||
46c2552ac7b8d6314a52e14e0a0761aaeebdd6aba5f531de386f4cf2b66ec723 go1.22.6.solaris-amd64.tar.gz
|
52efbc5804c1c86ba7868aa8ebbc31cc8c2a27b62a60fd57944970d48fc67525 go1.23.1.plan9-arm.tar.gz
|
||||||
a57821dab76af1ef7a6b62db1628f0caa74343e0c7cb829df9ce8ea0713a3e8e go1.22.6.windows-386.msi
|
f54205f21e2143f2ada1bf1c00ddf64590f5139d5c3fb77cc06175f0d8cc7567 go1.23.1.solaris-amd64.tar.gz
|
||||||
eb734bacc9aabca1273b61dd392bb84a9bb33783f5e2fff2cd6ab9885bbefbe6 go1.22.6.windows-386.zip
|
369a17f0cfd29e5c848e58ffe0d772da20abe334d1c7ca01dbcd55bb3db0b440 go1.23.1.windows-386.msi
|
||||||
1238a3e6892eb8a0eb3fe0640e18ab82ca21cc1a933f16897b2ad081f057b5da go1.22.6.windows-amd64.msi
|
ab866f47d7be56e6b1c67f1d529bf4c23331a339fb0785f435a0552d352cb257 go1.23.1.windows-386.zip
|
||||||
6023083a6e4d3199b44c37e9ba7b25d9674da20fd846a35ee5f9589d81c21a6a go1.22.6.windows-amd64.zip
|
e99dac215ee437b9bb8f8b14bbfe0e8756882c1ed291f30818e8363bc9c047a5 go1.23.1.windows-amd64.msi
|
||||||
6791218c568a3d000cb36317506541d7fd67e7cfe613baaf361ca36cad5e2cd5 go1.22.6.windows-arm.msi
|
32dedf277c86610e380e1765593edb66876f00223df71690bd6be68ee17675c0 go1.23.1.windows-amd64.zip
|
||||||
ee41ca83bb07c4fd46a1d6b2d083519bb8ca156fcd9db37ee711234d43126e2f go1.22.6.windows-arm.zip
|
23169c79dc6b54e0dffb25be6b67425ad9759392a58309bc057430a9bf4c8f6a go1.23.1.windows-arm.msi
|
||||||
91c6b3376612095315a0aeae4b03e3da34fabe9dfd4532d023e2a70f913cf22a go1.22.6.windows-arm64.msi
|
1a57615a09f13534f88e9f2d7efd5743535d1a5719b19e520eef965a634f8efb go1.23.1.windows-arm.zip
|
||||||
7cf55f357ba8116cd3bff992980e20a704ba451b3dab341cf1787b133d900512 go1.22.6.windows-arm64.zip
|
313e1a543931ad8735b4df8969e00f5f4c2ef07be21f54015ede961a70263d35 go1.23.1.windows-arm64.msi
|
||||||
|
64ad0954d2c33f556fb1018d62de091254aa6e3a94f1c8a8b16af0d3701d194e go1.23.1.windows-arm64.zip
|
||||||
|
|
||||||
# version:golangci 1.59.0
|
# version:golangci 1.59.0
|
||||||
# https://github.com/golangci/golangci-lint/releases/
|
# 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
|
"focal", // 20.04, EOL: 04/2030
|
||||||
"jammy", // 22.04, EOL: 04/2032
|
"jammy", // 22.04, EOL: 04/2032
|
||||||
"noble", // 24.04, EOL: 04/2034
|
"noble", // 24.04, EOL: 04/2034
|
||||||
|
|
||||||
"mantic", // 23.10, EOL: 07/2024
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is where the tests should be unpacked.
|
// This is where the tests should be unpacked.
|
||||||
|
@ -239,6 +237,10 @@ func doInstall(cmdline []string) {
|
||||||
// buildFlags returns the go tool flags for building.
|
// buildFlags returns the go tool flags for building.
|
||||||
func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) {
|
func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) {
|
||||||
var ld []string
|
var ld []string
|
||||||
|
// 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 != "" {
|
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.gitCommit="+env.Commit)
|
||||||
ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitDate="+env.Date)
|
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" {
|
if runtime.GOOS == "linux" {
|
||||||
// Enforce the stacksize to 8M, which is the case on most platforms apart from
|
// Enforce the stacksize to 8M, which is the case on most platforms apart from
|
||||||
// alpine Linux.
|
// 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 {
|
if staticLinking {
|
||||||
extld = append(extld, "-static")
|
extld = append(extld, "-static")
|
||||||
// Under static linking, use of certain glibc features must be
|
// Under static linking, use of certain glibc features must be
|
||||||
|
@ -298,7 +304,7 @@ func doTest(cmdline []string) {
|
||||||
gotest := tc.Go("test")
|
gotest := tc.Go("test")
|
||||||
|
|
||||||
// CI needs a bit more time for the statetests (default 10m).
|
// 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.
|
// Enable CKZG backend in CI.
|
||||||
gotest.Args = append(gotest.Args, "-tags=ckzg")
|
gotest.Args = append(gotest.Args, "-tags=ckzg")
|
||||||
|
@ -349,10 +355,10 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
|
||||||
return filepath.Join(cachedir, base)
|
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
|
// computing the hash of each file (excluding files within the tests
|
||||||
// subrepo)
|
// subrepo)
|
||||||
func hashSourceFiles() (map[string]common.Hash, error) {
|
func hashAllSourceFiles() (map[string]common.Hash, error) {
|
||||||
res := make(map[string]common.Hash)
|
res := make(map[string]common.Hash)
|
||||||
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
|
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
|
||||||
if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) {
|
if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) {
|
||||||
|
@ -379,6 +385,56 @@ func hashSourceFiles() (map[string]common.Hash, error) {
|
||||||
return res, nil
|
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
|
// doGenerate ensures that re-generating generated files does not cause
|
||||||
// any mutations in the source file tree: i.e. all generated files were
|
// any mutations in the source file tree: i.e. all generated files were
|
||||||
// updated and committed. Any stale generated files are updated.
|
// updated and committed. Any stale generated files are updated.
|
||||||
|
@ -395,7 +451,7 @@ func doGenerate() {
|
||||||
var preHashes map[string]common.Hash
|
var preHashes map[string]common.Hash
|
||||||
if *verify {
|
if *verify {
|
||||||
var err error
|
var err error
|
||||||
preHashes, err = hashSourceFiles()
|
preHashes, err = hashAllSourceFiles()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("failed to compute map of source hashes", "err", err)
|
log.Fatal("failed to compute map of source hashes", "err", err)
|
||||||
}
|
}
|
||||||
|
@ -410,17 +466,11 @@ func doGenerate() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Check if files were changed.
|
// Check if files were changed.
|
||||||
postHashes, err := hashSourceFiles()
|
postHashes, err := hashAllSourceFiles()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("error computing source tree file hashes", "err", err)
|
log.Fatal("error computing source tree file hashes", "err", err)
|
||||||
}
|
}
|
||||||
updates := []string{}
|
updates := compareHashedFilesets(preHashes, postHashes)
|
||||||
for path, postHash := range postHashes {
|
|
||||||
preHash, ok := preHashes[path]
|
|
||||||
if !ok || preHash != postHash {
|
|
||||||
updates = append(updates, path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, updatedFile := range updates {
|
for _, updatedFile := range updates {
|
||||||
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
|
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
|
||||||
}
|
}
|
||||||
|
@ -443,6 +493,8 @@ func doLint(cmdline []string) {
|
||||||
linter := downloadLinter(*cachedir)
|
linter := downloadLinter(*cachedir)
|
||||||
lflags := []string{"run", "--config", ".golangci.yml"}
|
lflags := []string{"run", "--config", ".golangci.yml"}
|
||||||
build.MustRunCommandWithOutput(linter, append(lflags, packages...)...)
|
build.MustRunCommandWithOutput(linter, append(lflags, packages...)...)
|
||||||
|
|
||||||
|
doGoModTidy()
|
||||||
fmt.Println("You have achieved perfection.")
|
fmt.Println("You have achieved perfection.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,6 @@ func main() {
|
||||||
//TODO datadir for optional permanent database
|
//TODO datadir for optional permanent database
|
||||||
utils.MainnetFlag,
|
utils.MainnetFlag,
|
||||||
utils.SepoliaFlag,
|
utils.SepoliaFlag,
|
||||||
utils.GoerliFlag,
|
|
||||||
utils.BlsyncApiFlag,
|
utils.BlsyncApiFlag,
|
||||||
utils.BlsyncJWTSecretFlag,
|
utils.BlsyncJWTSecretFlag,
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,7 +29,7 @@ GLOBAL OPTIONS:
|
||||||
--loglevel value log level to emit to the screen (default: 4)
|
--loglevel value log level to emit to the screen (default: 4)
|
||||||
--keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore")
|
--keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore")
|
||||||
--configdir value Directory for Clef configuration (default: "$HOME/.clef")
|
--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
|
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
|
||||||
--nousb Disables monitoring for and managing USB hardware wallets
|
--nousb Disables monitoring for and managing USB hardware wallets
|
||||||
--pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")
|
--pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")
|
||||||
|
|
|
@ -100,7 +100,7 @@ var (
|
||||||
chainIdFlag = &cli.Int64Flag{
|
chainIdFlag = &cli.Int64Flag{
|
||||||
Name: "chainid",
|
Name: "chainid",
|
||||||
Value: params.MainnetChainConfig.ChainID.Int64(),
|
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{
|
rpcPortFlag = &cli.IntFlag{
|
||||||
Name: "http.port",
|
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
|
- `-limit <N>` limits the output set to N entries, taking the top N nodes by score
|
||||||
- `-ip <CIDR>` filters nodes by IP subnet
|
- `-ip <CIDR>` filters nodes by IP subnet
|
||||||
- `-min-age <duration>` filters nodes by 'first seen' time
|
- `-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
|
- `-les-server` filters nodes by LES server support
|
||||||
- `-snap` filters nodes by snap protocol 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) {
|
if !strings.HasSuffix(name, "."+zone.Name) {
|
||||||
return fmt.Errorf("CloudFlare zone name %q does not match name %q to be deployed", zone.Name, 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 {
|
for _, perm := range zone.Permissions {
|
||||||
if _, ok := needPerms[perm]; ok {
|
if _, ok := needPerms[perm]; ok {
|
||||||
needPerms[perm] = true
|
needPerms[perm] = true
|
||||||
|
|
|
@ -849,8 +849,17 @@ func (s *Suite) TestBlobViolations(t *utesting.T) {
|
||||||
if code, _, err := conn.Read(); err != nil {
|
if code, _, err := conn.Read(); err != nil {
|
||||||
t.Fatalf("expected disconnect on blob violation, got err: %v", err)
|
t.Fatalf("expected disconnect on blob violation, got err: %v", err)
|
||||||
} else if code != discMsg {
|
} else if code != discMsg {
|
||||||
|
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)
|
t.Fatalf("expected disconnect on blob violation, got msg code: %d", code)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,8 +230,6 @@ func ethFilter(args []string) (nodeFilter, error) {
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "mainnet":
|
case "mainnet":
|
||||||
filter = forkid.NewStaticFilter(params.MainnetChainConfig, core.DefaultGenesisBlock().ToBlock())
|
filter = forkid.NewStaticFilter(params.MainnetChainConfig, core.DefaultGenesisBlock().ToBlock())
|
||||||
case "goerli":
|
|
||||||
filter = forkid.NewStaticFilter(params.GoerliChainConfig, core.DefaultGoerliGenesisBlock().ToBlock())
|
|
||||||
case "sepolia":
|
case "sepolia":
|
||||||
filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock())
|
filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock())
|
||||||
case "holesky":
|
case "holesky":
|
||||||
|
|
|
@ -66,6 +66,8 @@ type ExecutionResult struct {
|
||||||
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
|
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
|
||||||
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
||||||
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
|
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
|
||||||
|
RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
|
||||||
|
DepositRequests *types.Deposits `json:"depositRequests,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ommer struct {
|
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)
|
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
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++ {
|
for i := 0; txIt.Next(); i++ {
|
||||||
tx, err := txIt.Tx()
|
tx, err := txIt.Tx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -370,9 +379,31 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
|
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
|
||||||
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
|
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
|
// Re-create statedb instance with new root upon the updated database
|
||||||
// for accessing latest states.
|
// for accessing latest states.
|
||||||
statedb, err = state.New(root, statedb.Database(), nil)
|
statedb, err = state.New(root, statedb.Database())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
|
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
|
||||||
}
|
}
|
||||||
|
@ -381,8 +412,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
|
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
|
||||||
sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
||||||
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
|
sdb := state.NewDatabase(tdb, nil)
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, sdb)
|
||||||
for addr, a := range accounts {
|
for addr, a := range accounts {
|
||||||
statedb.SetCode(addr, a.Code)
|
statedb.SetCode(addr, a.Code)
|
||||||
statedb.SetNonce(addr, a.Nonce)
|
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.
|
// Commit and re-open to start with a clean state.
|
||||||
root, _ := statedb.Commit(0, false)
|
root, _ := statedb.Commit(0, false)
|
||||||
statedb, _ = state.New(root, sdb, nil)
|
statedb, _ = state.New(root, sdb)
|
||||||
return statedb
|
return statedb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,8 +155,8 @@ func runCmd(ctx *cli.Context) error {
|
||||||
})
|
})
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
genesis := genesisConfig.MustCommit(db, triedb)
|
genesis := genesisConfig.MustCommit(db, triedb)
|
||||||
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
sdb := state.NewDatabase(triedb, nil)
|
||||||
statedb, _ = state.New(genesis.Root(), sdb, nil)
|
statedb, _ = state.New(genesis.Root(), sdb)
|
||||||
chainConfig = genesisConfig.Config
|
chainConfig = genesisConfig.Config
|
||||||
|
|
||||||
if ctx.String(SenderFlag.Name) != "" {
|
if ctx.String(SenderFlag.Name) != "" {
|
||||||
|
@ -277,7 +277,7 @@ func runCmd(ctx *cli.Context) error {
|
||||||
fmt.Printf("Failed to commit changes %v\n", err)
|
fmt.Printf("Failed to commit changes %v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dumpdb, err := state.New(root, sdb, nil)
|
dumpdb, err := state.New(root, sdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to open statedb %v\n", err)
|
fmt.Printf("Failed to open statedb %v\n", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -107,7 +107,7 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error {
|
||||||
result.Root = &root
|
result.Root = &root
|
||||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||||
if dump { // Dump any state to aid debugging
|
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)
|
dump := cpy.RawDump(nil)
|
||||||
result.State = &dump
|
result.State = &dump
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,8 +425,6 @@ func importHistory(ctx *cli.Context) error {
|
||||||
network = "mainnet"
|
network = "mainnet"
|
||||||
case ctx.Bool(utils.SepoliaFlag.Name):
|
case ctx.Bool(utils.SepoliaFlag.Name):
|
||||||
network = "sepolia"
|
network = "sepolia"
|
||||||
case ctx.Bool(utils.GoerliFlag.Name):
|
|
||||||
network = "goerli"
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No network flag set, try to determine network based on files
|
// 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
|
triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup
|
||||||
defer triedb.Close()
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,8 @@ var tomlSettings = toml.Config{
|
||||||
},
|
},
|
||||||
MissingField: func(rt reflect.Type, field string) error {
|
MissingField: func(rt reflect.Type, field string) error {
|
||||||
id := fmt.Sprintf("%s.%s", rt.String(), field)
|
id := fmt.Sprintf("%s.%s", rt.String(), field)
|
||||||
if deprecated(id) {
|
if deprecatedConfigFields[id] {
|
||||||
log.Warn("Config field is deprecated and won't have an effect", "name", id)
|
log.Warn(fmt.Sprintf("Config field '%s' is deprecated and won't have any effect.", id))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var link string
|
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 {
|
type ethstatsConfig struct {
|
||||||
URL string `toml:",omitempty"`
|
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 {
|
func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error {
|
||||||
scryptN := keystore.StandardScryptN
|
scryptN := keystore.StandardScryptN
|
||||||
scryptP := keystore.StandardScryptP
|
scryptP := keystore.StandardScryptP
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
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"
|
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
|
// memory and disk IO. If the args don't set --datadir, the
|
||||||
// child g gets a temporary data directory.
|
// child g gets a temporary data directory.
|
||||||
func runMinimalGeth(t *testing.T, args ...string) *testgeth {
|
func runMinimalGeth(t *testing.T, args ...string) *testgeth {
|
||||||
// --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
|
// --networkid=1337 to avoid cache bump
|
||||||
// --syncmode=full to avoid allocating fast sync bloom
|
// --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",
|
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
|
||||||
"--datadir.minfreedisk", "0"}
|
"--datadir.minfreedisk", "0"}
|
||||||
return runGeth(t, append(allArgs, args...)...)
|
return runGeth(t, append(allArgs, args...)...)
|
||||||
|
@ -62,7 +62,7 @@ func TestConsoleWelcome(t *testing.T) {
|
||||||
geth.SetTemplateFunc("gover", runtime.Version)
|
geth.SetTemplateFunc("gover", runtime.Version)
|
||||||
geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
||||||
geth.SetTemplateFunc("niltime", func() string {
|
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 })
|
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("gover", runtime.Version)
|
||||||
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
||||||
attach.SetTemplateFunc("niltime", func() string {
|
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("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
|
||||||
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
|
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
|
||||||
|
|
|
@ -289,9 +289,6 @@ func main() {
|
||||||
func prepare(ctx *cli.Context) {
|
func prepare(ctx *cli.Context) {
|
||||||
// If we're running a known preset, log it for convenience.
|
// If we're running a known preset, log it for convenience.
|
||||||
switch {
|
switch {
|
||||||
case ctx.IsSet(utils.GoerliFlag.Name):
|
|
||||||
log.Info("Starting Geth on Görli testnet...")
|
|
||||||
|
|
||||||
case ctx.IsSet(utils.SepoliaFlag.Name):
|
case ctx.IsSet(utils.SepoliaFlag.Name):
|
||||||
log.Info("Starting Geth on Sepolia testnet...")
|
log.Info("Starting Geth on Sepolia testnet...")
|
||||||
|
|
||||||
|
@ -324,7 +321,6 @@ func prepare(ctx *cli.Context) {
|
||||||
// Make sure we're not on any supported preconfigured testnet either
|
// Make sure we're not on any supported preconfigured testnet either
|
||||||
if !ctx.IsSet(utils.HoleskyFlag.Name) &&
|
if !ctx.IsSet(utils.HoleskyFlag.Name) &&
|
||||||
!ctx.IsSet(utils.SepoliaFlag.Name) &&
|
!ctx.IsSet(utils.SepoliaFlag.Name) &&
|
||||||
!ctx.IsSet(utils.GoerliFlag.Name) &&
|
|
||||||
!ctx.IsSet(utils.DeveloperFlag.Name) {
|
!ctx.IsSet(utils.DeveloperFlag.Name) {
|
||||||
// Nope, we're really on mainnet. Bump that cache up!
|
// Nope, we're really on mainnet. Bump that cache up!
|
||||||
log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
|
log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
|
||||||
|
|
|
@ -262,7 +262,6 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
reported = time.Now()
|
reported = time.Now()
|
||||||
imported = 0
|
imported = 0
|
||||||
forker = core.NewForkChoice(chain, nil)
|
|
||||||
h = sha256.New()
|
h = sha256.New()
|
||||||
buf = bytes.NewBuffer(nil)
|
buf = bytes.NewBuffer(nil)
|
||||||
)
|
)
|
||||||
|
@ -305,7 +304,7 @@ func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, networ
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error reading receipts %d: %w", it.Number(), err)
|
return fmt.Errorf("error reading receipts %d: %w", it.Number(), err)
|
||||||
}
|
}
|
||||||
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)
|
return fmt.Errorf("error inserting header %d: %w", it.Number(), err)
|
||||||
} else if status != core.CanonStatTy {
|
} else if status != core.CanonStatTy {
|
||||||
return fmt.Errorf("error inserting header %d, not canon: %v", it.Number(), status)
|
return fmt.Errorf("error inserting header %d, not canon: %v", it.Number(), status)
|
||||||
|
|
|
@ -134,7 +134,7 @@ var (
|
||||||
}
|
}
|
||||||
NetworkIdFlag = &cli.Uint64Flag{
|
NetworkIdFlag = &cli.Uint64Flag{
|
||||||
Name: "networkid",
|
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,
|
Value: ethconfig.Defaults.NetworkId,
|
||||||
Category: flags.EthCategory,
|
Category: flags.EthCategory,
|
||||||
}
|
}
|
||||||
|
@ -143,11 +143,6 @@ var (
|
||||||
Usage: "Ethereum mainnet",
|
Usage: "Ethereum mainnet",
|
||||||
Category: flags.EthCategory,
|
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{
|
SepoliaFlag = &cli.BoolFlag{
|
||||||
Name: "sepolia",
|
Name: "sepolia",
|
||||||
Usage: "Sepolia network: pre-configured proof-of-work test network",
|
Usage: "Sepolia network: pre-configured proof-of-work test network",
|
||||||
|
@ -812,8 +807,9 @@ var (
|
||||||
DiscoveryV5Flag = &cli.BoolFlag{
|
DiscoveryV5Flag = &cli.BoolFlag{
|
||||||
Name: "discovery.v5",
|
Name: "discovery.v5",
|
||||||
Aliases: []string{"discv5"},
|
Aliases: []string{"discv5"},
|
||||||
Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
|
Usage: "Enables the V5 discovery mechanism",
|
||||||
Category: flags.NetworkingCategory,
|
Category: flags.NetworkingCategory,
|
||||||
|
Value: true,
|
||||||
}
|
}
|
||||||
NetrestrictFlag = &cli.StringFlag{
|
NetrestrictFlag = &cli.StringFlag{
|
||||||
Name: "netrestrict",
|
Name: "netrestrict",
|
||||||
|
@ -965,7 +961,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
||||||
var (
|
var (
|
||||||
// TestnetFlags is the flag group of all built-in supported testnets.
|
// TestnetFlags is the flag group of all built-in supported testnets.
|
||||||
TestnetFlags = []cli.Flag{
|
TestnetFlags = []cli.Flag{
|
||||||
GoerliFlag,
|
|
||||||
SepoliaFlag,
|
SepoliaFlag,
|
||||||
HoleskyFlag,
|
HoleskyFlag,
|
||||||
}
|
}
|
||||||
|
@ -988,9 +983,6 @@ var (
|
||||||
// then a subdirectory of the specified datadir will be used.
|
// then a subdirectory of the specified datadir will be used.
|
||||||
func MakeDataDir(ctx *cli.Context) string {
|
func MakeDataDir(ctx *cli.Context) string {
|
||||||
if path := ctx.String(DataDirFlag.Name); path != "" {
|
if path := ctx.String(DataDirFlag.Name); path != "" {
|
||||||
if ctx.Bool(GoerliFlag.Name) {
|
|
||||||
return filepath.Join(path, "goerli")
|
|
||||||
}
|
|
||||||
if ctx.Bool(SepoliaFlag.Name) {
|
if ctx.Bool(SepoliaFlag.Name) {
|
||||||
return filepath.Join(path, "sepolia")
|
return filepath.Join(path, "sepolia")
|
||||||
}
|
}
|
||||||
|
@ -1042,7 +1034,7 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
|
||||||
//
|
//
|
||||||
// 1. --bootnodes flag
|
// 1. --bootnodes flag
|
||||||
// 2. Config file
|
// 2. Config file
|
||||||
// 3. Network preset flags (e.g. --goerli)
|
// 3. Network preset flags (e.g. --holesky)
|
||||||
// 4. default to mainnet nodes
|
// 4. default to mainnet nodes
|
||||||
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
|
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
|
||||||
urls := params.MainnetBootnodes
|
urls := params.MainnetBootnodes
|
||||||
|
@ -1057,8 +1049,6 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
|
||||||
urls = params.HoleskyBootnodes
|
urls = params.HoleskyBootnodes
|
||||||
case ctx.Bool(SepoliaFlag.Name):
|
case ctx.Bool(SepoliaFlag.Name):
|
||||||
urls = params.SepoliaBootnodes
|
urls = params.SepoliaBootnodes
|
||||||
case ctx.Bool(GoerliFlag.Name):
|
|
||||||
urls = params.GoerliBootnodes
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cfg.BootstrapNodes = mustParseBootnodes(urls)
|
cfg.BootstrapNodes = mustParseBootnodes(urls)
|
||||||
|
@ -1484,8 +1474,6 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) {
|
||||||
cfg.DataDir = ctx.String(DataDirFlag.Name)
|
cfg.DataDir = ctx.String(DataDirFlag.Name)
|
||||||
case ctx.Bool(DeveloperFlag.Name):
|
case ctx.Bool(DeveloperFlag.Name):
|
||||||
cfg.DataDir = "" // unless explicitly requested, use memory databases
|
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():
|
case ctx.Bool(SepoliaFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||||
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia")
|
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia")
|
||||||
case ctx.Bool(HoleskyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
case ctx.Bool(HoleskyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||||
|
@ -1657,7 +1645,7 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) {
|
||||||
// SetEthConfig applies eth-related command line flags to the config.
|
// SetEthConfig applies eth-related command line flags to the config.
|
||||||
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
// Avoid conflicting network flags
|
// 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
|
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
|
||||||
|
|
||||||
// Set configurations from CLI flags
|
// Set configurations from CLI flags
|
||||||
|
@ -1827,12 +1815,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
}
|
}
|
||||||
cfg.Genesis = core.DefaultSepoliaGenesisBlock()
|
cfg.Genesis = core.DefaultSepoliaGenesisBlock()
|
||||||
SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash)
|
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):
|
case ctx.Bool(DeveloperFlag.Name):
|
||||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||||
cfg.NetworkId = 1337
|
cfg.NetworkId = 1337
|
||||||
|
@ -2154,8 +2136,6 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
|
||||||
genesis = core.DefaultHoleskyGenesisBlock()
|
genesis = core.DefaultHoleskyGenesisBlock()
|
||||||
case ctx.Bool(SepoliaFlag.Name):
|
case ctx.Bool(SepoliaFlag.Name):
|
||||||
genesis = core.DefaultSepoliaGenesisBlock()
|
genesis = core.DefaultSepoliaGenesisBlock()
|
||||||
case ctx.Bool(GoerliFlag.Name):
|
|
||||||
genesis = core.DefaultGoerliGenesisBlock()
|
|
||||||
case ctx.Bool(DeveloperFlag.Name):
|
case ctx.Bool(DeveloperFlag.Name):
|
||||||
Fatalf("Developer chains are ephemeral")
|
Fatalf("Developer chains are ephemeral")
|
||||||
}
|
}
|
||||||
|
@ -2230,7 +2210,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Disable transaction indexing/unindexing by default.
|
// 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 {
|
if err != nil {
|
||||||
Fatalf("Can't create BlockChain: %v", err)
|
Fatalf("Can't create BlockChain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,25 +92,21 @@ var (
|
||||||
LightServeFlag = &cli.IntFlag{
|
LightServeFlag = &cli.IntFlag{
|
||||||
Name: "light.serve",
|
Name: "light.serve",
|
||||||
Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)",
|
Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)",
|
||||||
Value: ethconfig.Defaults.LightServ,
|
|
||||||
Category: flags.DeprecatedCategory,
|
Category: flags.DeprecatedCategory,
|
||||||
}
|
}
|
||||||
LightIngressFlag = &cli.IntFlag{
|
LightIngressFlag = &cli.IntFlag{
|
||||||
Name: "light.ingress",
|
Name: "light.ingress",
|
||||||
Usage: "Incoming bandwidth limit for serving light clients (deprecated)",
|
Usage: "Incoming bandwidth limit for serving light clients (deprecated)",
|
||||||
Value: ethconfig.Defaults.LightIngress,
|
|
||||||
Category: flags.DeprecatedCategory,
|
Category: flags.DeprecatedCategory,
|
||||||
}
|
}
|
||||||
LightEgressFlag = &cli.IntFlag{
|
LightEgressFlag = &cli.IntFlag{
|
||||||
Name: "light.egress",
|
Name: "light.egress",
|
||||||
Usage: "Outgoing bandwidth limit for serving light clients (deprecated)",
|
Usage: "Outgoing bandwidth limit for serving light clients (deprecated)",
|
||||||
Value: ethconfig.Defaults.LightEgress,
|
|
||||||
Category: flags.DeprecatedCategory,
|
Category: flags.DeprecatedCategory,
|
||||||
}
|
}
|
||||||
LightMaxPeersFlag = &cli.IntFlag{
|
LightMaxPeersFlag = &cli.IntFlag{
|
||||||
Name: "light.maxpeers",
|
Name: "light.maxpeers",
|
||||||
Usage: "Maximum number of light clients to serve, or light servers to attach to (deprecated)",
|
Usage: "Maximum number of light clients to serve, or light servers to attach to (deprecated)",
|
||||||
Value: ethconfig.Defaults.LightPeers,
|
|
||||||
Category: flags.DeprecatedCategory,
|
Category: flags.DeprecatedCategory,
|
||||||
}
|
}
|
||||||
LightNoPruneFlag = &cli.BoolFlag{
|
LightNoPruneFlag = &cli.BoolFlag{
|
||||||
|
|
|
@ -78,7 +78,7 @@ func TestHistoryImportAndExport(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Initialize BlockChain.
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("unable to initialize chain: %v", err)
|
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))
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("unable to initialize chain: %v", err)
|
t.Fatalf("unable to initialize chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,8 +387,39 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||||
// Assign the final state root to header.
|
// Assign the final state root to header.
|
||||||
header.Root = state.IntermediateRoot(true)
|
header.Root = state.IntermediateRoot(true)
|
||||||
|
|
||||||
// Assemble and return the final block.
|
// Assemble the final block.
|
||||||
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil
|
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
|
// 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.
|
// 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
|
// In Clique PoA networks, consecutive blocks might have the same state root (no
|
||||||
// the same state root (no block subsidy, empty block). If a node crashes, the
|
// block subsidy, empty block). If a node crashes, the chain ends up losing the
|
||||||
// chain ends up losing the recent state and needs to regenerate it from blocks
|
// recent state and needs to regenerate it from blocks already in the database.
|
||||||
// already in the database. The bug was that processing the block *prior* to an
|
// The bug was that processing the block *prior* to an empty one **also
|
||||||
// empty one **also completes** the empty one, ending up in a known-block error.
|
// completes** the empty one, ending up in a known-block error.
|
||||||
func TestReimportMirroredState(t *testing.T) {
|
func TestReimportMirroredState(t *testing.T) {
|
||||||
// Initialize a Clique chain with a single signer
|
// Initialize a Clique chain with a single signer
|
||||||
var (
|
var (
|
||||||
|
@ -55,7 +55,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
copy(genspec.ExtraData[extraVanity:], addr[:])
|
copy(genspec.ExtraData[extraVanity:], addr[:])
|
||||||
|
|
||||||
// Generate a batch of blocks, each properly signed
|
// 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()
|
defer chain.Stop()
|
||||||
|
|
||||||
_, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) {
|
_, 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
|
// Insert the first two blocks and make sure the chain is valid
|
||||||
db = rawdb.NewMemoryDatabase()
|
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()
|
defer chain.Stop()
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[:2]); err != nil {
|
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
|
// 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
|
// flushing the dirty states out. Insert the last block, triggering a sidechain
|
||||||
// reimport.
|
// 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()
|
defer chain.Stop()
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[2:]); err != nil {
|
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)
|
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
||||||
}
|
}
|
||||||
// Pass all the headers through clique and ensure tallying succeeds
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create test chain: %v", err)
|
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.
|
// Time the insertion of the new chain.
|
||||||
// State and blocks are stored in the same DB.
|
// 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()
|
defer chainman.Stop()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
@ -312,7 +312,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
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 {
|
if err != nil {
|
||||||
b.Fatalf("error creating chain: %v", err)
|
b.Fatalf("error creating chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,14 +121,17 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
|
|
||||||
// ValidateState validates the various changes that happen after a state transition,
|
// 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.
|
// 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()
|
header := block.Header()
|
||||||
if block.GasUsed() != usedGas {
|
if block.GasUsed() != res.GasUsed {
|
||||||
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
|
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.
|
// Validate the received block's bloom with the one derived from the generated receipts.
|
||||||
// For valid blocks this should always validate to true.
|
// For valid blocks this should always validate to true.
|
||||||
rbloom := types.CreateBloom(receipts)
|
rbloom := types.CreateBloom(res.Receipts)
|
||||||
if rbloom != header.Bloom {
|
if rbloom != header.Bloom {
|
||||||
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
||||||
}
|
}
|
||||||
|
@ -138,10 +141,17 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
|
// 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 {
|
if receiptSha != header.ReceiptHash {
|
||||||
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
|
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
|
// Validate the state root against the received state root and throw
|
||||||
// an error if they don't match.
|
// an error if they don't match.
|
||||||
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
||||||
|
|
|
@ -50,7 +50,7 @@ func testHeaderVerification(t *testing.T, scheme string) {
|
||||||
headers[i] = block.Header()
|
headers[i] = block.Header()
|
||||||
}
|
}
|
||||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
// 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()
|
defer chain.Stop()
|
||||||
|
|
||||||
for i := 0; i < len(blocks); i++ {
|
for i := 0; i < len(blocks); i++ {
|
||||||
|
@ -160,7 +160,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
|
||||||
postHeaders[i] = block.Header()
|
postHeaders[i] = block.Header()
|
||||||
}
|
}
|
||||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
// 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()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Verify the blocks before the merging
|
// Verify the blocks before the merging
|
||||||
|
|
|
@ -72,10 +72,10 @@ var (
|
||||||
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
||||||
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
||||||
|
|
||||||
snapshotAccountReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/account/reads", nil)
|
accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil)
|
||||||
snapshotStorageReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/storage/reads", nil)
|
storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil)
|
||||||
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
|
|
||||||
|
|
||||||
|
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
|
||||||
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
|
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
|
||||||
|
|
||||||
blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil)
|
blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil)
|
||||||
|
@ -217,7 +217,7 @@ type BlockChain struct {
|
||||||
lastWrite uint64 // Last block when the state was flushed
|
lastWrite uint64 // Last block when the state was flushed
|
||||||
flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state
|
flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state
|
||||||
triedb *triedb.Database // The database handler for maintaining trie nodes.
|
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
|
txIndexer *txIndexer // Transaction indexer, might be nil if not enabled
|
||||||
|
|
||||||
hc *HeaderChain
|
hc *HeaderChain
|
||||||
|
@ -256,7 +256,6 @@ type BlockChain struct {
|
||||||
validator Validator // Block and state validator interface
|
validator Validator // Block and state validator interface
|
||||||
prefetcher Prefetcher
|
prefetcher Prefetcher
|
||||||
processor Processor // Block transaction processor interface
|
processor Processor // Block transaction processor interface
|
||||||
forker *ForkChoice
|
|
||||||
vmConfig vm.Config
|
vmConfig vm.Config
|
||||||
logger *tracing.Hooks
|
logger *tracing.Hooks
|
||||||
}
|
}
|
||||||
|
@ -264,7 +263,7 @@ type BlockChain struct {
|
||||||
// NewBlockChain returns a fully initialised block chain using information
|
// NewBlockChain returns a fully initialised block chain using information
|
||||||
// available in the database. It initialises the default Ethereum Validator
|
// available in the database. It initialises the default Ethereum Validator
|
||||||
// and Processor.
|
// 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 {
|
if cacheConfig == nil {
|
||||||
cacheConfig = defaultCacheConfig
|
cacheConfig = defaultCacheConfig
|
||||||
}
|
}
|
||||||
|
@ -309,8 +308,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
||||||
bc.forker = NewForkChoice(bc, shouldPreserve)
|
bc.statedb = state.NewDatabase(bc.triedb, nil)
|
||||||
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
|
||||||
bc.validator = NewBlockValidator(chainConfig, bc)
|
bc.validator = NewBlockValidator(chainConfig, bc)
|
||||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
||||||
bc.processor = NewStateProcessor(chainConfig, bc.hc)
|
bc.processor = NewStateProcessor(chainConfig, bc.hc)
|
||||||
|
@ -448,7 +446,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||||
AsyncBuild: !bc.cacheConfig.SnapshotWait,
|
AsyncBuild: !bc.cacheConfig.SnapshotWait,
|
||||||
}
|
}
|
||||||
bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root)
|
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.
|
// Rewind the chain in case of an incompatible config upgrade.
|
||||||
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
||||||
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
|
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
|
||||||
|
@ -1240,13 +1242,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
|
|
||||||
// Rewind may have occurred, skip in that case.
|
// Rewind may have occurred, skip in that case.
|
||||||
if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 {
|
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())
|
rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
|
||||||
bc.currentSnapBlock.Store(head.Header())
|
bc.currentSnapBlock.Store(head.Header())
|
||||||
headFastBlockGauge.Update(int64(head.NumberU64()))
|
headFastBlockGauge.Update(int64(head.NumberU64()))
|
||||||
|
@ -1545,26 +1540,17 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
|
||||||
return NonStatTy, err
|
return NonStatTy, err
|
||||||
}
|
}
|
||||||
currentBlock := bc.CurrentBlock()
|
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
|
// Reorganise the chain if the parent is not the head block
|
||||||
if block.ParentHash() != currentBlock.Hash() {
|
if block.ParentHash() != currentBlock.Hash() {
|
||||||
if err := bc.reorg(currentBlock, block); err != nil {
|
if err := bc.reorg(currentBlock, block); err != nil {
|
||||||
return NonStatTy, err
|
return NonStatTy, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status = CanonStatTy
|
|
||||||
} else {
|
|
||||||
status = SideStatTy
|
|
||||||
}
|
|
||||||
// Set new head.
|
// Set new head.
|
||||||
if status == CanonStatTy {
|
|
||||||
bc.writeHeadBlock(block)
|
bc.writeHeadBlock(block)
|
||||||
}
|
|
||||||
if status == CanonStatTy {
|
|
||||||
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
|
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
|
||||||
if len(logs) > 0 {
|
if len(logs) > 0 {
|
||||||
bc.logsFeed.Send(logs)
|
bc.logsFeed.Send(logs)
|
||||||
|
@ -1577,10 +1563,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
|
||||||
if emitHeadEvent {
|
if emitHeadEvent {
|
||||||
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
|
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
|
||||||
}
|
}
|
||||||
} else {
|
return CanonStatTy, nil
|
||||||
bc.chainSideFeed.Send(ChainSideEvent{Block: block})
|
|
||||||
}
|
|
||||||
return status, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertChain attempts to insert the given batch of blocks in to the canonical
|
// InsertChain attempts to insert the given batch of blocks in to the canonical
|
||||||
|
@ -1631,7 +1614,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||||
if bc.insertStopped() {
|
if bc.insertStopped() {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
|
// 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)
|
SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain)
|
||||||
|
|
||||||
|
@ -1664,25 +1646,11 @@ 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
|
// 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.
|
// from the canonical chain, which has not been verified.
|
||||||
// Skip all known blocks that are behind us.
|
// Skip all known blocks that are behind us.
|
||||||
var (
|
current := bc.CurrentBlock()
|
||||||
reorg bool
|
|
||||||
current = bc.CurrentBlock()
|
|
||||||
)
|
|
||||||
for block != nil && bc.skipBlock(err, it) {
|
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() {
|
if block.NumberU64() > current.Number.Uint64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
|
||||||
log.Debug("Ignoring already known block", "number", block.Number(), "hash", block.Hash())
|
log.Debug("Ignoring already known block", "number", block.Number(), "hash", block.Hash())
|
||||||
stats.ignored++
|
stats.ignored++
|
||||||
|
|
||||||
|
@ -1800,7 +1768,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
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 {
|
if err != nil {
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
|
@ -1826,7 +1794,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||||
var followupInterrupt atomic.Bool
|
var followupInterrupt atomic.Bool
|
||||||
if !bc.cacheConfig.TrieCleanNoPrefetch {
|
if !bc.cacheConfig.TrieCleanNoPrefetch {
|
||||||
if followup, err := it.peek(); followup != nil && err == nil {
|
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) {
|
go func(start time.Time, followup *types.Block, throwaway *state.StateDB) {
|
||||||
// Disable tracing for prefetcher executions.
|
// Disable tracing for prefetcher executions.
|
||||||
|
@ -1924,23 +1892,23 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||||
|
|
||||||
// Process block using the parent state as reference point
|
// Process block using the parent state as reference point
|
||||||
pstart := time.Now()
|
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 {
|
if err != nil {
|
||||||
bc.reportBlock(block, receipts, err)
|
bc.reportBlock(block, res, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ptime := time.Since(pstart)
|
ptime := time.Since(pstart)
|
||||||
|
|
||||||
vstart := time.Now()
|
vstart := time.Now()
|
||||||
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
if err := bc.validator.ValidateState(block, statedb, res, false); err != nil {
|
||||||
bc.reportBlock(block, receipts, err)
|
bc.reportBlock(block, res, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
vtime := time.Since(vstart)
|
vtime := time.Since(vstart)
|
||||||
|
|
||||||
if witness := statedb.Witness(); witness != nil {
|
if witness := statedb.Witness(); witness != nil {
|
||||||
if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil {
|
if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil {
|
||||||
bc.reportBlock(block, receipts, err)
|
bc.reportBlock(block, res, err)
|
||||||
return nil, fmt.Errorf("cross verification failed: %v", err)
|
return nil, fmt.Errorf("cross verification failed: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1949,16 +1917,18 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||||
// Update the metrics touched during block processing and validation
|
// Update the metrics touched during block processing and validation
|
||||||
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
||||||
storageReadTimer.Update(statedb.StorageReads) // Storage 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)
|
if statedb.AccountLoaded != 0 {
|
||||||
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
|
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)
|
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
|
||||||
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage 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)
|
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
||||||
triehash := statedb.AccountHashes // The time spent on tries hashing
|
triehash := statedb.AccountHashes // The time spent on tries hashing
|
||||||
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
|
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
|
||||||
trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
|
blockExecutionTimer.Update(ptime - (statedb.AccountReads + statedb.StorageReads)) // The time spent on EVM processing
|
||||||
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
|
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
|
||||||
|
|
||||||
// Write the block to the chain and get the status.
|
// Write the block to the chain and get the status.
|
||||||
|
@ -1968,9 +1938,9 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||||
)
|
)
|
||||||
if !setHead {
|
if !setHead {
|
||||||
// Don't set the head, only insert the block
|
// Don't set the head, only insert the block
|
||||||
err = bc.writeBlockWithState(block, receipts, statedb)
|
err = bc.writeBlockWithState(block, res.Receipts, statedb)
|
||||||
} else {
|
} else {
|
||||||
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
|
status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1984,7 +1954,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)
|
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
||||||
blockInsertTimer.UpdateSince(start)
|
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
|
// insertSideChain is called when an import batch hits upon a pruned ancestor
|
||||||
|
@ -1997,7 +1967,6 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||||
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, error) {
|
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, error) {
|
||||||
var (
|
var (
|
||||||
externTd *big.Int
|
externTd *big.Int
|
||||||
lastBlock = block
|
|
||||||
current = bc.CurrentBlock()
|
current = bc.CurrentBlock()
|
||||||
)
|
)
|
||||||
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
||||||
|
@ -2049,22 +2018,6 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
||||||
"txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()),
|
"txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()),
|
||||||
"root", block.Root())
|
"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)
|
// Gather all the sidechain hashes (full blocks may be memory heavy)
|
||||||
var (
|
var (
|
||||||
|
@ -2481,7 +2434,11 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// reportBlock logs a bad block error.
|
// 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)
|
rawdb.WriteBadBlock(bc.db, block)
|
||||||
log.Error(summarizeBadBlock(block, receipts, bc.Config(), err))
|
log.Error(summarizeBadBlock(block, receipts, bc.Config(), err))
|
||||||
}
|
}
|
||||||
|
@ -2527,7 +2484,7 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header) (int, error) {
|
||||||
return 0, errChainStopped
|
return 0, errChainStopped
|
||||||
}
|
}
|
||||||
defer bc.chainmu.Unlock()
|
defer bc.chainmu.Unlock()
|
||||||
_, err := bc.hc.InsertHeaderChain(chain, start, bc.forker)
|
_, err := bc.hc.InsertHeaderChain(chain, start)
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,11 +170,6 @@ func (it *insertIterator) current() *types.Header {
|
||||||
return it.chain[it.index].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.
|
// remaining returns the number of remaining blocks.
|
||||||
func (it *insertIterator) remaining() int {
|
func (it *insertIterator) remaining() int {
|
||||||
return len(it.chain) - it.index
|
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.
|
// HasState checks if state trie is fully present in the database or not.
|
||||||
func (bc *BlockChain) HasState(hash common.Hash) bool {
|
func (bc *BlockChain) HasState(hash common.Hash) bool {
|
||||||
_, err := bc.stateCache.OpenTrie(hash)
|
_, err := bc.statedb.OpenTrie(hash)
|
||||||
return err == nil
|
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
|
// If the code doesn't exist in the in-memory cache, check the storage with
|
||||||
// new code scheme.
|
// new code scheme.
|
||||||
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
|
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
|
// TODO(rjl493456442) The associated account address is also required
|
||||||
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
|
// 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.
|
// 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.
|
// StateAt returns a new mutable state based on a particular point in time.
|
||||||
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
|
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.
|
// 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.
|
// StateCache returns the caching database underpinning the blockchain instance.
|
||||||
func (bc *BlockChain) StateCache() state.Database {
|
func (bc *BlockChain) StateCache() state.Database {
|
||||||
return bc.stateCache
|
return bc.statedb
|
||||||
}
|
}
|
||||||
|
|
||||||
// GasLimit returns the gas limit of the current HEAD block.
|
// GasLimit returns the gas limit of the current HEAD block.
|
||||||
|
|
|
@ -1794,7 +1794,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
|
||||||
config.SnapshotLimit = 256
|
config.SnapshotLimit = 256
|
||||||
config.SnapshotWait = true
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
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()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1931,7 +1931,7 @@ func testIssue23496(t *testing.T, scheme string) {
|
||||||
}
|
}
|
||||||
engine = ethash.NewFullFaker()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1981,7 +1981,7 @@ func testIssue23496(t *testing.T, scheme string) {
|
||||||
}
|
}
|
||||||
defer db.Close()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1997,7 +1997,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
|
||||||
config.SnapshotLimit = 256
|
config.SnapshotLimit = 256
|
||||||
config.SnapshotWait = true
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
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
|
dbconfig.HashDB = hashdb.Defaults
|
||||||
}
|
}
|
||||||
chain.triedb = triedb.NewDatabase(chain.db, dbconfig)
|
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
|
// Force run a freeze cycle
|
||||||
type freezer interface {
|
type freezer interface {
|
||||||
|
|
|
@ -81,7 +81,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||||
}
|
}
|
||||||
engine = ethash.NewFullFaker()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ func (snaptest *snapshotTest) test(t *testing.T) {
|
||||||
|
|
||||||
// Restart the chain normally
|
// Restart the chain normally
|
||||||
chain.Stop()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -270,13 +270,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||||
// the crash, we do restart twice here: one after the crash and one
|
// 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
|
// after the normal stop. It's used to ensure the broken snapshot
|
||||||
// can be detected all the time.
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
newchain.Stop()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
StateScheme: snaptest.scheme,
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
// Restart the chain with enabling the snapshot
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
|
||||||
chain.SetHead(snaptest.setHead)
|
chain.SetHead(snaptest.setHead)
|
||||||
chain.Stop()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
StateScheme: snaptest.scheme,
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
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
|
SnapshotWait: false, // Don't wait rebuild
|
||||||
StateScheme: snaptest.scheme,
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -411,7 +411,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||||
tmp.triedb.Close()
|
tmp.triedb.Close()
|
||||||
tmp.stopWithoutSaving()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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
|
// 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
|
// Create and inject the requested chain
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
|
@ -159,17 +160,18 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
||||||
}
|
}
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{})
|
res, err := blockchain.processor.Process(block, statedb, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
blockchain.reportBlock(block, receipts, err)
|
blockchain.reportBlock(block, res, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
err = blockchain.validator.ValidateState(block, statedb, res, false)
|
||||||
blockchain.reportBlock(block, receipts, err)
|
if err != nil {
|
||||||
|
blockchain.reportBlock(block, res, err)
|
||||||
return 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
|
// Import the chain as an archive node for the comparison baseline
|
||||||
archiveDb := rawdb.NewMemoryDatabase()
|
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()
|
defer archive.Stop()
|
||||||
|
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
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
|
// Fast import the chain as a non-archive node to test
|
||||||
fastDb := rawdb.NewMemoryDatabase()
|
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()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
@ -790,7 +792,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
|
||||||
}
|
}
|
||||||
defer ancientDb.Close()
|
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()
|
defer ancient.Stop()
|
||||||
|
|
||||||
if n, err := ancient.InsertHeaderChain(headers); err != nil {
|
if n, err := ancient.InsertHeaderChain(headers); err != nil {
|
||||||
|
@ -910,7 +912,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
|
||||||
archiveCaching.TrieDirtyDisabled = true
|
archiveCaching.TrieDirtyDisabled = true
|
||||||
archiveCaching.StateScheme = scheme
|
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 {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
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
|
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||||
fastDb := makeDb()
|
fastDb := makeDb()
|
||||||
defer fastDb.Close()
|
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()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
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
|
// Import the chain as a ancient-first node and ensure all pointers are updated
|
||||||
ancientDb := makeDb()
|
ancientDb := makeDb()
|
||||||
defer ancientDb.Close()
|
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()
|
defer ancient.Stop()
|
||||||
|
|
||||||
if n, err := ancient.InsertHeaderChain(headers); err != nil {
|
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
|
// Import the chain as a light node and ensure all pointers are updated
|
||||||
lightDb := makeDb()
|
lightDb := makeDb()
|
||||||
defer lightDb.Close()
|
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 {
|
if n, err := light.InsertHeaderChain(headers); err != nil {
|
||||||
t.Fatalf("failed to insert header %d: %v", n, err)
|
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.
|
// Import the chain. This runs all block validation rules.
|
||||||
db := rawdb.NewMemoryDatabase()
|
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 {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
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)
|
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()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
rmLogsCh := make(chan RemovedLogsEvent)
|
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)}}}
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
engine = ethash.NewFaker()
|
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()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
|
@ -1246,7 +1248,7 @@ func testSideLogRebirth(t *testing.T, scheme string) {
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
|
||||||
signer = types.LatestSigner(gspec.Config)
|
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()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
|
@ -1265,7 +1267,7 @@ func testSideLogRebirth(t *testing.T, scheme string) {
|
||||||
}
|
}
|
||||||
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
|
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) {
|
genDb, sideChain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1)
|
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 {
|
if _, err := blockchain.InsertChain(sideChain); err != nil {
|
||||||
t.Fatalf("failed to insert forked chain: %v", err)
|
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) {})
|
newBlocks, _ := GenerateChain(gspec.Config, sideChain[len(sideChain)-1], ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||||
if _, err := blockchain.InsertChain(newBlocks); err != nil {
|
if _, err := blockchain.InsertChain(newBlocks); err != nil {
|
||||||
t.Fatalf("failed to insert forked chain: %v", err)
|
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) {
|
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)
|
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()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
_, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {})
|
_, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {})
|
||||||
|
@ -1369,12 +1371,7 @@ func testReorgSideEvent(t *testing.T, scheme string) {
|
||||||
t.Fatalf("failed to insert chain: %v", err)
|
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{
|
expectedSideHashes := map[common.Hash]bool{
|
||||||
replacementBlocks[0].Hash(): true,
|
|
||||||
replacementBlocks[1].Hash(): true,
|
|
||||||
chain[0].Hash(): true,
|
chain[0].Hash(): true,
|
||||||
chain[1].Hash(): true,
|
chain[1].Hash(): true,
|
||||||
chain[2].Hash(): true,
|
chain[2].Hash(): true,
|
||||||
|
@ -1402,7 +1399,7 @@ done:
|
||||||
timeout.Reset(timeoutDura)
|
timeout.Reset(timeoutDura)
|
||||||
|
|
||||||
case <-timeout.C:
|
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()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
if _, err := blockchain.InsertChain(blocks); err != nil {
|
if _, err := blockchain.InsertChain(blocks); err != nil {
|
||||||
|
@ -1622,7 +1619,7 @@ func testEIP161AccountRemoval(t *testing.T, scheme string) {
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
})
|
})
|
||||||
// account must exist pre eip 161
|
// 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()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil {
|
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
|
// Import the canonical and fork chain side by side, verifying the current block
|
||||||
// and current header consistency
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1724,7 +1721,7 @@ func TestTrieForkGC(t *testing.T) {
|
||||||
forks[i] = fork[0]
|
forks[i] = fork[0]
|
||||||
}
|
}
|
||||||
// Import the canonical and fork chain side by side, forcing the trie cache to cache both
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
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)
|
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||||
defer db.Close()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
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()) {
|
if chain.HasState(shared[len(shared)-1].Root()) {
|
||||||
t.Fatalf("common-but-old ancestor still cache")
|
t.Fatalf("common-but-old ancestor still cache")
|
||||||
}
|
}
|
||||||
// Import the competitor chain without exceeding the canonical's TD and ensure
|
// Import the competitor chain without exceeding the canonical's TD.
|
||||||
// we have not processed any of the blocks (protection against malicious blocks)
|
// Post-merge the side chain should be executed
|
||||||
if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil {
|
if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil {
|
||||||
t.Fatalf("failed to insert competitor chain: %v", err)
|
t.Fatalf("failed to insert competitor chain: %v", err)
|
||||||
}
|
}
|
||||||
for i, block := range competitor[:len(competitor)-2] {
|
if !chain.HasState(competitor[len(competitor)-3].Root()) {
|
||||||
if chain.HasState(block.Root()) {
|
t.Fatalf("failed to insert low-TD chain")
|
||||||
t.Fatalf("competitor %d: low TD chain became processed", i)
|
|
||||||
}
|
}
|
||||||
}
|
// Import the head of the competitor chain.
|
||||||
// Import the head of the competitor chain, triggering the reorg and ensure we
|
|
||||||
// successfully reprocess all the stashed away blocks.
|
|
||||||
if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil {
|
if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil {
|
||||||
t.Fatalf("failed to finalize competitor chain: %v", err)
|
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)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
defer ancientDb.Close()
|
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))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
@ -1861,7 +1855,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) {
|
||||||
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
|
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
|
||||||
|
|
||||||
// Reopen broken blockchain again
|
// 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()
|
defer ancient.Stop()
|
||||||
if num := ancient.CurrentBlock().Number.Uint64(); num != 0 {
|
if num := ancient.CurrentBlock().Number.Uint64(); num != 0 {
|
||||||
t.Errorf("head block mismatch: have #%v, want #%v", 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()
|
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()
|
defer ancientChain.Stop()
|
||||||
|
|
||||||
// Import the canonical header chain.
|
// Import the canonical header chain.
|
||||||
|
@ -1980,7 +1974,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
|
||||||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||||
defer diskdb.Close()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -2041,7 +2035,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||||
mergeBlock = math.MaxInt32
|
mergeBlock = math.MaxInt32
|
||||||
)
|
)
|
||||||
// Generate and import the canonical chain
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -2195,7 +2189,7 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) {
|
||||||
}
|
}
|
||||||
defer chaindb.Close()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
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 {
|
if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
||||||
t.Fatalf("failed to insert chain data: %v", err)
|
t.Fatalf("failed to insert chain data: %v", err)
|
||||||
}
|
}
|
||||||
// The head shouldn't change.
|
// Post-merge the chain should change even if td is lower.
|
||||||
asserter(t, blocks3[len(blocks3)-1])
|
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)
|
chain.SetHead(rollback - 1)
|
||||||
if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil {
|
||||||
t.Fatalf("failed to insert chain data: %v", err)
|
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()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
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) {
|
genDb, longChain, _ := GenerateChainWithGenesis(genesis, engine, 80, func(i int, b *BlockGen) {
|
||||||
b.SetCoinbase(common.Address{1})
|
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 {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
|
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()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
// Import the shared chain and the original canonical one
|
// 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 {
|
if err != nil {
|
||||||
b.Fatalf("failed to create tester chain: %v", err)
|
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
|
// Generate and import the canonical chain
|
||||||
_, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil)
|
_, 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
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()) {
|
if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) {
|
||||||
t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64())
|
t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64())
|
||||||
}
|
}
|
||||||
// Now re-import some old blocks
|
|
||||||
blockToReimport := blocks[5:8]
|
blockToReimport := blocks[5:8]
|
||||||
_, err = chain.InsertChain(blockToReimport)
|
_, err = chain.InsertChain(blockToReimport)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2843,7 +2850,7 @@ func testDeleteCreateRevert(t *testing.T, scheme string) {
|
||||||
b.AddTx(tx)
|
b.AddTx(tx)
|
||||||
})
|
})
|
||||||
// Import the canonical chain
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -2958,7 +2965,7 @@ func testDeleteRecreateSlots(t *testing.T, scheme string) {
|
||||||
// Import the canonical chain
|
// Import the canonical chain
|
||||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
||||||
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -3040,7 +3047,7 @@ func testDeleteRecreateAccount(t *testing.T, scheme string) {
|
||||||
// Import the canonical chain
|
// Import the canonical chain
|
||||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
||||||
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
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{
|
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
||||||
//Debug: true,
|
//Debug: true,
|
||||||
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
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{
|
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{
|
||||||
//Debug: true,
|
//Debug: true,
|
||||||
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -3441,7 +3448,7 @@ func testEIP2718Transition(t *testing.T, scheme string) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Import the canonical chain
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -3535,7 +3542,7 @@ func testEIP1559Transition(t *testing.T, scheme string) {
|
||||||
|
|
||||||
b.AddTx(tx)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -3648,7 +3655,7 @@ func testSetCanonical(t *testing.T, scheme string) {
|
||||||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||||
defer diskdb.Close()
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester 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) {})
|
_, forkB, _ := GenerateChainWithGenesis(gspec, engine, c.forkB, func(i int, gen *BlockGen) {})
|
||||||
|
|
||||||
// Initialize test chain
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
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{
|
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{
|
||||||
//Debug: true,
|
//Debug: true,
|
||||||
//Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
//Tracer: logger.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -4006,7 +4013,7 @@ func TestDeleteThenCreate(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Import the canonical chain
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -4091,7 +4098,7 @@ func TestTransientStorageReset(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Initialize the blockchain with 1153 enabled.
|
// 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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -4186,7 +4193,7 @@ func TestEIP3651(t *testing.T) {
|
||||||
|
|
||||||
b.AddTx(tx)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
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)
|
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)
|
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)
|
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -368,7 +379,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -467,15 +478,14 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
|
||||||
panic(fmt.Sprintf("trie write error: %v", err))
|
panic(fmt.Sprintf("trie write error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO uncomment when proof generation is merged
|
proofs = append(proofs, block.ExecutionWitness().VerkleProof)
|
||||||
// proofs = append(proofs, block.ExecutionWitness().VerkleProof)
|
keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
|
||||||
// keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
|
|
||||||
|
|
||||||
return block, b.receipts
|
return block, b.receipts
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ func TestGeneratePOSChain(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Import the chain. This runs all block validation rules.
|
// 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()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
if i, err := blockchain.InsertChain(genchain); err != nil {
|
if i, err := blockchain.InsertChain(genchain); err != nil {
|
||||||
|
@ -238,7 +238,7 @@ func ExampleGenerateChain() {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Import the chain. This runs all block validation rules.
|
// 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()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
|
|
|
@ -50,7 +50,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
Config: &proConf,
|
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()
|
defer proBc.Stop()
|
||||||
|
|
||||||
conDb := rawdb.NewMemoryDatabase()
|
conDb := rawdb.NewMemoryDatabase()
|
||||||
|
@ -62,7 +62,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
Config: &conConf,
|
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()
|
defer conBc.Stop()
|
||||||
|
|
||||||
if _, err := proBc.InsertChain(prefix); err != nil {
|
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
|
// 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++ {
|
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
|
||||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
// 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()))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64()))
|
||||||
for j := 0; j < len(blocks)/2; j++ {
|
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)
|
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
|
// 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()))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64()))
|
||||||
for j := 0; j < len(blocks)/2; j++ {
|
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
|
// 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()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64()))
|
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)
|
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
|
// 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()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64()))
|
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
|
{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
|
// Sepolia test cases
|
||||||
{
|
{
|
||||||
params.SepoliaChainConfig,
|
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,
|
// Create an ephemeral in-memory database for computing hash,
|
||||||
// all the derived states will be discarded to not pollute disk.
|
// all the derived states will be discarded to not pollute disk.
|
||||||
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config)
|
db := rawdb.NewMemoryDatabase()
|
||||||
statedb, err := state.New(types.EmptyRootHash, db, nil)
|
statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb.NewDatabase(db, config), nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
@ -145,13 +145,12 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
|
||||||
return statedb.Commit(0, false)
|
return statedb.Commit(0, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// flushAlloc is very similar with hash, but the main difference is all the generated
|
// flushAlloc is very similar with hash, but the main difference is all the
|
||||||
// states will be persisted into the given database. Also, the genesis state
|
// generated states will be persisted into the given database.
|
||||||
// specification will be flushed as well.
|
func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) {
|
||||||
func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database, blockhash common.Hash) error {
|
statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb, nil))
|
||||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
for addr, account := range *ga {
|
for addr, account := range *ga {
|
||||||
if account.Balance != nil {
|
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)
|
root, err := statedb.Commit(0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
// Commit newly generated states into disk if it's not empty.
|
// Commit newly generated states into disk if it's not empty.
|
||||||
if root != types.EmptyRootHash {
|
if root != types.EmptyRootHash {
|
||||||
if err := triedb.Commit(root, true); err != nil {
|
if err := triedb.Commit(root, true); err != nil {
|
||||||
return err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Marshal the genesis state specification and persist.
|
return root, nil
|
||||||
blob, err := json.Marshal(ga)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rawdb.WriteGenesisStateSpec(db, blockhash, blob)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) {
|
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 {
|
switch blockhash {
|
||||||
case params.MainnetGenesisHash:
|
case params.MainnetGenesisHash:
|
||||||
genesis = DefaultGenesisBlock()
|
genesis = DefaultGenesisBlock()
|
||||||
case params.GoerliGenesisHash:
|
|
||||||
genesis = DefaultGoerliGenesisBlock()
|
|
||||||
case params.SepoliaGenesisHash:
|
case params.SepoliaGenesisHash:
|
||||||
genesis = DefaultSepoliaGenesisBlock()
|
genesis = DefaultSepoliaGenesisBlock()
|
||||||
case params.HoleskyGenesisHash:
|
case params.HoleskyGenesisHash:
|
||||||
|
@ -407,8 +398,6 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
|
||||||
return params.HoleskyChainConfig
|
return params.HoleskyChainConfig
|
||||||
case ghash == params.SepoliaGenesisHash:
|
case ghash == params.SepoliaGenesisHash:
|
||||||
return params.SepoliaChainConfig
|
return params.SepoliaChainConfig
|
||||||
case ghash == params.GoerliGenesisHash:
|
|
||||||
return params.GoerliChainConfig
|
|
||||||
default:
|
default:
|
||||||
return params.AllEthashProtocolChanges
|
return params.AllEthashProtocolChanges
|
||||||
}
|
}
|
||||||
|
@ -426,6 +415,11 @@ func (g *Genesis) ToBlock() *types.Block {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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{
|
head := &types.Header{
|
||||||
Number: new(big.Int).SetUint64(g.Number),
|
Number: new(big.Int).SetUint64(g.Number),
|
||||||
Nonce: types.EncodeNonce(g.Nonce),
|
Nonce: types.EncodeNonce(g.Nonce),
|
||||||
|
@ -453,7 +447,10 @@ func (g *Genesis) ToBlock() *types.Block {
|
||||||
head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee)
|
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 {
|
if conf := g.Config; conf != nil {
|
||||||
num := big.NewInt(int64(g.Number))
|
num := big.NewInt(int64(g.Number))
|
||||||
if conf.IsShanghai(num, g.Timestamp) {
|
if conf.IsShanghai(num, g.Timestamp) {
|
||||||
|
@ -475,15 +472,18 @@ func (g *Genesis) ToBlock() *types.Block {
|
||||||
head.BlobGasUsed = new(uint64)
|
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.
|
// Commit writes the block and state of a genesis specification to the database.
|
||||||
// The block is committed as the canonical head block.
|
// The block is committed as the canonical head block.
|
||||||
func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) {
|
func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) {
|
||||||
block := g.ToBlock()
|
if g.Number != 0 {
|
||||||
if block.Number().Sign() != 0 {
|
|
||||||
return nil, errors.New("can't commit genesis block with number > 0")
|
return nil, errors.New("can't commit genesis block with number > 0")
|
||||||
}
|
}
|
||||||
config := g.Config
|
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 {
|
if err := config.CheckConfigForkOrder(); err != nil {
|
||||||
return nil, err
|
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")
|
return nil, errors.New("can't start clique chain without signers")
|
||||||
}
|
}
|
||||||
// All the checks has passed, flushAlloc the states derived from the genesis
|
// flush the data to disk and compute the state root
|
||||||
// specification as well as the specification itself into the provided
|
root, err := flushAlloc(&g.Alloc, triedb)
|
||||||
// database.
|
if err != nil {
|
||||||
if err := flushAlloc(&g.Alloc, db, triedb, block.Hash()); err != nil {
|
|
||||||
return nil, err
|
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.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
|
||||||
rawdb.WriteBlock(db, block)
|
rawdb.WriteBlock(db, block)
|
||||||
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
|
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.
|
// DefaultSepoliaGenesisBlock returns the Sepolia network genesis block.
|
||||||
func DefaultSepoliaGenesisBlock() *Genesis {
|
func DefaultSepoliaGenesisBlock() *Genesis {
|
||||||
return &Genesis{
|
return &Genesis{
|
||||||
|
@ -595,6 +590,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
||||||
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
||||||
// Pre-deploy EIP-4788 system contract
|
// Pre-deploy EIP-4788 system contract
|
||||||
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
||||||
|
// Pre-deploy EIP-2935 history contract.
|
||||||
|
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if faucet != nil {
|
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"
|
"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) {
|
func TestSetupGenesis(t *testing.T) {
|
||||||
testSetupGenesis(t, rawdb.HashScheme)
|
testSetupGenesis(t, rawdb.HashScheme)
|
||||||
testSetupGenesis(t, rawdb.PathScheme)
|
testSetupGenesis(t, rawdb.PathScheme)
|
||||||
|
@ -105,15 +96,15 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||||
wantConfig: customg.Config,
|
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) {
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||||
customg.Commit(db, tdb)
|
customg.Commit(db, tdb)
|
||||||
return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock())
|
return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock())
|
||||||
},
|
},
|
||||||
wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash},
|
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
|
||||||
wantHash: params.GoerliGenesisHash,
|
wantHash: params.SepoliaGenesisHash,
|
||||||
wantConfig: params.GoerliChainConfig,
|
wantConfig: params.SepoliaChainConfig,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "compatible config in DB",
|
name: "compatible config in DB",
|
||||||
|
@ -133,7 +124,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||||
oldcustomg.Commit(db, tdb)
|
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()
|
defer bc.Stop()
|
||||||
|
|
||||||
_, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil)
|
_, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil)
|
||||||
|
@ -184,7 +175,6 @@ func TestGenesisHashes(t *testing.T) {
|
||||||
want common.Hash
|
want common.Hash
|
||||||
}{
|
}{
|
||||||
{DefaultGenesisBlock(), params.MainnetGenesisHash},
|
{DefaultGenesisBlock(), params.MainnetGenesisHash},
|
||||||
{DefaultGoerliGenesisBlock(), params.GoerliGenesisHash},
|
|
||||||
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
|
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
|
||||||
} {
|
} {
|
||||||
// Test via MustCommit
|
// Test via MustCommit
|
||||||
|
@ -304,7 +294,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := common.FromHex("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b")
|
expected := common.FromHex("4a83dc39eb688dbcfaf581d60e82de18f875e38786ebce5833342011d6fef37b")
|
||||||
got := genesis.ToBlock().Root().Bytes()
|
got := genesis.ToBlock().Root().Bytes()
|
||||||
if !bytes.Equal(got, expected) {
|
if !bytes.Equal(got, expected) {
|
||||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
||||||
|
|
|
@ -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
|
// without the real blocks. Hence, writing headers directly should only be done
|
||||||
// in two scenarios: pure-header mode of operation (light clients), or properly
|
// in two scenarios: pure-header mode of operation (light clients), or properly
|
||||||
// separated header/block phases (non-archive clients).
|
// 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)
|
inserted, err := hc.WriteHeaders(headers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -270,15 +270,6 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F
|
||||||
lastHeader: lastHeader,
|
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
|
// Special case, all the inserted headers are already on the canonical
|
||||||
// header chain, skip the reorg operation.
|
// header chain, skip the reorg operation.
|
||||||
if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() {
|
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
|
// The returned 'write status' says if the inserted headers are part of the canonical chain
|
||||||
// or a side 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() {
|
if hc.procInterrupt() {
|
||||||
return 0, errors.New("aborted")
|
return 0, errors.New("aborted")
|
||||||
}
|
}
|
||||||
res, err := hc.writeHeadersAndSetHead(chain, forker)
|
res, err := hc.writeHeadersAndSetHead(chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,10 +51,10 @@ func verifyUnbrokenCanonchain(hc *HeaderChain) error {
|
||||||
return nil
|
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()
|
t.Helper()
|
||||||
|
|
||||||
status, err := hc.InsertHeaderChain(chain, time.Now(), forker)
|
status, err := hc.InsertHeaderChain(chain, time.Now())
|
||||||
if status != wantStatus {
|
if status != wantStatus {
|
||||||
t.Errorf("wrong write status from InsertHeaderChain: got %v, want %v", 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
|
// chain B: G->A1->B1...B128
|
||||||
chainB := makeHeaderChain(gspec.Config, chainA[0], 128, ethash.NewFaker(), genDb, 10)
|
chainB := makeHeaderChain(gspec.Config, chainA[0], 128, ethash.NewFaker(), genDb, 10)
|
||||||
|
|
||||||
forker := NewForkChoice(hc, nil)
|
|
||||||
// Inserting 64 headers on an empty chain, expecting
|
// Inserting 64 headers on an empty chain, expecting
|
||||||
// 1 callbacks, 1 canon-status, 0 sidestatus,
|
// 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
|
// Inserting 64 identical headers, expecting
|
||||||
// 0 callbacks, 0 canon-status, 0 sidestatus,
|
// 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
|
// Inserting the same some old, some new headers
|
||||||
// 1 callbacks, 1 canon, 0 side
|
// 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
|
// Inserting headers from chain B, overtaking the canon chain blindly
|
||||||
testInsert(t, hc, chainB[0:32], SideStatTy, nil, forker)
|
testInsert(t, hc, chainB[0:32], CanonStatTy, nil)
|
||||||
|
|
||||||
// Inserting more side blocks, but we don't have the parent
|
// Inserting more headers on chain B, but we don't have the parent
|
||||||
testInsert(t, hc, chainB[34:36], NonStatTy, consensus.ErrUnknownAncestor, forker)
|
testInsert(t, hc, chainB[34:36], NonStatTy, consensus.ErrUnknownAncestor)
|
||||||
|
|
||||||
// Inserting more sideblocks, overtaking the canon chain
|
// Inserting more headers on chain B, extend the canon chain
|
||||||
testInsert(t, hc, chainB[32:97], CanonStatTy, nil, forker)
|
testInsert(t, hc, chainB[32:97], CanonStatTy, nil)
|
||||||
|
|
||||||
// Inserting more A-headers, taking back the canonicality
|
// Inserting more headers on chain A, taking back the canonicality
|
||||||
testInsert(t, hc, chainA[90:100], CanonStatTy, nil, forker)
|
testInsert(t, hc, chainA[90:100], CanonStatTy, nil)
|
||||||
|
|
||||||
// And B becomes canon again
|
// 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
|
// And B becomes even longer
|
||||||
testInsert(t, hc, chainB[107:128], CanonStatTy, nil, forker)
|
testInsert(t, hc, chainB[107:128], CanonStatTy, nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,12 +149,6 @@ func (db *nofreezedb) ReadAncients(fn func(reader ethdb.AncientReaderOp) error)
|
||||||
return fn(db)
|
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.
|
// AncientDatadir returns an error as we don't have a backing chain freezer.
|
||||||
func (db *nofreezedb) AncientDatadir() (string, error) {
|
func (db *nofreezedb) AncientDatadir() (string, error) {
|
||||||
return "", errNotSupported
|
return "", errNotSupported
|
||||||
|
|
|
@ -24,9 +24,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
@ -54,13 +52,11 @@ var (
|
||||||
// freezerTableSize defines the maximum size of freezer data files.
|
// freezerTableSize defines the maximum size of freezer data files.
|
||||||
const freezerTableSize = 2 * 1000 * 1000 * 1000
|
const freezerTableSize = 2 * 1000 * 1000 * 1000
|
||||||
|
|
||||||
// Freezer is a memory mapped append-only database to store immutable ordered
|
// Freezer is an append-only database to store immutable ordered data into
|
||||||
// data into flat files:
|
// flat files:
|
||||||
//
|
//
|
||||||
// - The append-only nature ensures that disk writes are minimized.
|
// - The append-only nature ensures that disk writes are minimized.
|
||||||
// - The memory mapping ensures we can max out system memory for caching without
|
// - The in-order data ensures that disk reads are always optimized.
|
||||||
// reserving it for go-ethereum. This would also reduce the memory requirements
|
|
||||||
// of Geth, and thus also GC overhead.
|
|
||||||
type Freezer struct {
|
type Freezer struct {
|
||||||
frozen atomic.Uint64 // Number of items already frozen
|
frozen atomic.Uint64 // Number of items already frozen
|
||||||
tail atomic.Uint64 // Number of the first stored item in the freezer
|
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
|
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 {
|
func (f *Freezer) Close() error {
|
||||||
f.writeLock.Lock()
|
f.writeLock.Lock()
|
||||||
defer f.writeLock.Unlock()
|
defer f.writeLock.Unlock()
|
||||||
|
@ -389,115 +385,3 @@ func (f *Freezer) repair() error {
|
||||||
f.tail.Store(tail)
|
f.tail.Store(tail)
|
||||||
return nil
|
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
|
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
|
// Close releases all the sources held by the memory freezer. It will panic if
|
||||||
// any following invocation is made to a closed freezer.
|
// any following invocation is made to a closed freezer.
|
||||||
func (f *MemoryFreezer) Close() error {
|
func (f *MemoryFreezer) Close() error {
|
||||||
|
|
|
@ -202,15 +202,6 @@ func (f *resettableFreezer) Sync() error {
|
||||||
return f.freezer.Sync()
|
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
|
// cleanup removes the directory located in the specified path
|
||||||
// has the name with deletion marker suffix.
|
// has the name with deletion marker suffix.
|
||||||
func cleanup(path string) error {
|
func cleanup(path string) error {
|
||||||
|
|
|
@ -22,8 +22,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"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) {
|
func TestFreezerCloseSync(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
f, _ := newFreezerForTesting(t, map[string]bool{"a": true, "b": true})
|
f, _ := newFreezerForTesting(t, map[string]bool{"a": true, "b": true})
|
||||||
|
|
|
@ -113,12 +113,6 @@ func (t *table) Sync() error {
|
||||||
return t.db.Sync()
|
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.
|
// AncientDatadir returns the ancient datadir of the underlying database.
|
||||||
func (t *table) AncientDatadir() (string, error) {
|
func (t *table) AncientDatadir() (string, error) {
|
||||||
return t.db.AncientDatadir()
|
return t.db.AncientDatadir()
|
||||||
|
|
|
@ -94,11 +94,8 @@ func (ae *AccessEvents) Copy() *AccessEvents {
|
||||||
// member fields of an account.
|
// member fields of an account.
|
||||||
func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite)
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, 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)
|
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,8 +104,7 @@ func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
||||||
// call to that account.
|
// call to that account.
|
||||||
func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false)
|
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.BasicDataLeafKey, false)
|
||||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
|
||||||
return gas
|
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.
|
// cold balance member fields of the caller and the callee accounts.
|
||||||
func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 {
|
func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, 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
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractCreateInitGas returns the access gas costs for the initialization of
|
// ContractCreateInitGas returns the access gas costs for the initialization of
|
||||||
// a contract creation.
|
// a contract creation.
|
||||||
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 {
|
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, true)
|
||||||
if createSendsValue {
|
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
|
||||||
}
|
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTxOrigin adds the member fields of the sender account to the access event list,
|
// 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.
|
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||||
func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) {
|
func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) {
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey, false)
|
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey, true)
|
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
|
||||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTxDestination adds the member fields of the sender account to the access event list,
|
// 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.
|
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||||
func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) {
|
func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) {
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false)
|
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, sendsValue)
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, sendsValue)
|
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, false)
|
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
|
||||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SlotGas returns the amount of gas to be charged for a cold storage access.
|
// 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
|
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.
|
// amount of gas that it costs.
|
||||||
// Note that an access in write mode implies an access in read mode, whereas an
|
// 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.
|
// access in read mode does not imply an access in write mode.
|
||||||
func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 {
|
func (ae *AccessEvents) BasicDataGas(addr common.Address, isWrite bool) uint64 {
|
||||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CodeHashGas adds the account's code hash to the accessed data, and returns the
|
// 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
|
// 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.
|
// read mode does not imply an access in write mode.
|
||||||
func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 {
|
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))
|
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||||
|
|
||||||
// Check cold read cost
|
// Check cold read cost
|
||||||
gas := ae.VersionGas(testAddr, false)
|
gas := ae.BasicDataGas(testAddr, false)
|
||||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
|
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check warm read cost
|
// Check warm read cost
|
||||||
gas = ae.VersionGas(testAddr, false)
|
gas = ae.BasicDataGas(testAddr, false)
|
||||||
if gas != 0 {
|
if gas != 0 {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", 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
|
// 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)
|
gas = ae.CodeHashGas(testAddr, false)
|
||||||
if gas != params.WitnessChunkReadCost {
|
if gas != params.WitnessChunkReadCost {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cold write cost
|
// Check cold write cost
|
||||||
gas = ae.VersionGas(testAddr, true)
|
gas = ae.BasicDataGas(testAddr, true)
|
||||||
if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want {
|
if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check warm write cost
|
// Check warm write cost
|
||||||
gas = ae.VersionGas(testAddr, true)
|
gas = ae.BasicDataGas(testAddr, true)
|
||||||
if gas != 0 {
|
if gas != 0 {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", 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
|
// 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 {
|
if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that a write followed by a read charges nothing
|
// Check that a write followed by a read charges nothing
|
||||||
gas = ae.BalanceGas(testAddr2, false)
|
gas = ae.BasicDataGas(testAddr2, false)
|
||||||
if gas != 0 {
|
if gas != 0 {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", 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
|
// Check cold read cost, without a value
|
||||||
gas := ae.ContractCreateInitGas(testAddr, false)
|
gas := ae.ContractCreateInitGas(testAddr)
|
||||||
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*2; gas != want {
|
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)
|
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check warm read cost
|
// Check warm read cost
|
||||||
gas = ae.ContractCreateInitGas(testAddr, false)
|
gas = ae.ContractCreateInitGas(testAddr)
|
||||||
if gas != 0 {
|
if gas != 0 {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", 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
|
// Check cold read cost, without a value
|
||||||
gas := ae.MessageCallGas(testAddr)
|
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)
|
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
|
// Check that reading the basic data and code hash of the same account does not incur the branch read cost
|
||||||
gas = ae.VersionGas(testAddr, false)
|
gas = ae.BasicDataGas(testAddr, false)
|
||||||
if gas != 0 {
|
if gas != 0 {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||||
}
|
}
|
||||||
gas = ae.CodeSizeGas(testAddr, false)
|
gas = ae.CodeHashGas(testAddr, false)
|
||||||
if gas != 0 {
|
if gas != params.WitnessChunkReadCost {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
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"
|
||||||
"github.com/ethereum/go-ethereum/common/lru"
|
"github.com/ethereum/go-ethereum/common/lru"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"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/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
@ -45,29 +46,29 @@ const (
|
||||||
|
|
||||||
// Database wraps access to tries and contract code.
|
// Database wraps access to tries and contract code.
|
||||||
type Database interface {
|
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 opens the main account trie.
|
||||||
OpenTrie(root common.Hash) (Trie, error)
|
OpenTrie(root common.Hash) (Trie, error)
|
||||||
|
|
||||||
// OpenStorageTrie opens the storage trie of an account.
|
// OpenStorageTrie opens the storage trie of an account.
|
||||||
OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error)
|
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 retrieves a particular contract's code.
|
||||||
ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error)
|
ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error)
|
||||||
|
|
||||||
// ContractCodeSize retrieves a particular contracts code's size.
|
// ContractCodeSize retrieves a particular contracts code's size.
|
||||||
ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error)
|
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 returns the cache holding points used in verkle tree key computation
|
||||||
PointCache() *utils.PointCache
|
PointCache() *utils.PointCache
|
||||||
|
|
||||||
// TrieDB returns the underlying trie database for managing trie nodes.
|
// TrieDB returns the underlying trie database for managing trie nodes.
|
||||||
TrieDB() *triedb.Database
|
TrieDB() *triedb.Database
|
||||||
|
|
||||||
|
// Snapshot returns the underlying state snapshot.
|
||||||
|
Snapshot() *snapshot.Tree
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trie is a Ethereum Merkle Patricia trie.
|
// 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
|
// UpdateAccount abstracts an account write to the trie. It encodes the
|
||||||
// provided account object with associated algorithm and then updates it
|
// provided account object with associated algorithm and then updates it
|
||||||
// in the trie with provided address.
|
// 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,
|
// 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
|
// any existing value is deleted from the trie. The value bytes must not be modified
|
||||||
|
@ -147,47 +148,62 @@ type Trie interface {
|
||||||
IsVerkle() bool
|
IsVerkle() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDatabase creates a backing store for state. The returned database is safe for
|
// CachingDB is an implementation of Database interface. It leverages both trie and
|
||||||
// concurrent use, but does not retain any recent trie nodes in memory. To keep some
|
// state snapshot to provide functionalities for state access. It's meant to be a
|
||||||
// historical state in memory, use the NewDatabaseWithConfig constructor.
|
// long-live object and has a few caches inside for sharing between blocks.
|
||||||
func NewDatabase(db ethdb.Database) Database {
|
type CachingDB struct {
|
||||||
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 {
|
|
||||||
disk ethdb.KeyValueStore
|
disk ethdb.KeyValueStore
|
||||||
codeSizeCache *lru.Cache[common.Hash, int]
|
|
||||||
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
|
||||||
triedb *triedb.Database
|
triedb *triedb.Database
|
||||||
|
snap *snapshot.Tree
|
||||||
|
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
||||||
|
codeSizeCache *lru.Cache[common.Hash, int]
|
||||||
pointCache *utils.PointCache
|
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.
|
// 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() {
|
if db.triedb.IsVerkle() {
|
||||||
return trie.NewVerkleTrie(root, db.triedb, db.pointCache)
|
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.
|
// 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
|
// 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
|
// is hardcoded in the codebase. So we need to return the same trie in this
|
||||||
// case.
|
// case.
|
||||||
|
@ -213,20 +229,8 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
|
||||||
return tr, nil
|
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.
|
// 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)
|
code, _ := db.codeCache.Get(codeHash)
|
||||||
if len(code) > 0 {
|
if len(code) > 0 {
|
||||||
return code, nil
|
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
|
// ContractCodeWithPrefix retrieves a particular contract's code. If the
|
||||||
// code can't be found in the cache, then check the existence with **new**
|
// code can't be found in the cache, then check the existence with **new**
|
||||||
// db scheme.
|
// 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)
|
code, _ := db.codeCache.Get(codeHash)
|
||||||
if len(code) > 0 {
|
if len(code) > 0 {
|
||||||
return code, nil
|
return code, nil
|
||||||
|
@ -258,7 +262,7 @@ func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash com
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractCodeSize retrieves a particular contracts code's size.
|
// 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 {
|
if cached, ok := db.codeSizeCache.Get(codeHash); ok {
|
||||||
return cached, nil
|
return cached, nil
|
||||||
}
|
}
|
||||||
|
@ -266,17 +270,29 @@ func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash)
|
||||||
return len(code), err
|
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.
|
// TrieDB retrieves any intermediate trie-node caching layer.
|
||||||
func (db *cachingDB) TrieDB() *triedb.Database {
|
func (db *CachingDB) TrieDB() *triedb.Database {
|
||||||
return db.triedb
|
return db.triedb
|
||||||
}
|
}
|
||||||
|
|
||||||
// PointCache returns the cache of evaluated curve points.
|
// PointCache returns the cache of evaluated curve points.
|
||||||
func (db *cachingDB) PointCache() *utils.PointCache {
|
func (db *CachingDB) PointCache() *utils.PointCache {
|
||||||
return db.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)
|
db, sdb, ndb, root, _ := makeTestState(scheme)
|
||||||
ndb.Commit(root, false)
|
ndb.Commit(root, false)
|
||||||
|
|
||||||
state, err := New(root, sdb, nil)
|
state, err := New(root, sdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create state trie at %x: %v", root, err)
|
t.Fatalf("failed to create state trie at %x: %v", root, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,21 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
|
"slices"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type revision struct {
|
||||||
|
id int
|
||||||
|
journalIndex int
|
||||||
|
}
|
||||||
|
|
||||||
// journalEntry is a modification entry in the state change journal that can be
|
// journalEntry is a modification entry in the state change journal that can be
|
||||||
// reverted on demand.
|
// reverted on demand.
|
||||||
type journalEntry interface {
|
type journalEntry interface {
|
||||||
|
@ -42,6 +51,9 @@ type journalEntry interface {
|
||||||
type journal struct {
|
type journal struct {
|
||||||
entries []journalEntry // Current changes tracked by the journal
|
entries []journalEntry // Current changes tracked by the journal
|
||||||
dirties map[common.Address]int // Dirty accounts and the number of changes
|
dirties map[common.Address]int // Dirty accounts and the number of changes
|
||||||
|
|
||||||
|
validRevisions []revision
|
||||||
|
nextRevisionId int
|
||||||
}
|
}
|
||||||
|
|
||||||
// newJournal creates a new initialized journal.
|
// 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.
|
// append inserts a new modification entry to the end of the change journal.
|
||||||
func (j *journal) append(entry journalEntry) {
|
func (j *journal) append(entry journalEntry) {
|
||||||
j.entries = append(j.entries, entry)
|
j.entries = append(j.entries, entry)
|
||||||
|
@ -97,46 +143,120 @@ func (j *journal) copy() *journal {
|
||||||
return &journal{
|
return &journal{
|
||||||
entries: entries,
|
entries: entries,
|
||||||
dirties: maps.Clone(j.dirties),
|
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 (
|
type (
|
||||||
// Changes to the account trie.
|
// Changes to the account trie.
|
||||||
createObjectChange struct {
|
createObjectChange struct {
|
||||||
account *common.Address
|
account common.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// createContractChange represents an account becoming a contract-account.
|
// createContractChange represents an account becoming a contract-account.
|
||||||
// This event happens prior to executing initcode. The journal-event simply
|
// This event happens prior to executing initcode. The journal-event simply
|
||||||
// manages the created-flag, in order to allow same-tx destruction.
|
// manages the created-flag, in order to allow same-tx destruction.
|
||||||
createContractChange struct {
|
createContractChange struct {
|
||||||
account common.Address
|
account common.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
selfDestructChange struct {
|
selfDestructChange struct {
|
||||||
account *common.Address
|
account common.Address
|
||||||
prev bool // whether account had already self-destructed
|
|
||||||
prevbalance *uint256.Int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes to individual accounts.
|
// Changes to individual accounts.
|
||||||
balanceChange struct {
|
balanceChange struct {
|
||||||
account *common.Address
|
account common.Address
|
||||||
prev *uint256.Int
|
prev *uint256.Int
|
||||||
}
|
}
|
||||||
nonceChange struct {
|
nonceChange struct {
|
||||||
account *common.Address
|
account common.Address
|
||||||
prev uint64
|
prev uint64
|
||||||
}
|
}
|
||||||
storageChange struct {
|
storageChange struct {
|
||||||
account *common.Address
|
account common.Address
|
||||||
key common.Hash
|
key common.Hash
|
||||||
prevvalue common.Hash
|
prevvalue common.Hash
|
||||||
origvalue common.Hash
|
origvalue common.Hash
|
||||||
}
|
}
|
||||||
codeChange struct {
|
codeChange struct {
|
||||||
account *common.Address
|
account common.Address
|
||||||
prevcode, prevhash []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes to other state values.
|
// Changes to other state values.
|
||||||
|
@ -146,35 +266,32 @@ type (
|
||||||
addLogChange struct {
|
addLogChange struct {
|
||||||
txhash common.Hash
|
txhash common.Hash
|
||||||
}
|
}
|
||||||
addPreimageChange struct {
|
|
||||||
hash common.Hash
|
|
||||||
}
|
|
||||||
touchChange struct {
|
touchChange struct {
|
||||||
account *common.Address
|
account common.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes to the access list
|
// Changes to the access list
|
||||||
accessListAddAccountChange struct {
|
accessListAddAccountChange struct {
|
||||||
address *common.Address
|
address common.Address
|
||||||
}
|
}
|
||||||
accessListAddSlotChange struct {
|
accessListAddSlotChange struct {
|
||||||
address *common.Address
|
address common.Address
|
||||||
slot *common.Hash
|
slot common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes to transient storage
|
// Changes to transient storage
|
||||||
transientStorageChange struct {
|
transientStorageChange struct {
|
||||||
account *common.Address
|
account common.Address
|
||||||
key, prevalue common.Hash
|
key, prevalue common.Hash
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ch createObjectChange) revert(s *StateDB) {
|
func (ch createObjectChange) revert(s *StateDB) {
|
||||||
delete(s.stateObjects, *ch.account)
|
delete(s.stateObjects, ch.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch createObjectChange) dirtied() *common.Address {
|
func (ch createObjectChange) dirtied() *common.Address {
|
||||||
return ch.account
|
return &ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch createObjectChange) copy() journalEntry {
|
func (ch createObjectChange) copy() journalEntry {
|
||||||
|
@ -198,22 +315,19 @@ func (ch createContractChange) copy() journalEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch selfDestructChange) revert(s *StateDB) {
|
func (ch selfDestructChange) revert(s *StateDB) {
|
||||||
obj := s.getStateObject(*ch.account)
|
obj := s.getStateObject(ch.account)
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
obj.selfDestructed = ch.prev
|
obj.selfDestructed = false
|
||||||
obj.setBalance(ch.prevbalance)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch selfDestructChange) dirtied() *common.Address {
|
func (ch selfDestructChange) dirtied() *common.Address {
|
||||||
return ch.account
|
return &ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch selfDestructChange) copy() journalEntry {
|
func (ch selfDestructChange) copy() journalEntry {
|
||||||
return selfDestructChange{
|
return selfDestructChange{
|
||||||
account: ch.account,
|
account: ch.account,
|
||||||
prev: ch.prev,
|
|
||||||
prevbalance: new(uint256.Int).Set(ch.prevbalance),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +337,7 @@ func (ch touchChange) revert(s *StateDB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch touchChange) dirtied() *common.Address {
|
func (ch touchChange) dirtied() *common.Address {
|
||||||
return ch.account
|
return &ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch touchChange) copy() journalEntry {
|
func (ch touchChange) copy() journalEntry {
|
||||||
|
@ -233,11 +347,11 @@ func (ch touchChange) copy() journalEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch balanceChange) revert(s *StateDB) {
|
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 {
|
func (ch balanceChange) dirtied() *common.Address {
|
||||||
return ch.account
|
return &ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch balanceChange) copy() journalEntry {
|
func (ch balanceChange) copy() journalEntry {
|
||||||
|
@ -248,11 +362,11 @@ func (ch balanceChange) copy() journalEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch nonceChange) revert(s *StateDB) {
|
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 {
|
func (ch nonceChange) dirtied() *common.Address {
|
||||||
return ch.account
|
return &ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch nonceChange) copy() journalEntry {
|
func (ch nonceChange) copy() journalEntry {
|
||||||
|
@ -263,27 +377,23 @@ func (ch nonceChange) copy() journalEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch codeChange) revert(s *StateDB) {
|
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 {
|
func (ch codeChange) dirtied() *common.Address {
|
||||||
return ch.account
|
return &ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch codeChange) copy() journalEntry {
|
func (ch codeChange) copy() journalEntry {
|
||||||
return codeChange{
|
return codeChange{account: ch.account}
|
||||||
account: ch.account,
|
|
||||||
prevhash: common.CopyBytes(ch.prevhash),
|
|
||||||
prevcode: common.CopyBytes(ch.prevcode),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch storageChange) revert(s *StateDB) {
|
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 {
|
func (ch storageChange) dirtied() *common.Address {
|
||||||
return ch.account
|
return &ch.account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch storageChange) copy() journalEntry {
|
func (ch storageChange) copy() journalEntry {
|
||||||
|
@ -295,7 +405,7 @@ func (ch storageChange) copy() journalEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch transientStorageChange) revert(s *StateDB) {
|
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 {
|
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) {
|
func (ch accessListAddAccountChange) revert(s *StateDB) {
|
||||||
/*
|
/*
|
||||||
One important invariant here, is that whenever a (addr, slot) is added, if the
|
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
|
(addr) at this point, since no storage adds can remain when come upon
|
||||||
a single (addr) change.
|
a single (addr) change.
|
||||||
*/
|
*/
|
||||||
s.accessList.DeleteAddress(*ch.address)
|
s.accessList.DeleteAddress(ch.address)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch accessListAddAccountChange) dirtied() *common.Address {
|
func (ch accessListAddAccountChange) dirtied() *common.Address {
|
||||||
|
@ -382,7 +478,7 @@ func (ch accessListAddAccountChange) copy() journalEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch accessListAddSlotChange) revert(s *StateDB) {
|
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 {
|
func (ch accessListAddSlotChange) dirtied() *common.Address {
|
||||||
|
|
|
@ -19,6 +19,8 @@ package state
|
||||||
import "github.com/ethereum/go-ethereum/metrics"
|
import "github.com/ethereum/go-ethereum/metrics"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
accountReadMeters = metrics.NewRegisteredMeter("state/read/accounts", nil)
|
||||||
|
storageReadMeters = metrics.NewRegisteredMeter("state/read/storage", nil)
|
||||||
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
|
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
|
||||||
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
|
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
|
||||||
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)
|
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)
|
||||||
|
|
|
@ -270,11 +270,10 @@ func (p *Pruner) Prune(root common.Hash) error {
|
||||||
// is the presence of root can indicate the presence of the
|
// is the presence of root can indicate the presence of the
|
||||||
// entire trie.
|
// entire trie.
|
||||||
if !rawdb.HasLegacyTrieNode(p.db, root) {
|
if !rawdb.HasLegacyTrieNode(p.db, root) {
|
||||||
// The special case is for clique based networks(goerli
|
// The special case is for clique based networks, it's possible
|
||||||
// and some other private networks), it's possible that two
|
// that two consecutive blocks will have same root. In this case
|
||||||
// consecutive blocks will have same root. In this case snapshot
|
// snapshot difflayer won't be created. So HEAD-127 may not paired
|
||||||
// difflayer won't be created. So HEAD-127 may not paired with
|
// with head-127 layer. Instead the paired layer is higher than the
|
||||||
// head-127 layer. Instead the paired layer is higher than the
|
|
||||||
// bottom-most diff layer. Try to find the bottom-most snapshot
|
// bottom-most diff layer. Try to find the bottom-most snapshot
|
||||||
// layer with state available.
|
// layer with state available.
|
||||||
//
|
//
|
||||||
|
|
|
@ -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
|
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
|
// Account directly retrieves the account associated with a particular hash in
|
||||||
// the snapshot slim data format.
|
// the snapshot slim data format.
|
||||||
func (dl *diskLayer) Account(hash common.Hash) (*types.SlimAccount, error) {
|
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 {
|
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)
|
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
|
accMarker = nil
|
||||||
return 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)
|
origin := common.CopyBytes(accMarker)
|
||||||
for {
|
for {
|
||||||
id := trie.StateTrieID(dl.root)
|
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 {
|
if err != nil {
|
||||||
return err // The procedure it aborted, either by external signal or internal error.
|
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()
|
ctx.removeStorageLeft()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
accountRange = accountCheckRange
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,24 +258,11 @@ func (t *Tree) Disable() {
|
||||||
for _, layer := range t.layers {
|
for _, layer := range t.layers {
|
||||||
switch layer := layer.(type) {
|
switch layer := layer.(type) {
|
||||||
case *diskLayer:
|
case *diskLayer:
|
||||||
|
// TODO this function will hang if it's called twice. Will
|
||||||
layer.lock.RLock()
|
// fix it in the following PRs.
|
||||||
generating := layer.genMarker != nil
|
layer.stopGeneration()
|
||||||
layer.lock.RUnlock()
|
layer.markStale()
|
||||||
if !generating {
|
layer.Release()
|
||||||
// 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()
|
|
||||||
|
|
||||||
case *diffLayer:
|
case *diffLayer:
|
||||||
// If the layer is a simple diff, simply mark as stale
|
// 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 {
|
for _, layer := range t.layers {
|
||||||
switch layer := layer.(type) {
|
switch layer := layer.(type) {
|
||||||
case *diskLayer:
|
case *diskLayer:
|
||||||
// If the base layer is generating, abort it and save
|
// TODO this function will hang if it's called twice. Will
|
||||||
if layer.genAbort != nil {
|
// fix it in the following PRs.
|
||||||
abort := make(chan *generatorStats)
|
layer.stopGeneration()
|
||||||
layer.genAbort <- abort
|
layer.markStale()
|
||||||
<-abort
|
layer.Release()
|
||||||
}
|
|
||||||
// Layer should be inactive now, mark it as stale
|
|
||||||
layer.lock.Lock()
|
|
||||||
layer.stale = true
|
|
||||||
layer.lock.Unlock()
|
|
||||||
|
|
||||||
case *diffLayer:
|
case *diffLayer:
|
||||||
// If the layer is a simple diff, simply mark as stale
|
// If the layer is a simple diff, simply mark as stale
|
||||||
|
|
|
@ -114,14 +114,7 @@ func (s *stateObject) markSelfdestructed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateObject) touch() {
|
func (s *stateObject) touch() {
|
||||||
s.db.journal.append(touchChange{
|
s.db.journal.touchChange(s.address)
|
||||||
account: &s.address,
|
|
||||||
})
|
|
||||||
if s.address == ripemd {
|
|
||||||
// Explicitly put it in the dirty-cache, which is otherwise generated from
|
|
||||||
// flattened journals.
|
|
||||||
s.db.journal.dirty(s.address)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTrie returns the associated storage trie. The trie will be opened if it's
|
// getTrie returns the associated storage trie. The trie will be opened if it's
|
||||||
|
@ -150,7 +143,7 @@ func (s *stateObject) getTrie() (Trie, error) {
|
||||||
func (s *stateObject) getPrefetchedTrie() Trie {
|
func (s *stateObject) getPrefetchedTrie() Trie {
|
||||||
// If there's nothing to meaningfully return, let the user figure it out by
|
// If there's nothing to meaningfully return, let the user figure it out by
|
||||||
// pulling the trie from disk.
|
// pulling the trie from disk.
|
||||||
if s.data.Root == types.EmptyRootHash || s.db.prefetcher == nil {
|
if (s.data.Root == types.EmptyRootHash && !s.db.db.TrieDB().IsVerkle()) || s.db.prefetcher == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Attempt to retrieve the trie from the prefetcher
|
// Attempt to retrieve the trie from the prefetcher
|
||||||
|
@ -194,45 +187,17 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
|
||||||
s.originStorage[key] = common.Hash{} // track the empty slot as origin value
|
s.originStorage[key] = common.Hash{} // track the empty slot as origin value
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
// If no live objects are available, attempt to use snapshots
|
s.db.StorageLoaded++
|
||||||
var (
|
|
||||||
enc []byte
|
|
||||||
err error
|
|
||||||
value common.Hash
|
|
||||||
)
|
|
||||||
if s.db.snap != nil {
|
|
||||||
start := time.Now()
|
|
||||||
enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes()))
|
|
||||||
s.db.SnapshotStorageReads += time.Since(start)
|
|
||||||
|
|
||||||
if len(enc) > 0 {
|
|
||||||
_, content, _, err := rlp.Split(enc)
|
|
||||||
if err != nil {
|
|
||||||
s.db.setError(err)
|
|
||||||
}
|
|
||||||
value.SetBytes(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the snapshot is unavailable or reading from it fails, load from the database.
|
|
||||||
if s.db.snap == nil || err != nil {
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
tr, err := s.getTrie()
|
value, err := s.db.reader.Storage(s.address, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.db.setError(err)
|
s.db.setError(err)
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
val, err := tr.GetStorage(s.address, key.Bytes())
|
|
||||||
s.db.StorageReads += time.Since(start)
|
s.db.StorageReads += time.Since(start)
|
||||||
|
|
||||||
if err != nil {
|
// Schedule the resolved storage slots for prefetching if it's enabled.
|
||||||
s.db.setError(err)
|
|
||||||
return common.Hash{}
|
|
||||||
}
|
|
||||||
value.SetBytes(val)
|
|
||||||
}
|
|
||||||
// Independent of where we loaded the data from, add it to the prefetcher.
|
|
||||||
// Whilst this would be a bit weird if snapshots are disabled, but we still
|
|
||||||
// want the trie nodes to end up in the prefetcher too, so just push through.
|
|
||||||
if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash {
|
if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash {
|
||||||
if err = s.db.prefetcher.prefetch(s.addrHash, s.origin.Root, s.address, [][]byte{key[:]}, true); err != nil {
|
if err = s.db.prefetcher.prefetch(s.addrHash, s.origin.Root, s.address, [][]byte{key[:]}, true); err != nil {
|
||||||
log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err)
|
log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err)
|
||||||
|
@ -251,16 +216,11 @@ func (s *stateObject) SetState(key, value common.Hash) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// New value is different, update and journal the change
|
// New value is different, update and journal the change
|
||||||
s.db.journal.append(storageChange{
|
s.db.journal.storageChange(s.address, key, prev, origin)
|
||||||
account: &s.address,
|
s.setState(key, value, origin)
|
||||||
key: key,
|
|
||||||
prevvalue: prev,
|
|
||||||
origvalue: origin,
|
|
||||||
})
|
|
||||||
if s.db.logger != nil && s.db.logger.OnStorageChange != nil {
|
if s.db.logger != nil && s.db.logger.OnStorageChange != nil {
|
||||||
s.db.logger.OnStorageChange(s.address, key, prev, value)
|
s.db.logger.OnStorageChange(s.address, key, prev, value)
|
||||||
}
|
}
|
||||||
s.setState(key, value, origin)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// setState updates a value in account dirty storage. The dirtiness will be
|
// setState updates a value in account dirty storage. The dirtiness will be
|
||||||
|
@ -510,10 +470,7 @@ func (s *stateObject) SubBalance(amount *uint256.Int, reason tracing.BalanceChan
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateObject) SetBalance(amount *uint256.Int, reason tracing.BalanceChangeReason) {
|
func (s *stateObject) SetBalance(amount *uint256.Int, reason tracing.BalanceChangeReason) {
|
||||||
s.db.journal.append(balanceChange{
|
s.db.journal.balanceChange(s.address, s.data.Balance)
|
||||||
account: &s.address,
|
|
||||||
prev: new(uint256.Int).Set(s.data.Balance),
|
|
||||||
})
|
|
||||||
if s.db.logger != nil && s.db.logger.OnBalanceChange != nil {
|
if s.db.logger != nil && s.db.logger.OnBalanceChange != nil {
|
||||||
s.db.logger.OnBalanceChange(s.address, s.Balance().ToBig(), amount.ToBig(), reason)
|
s.db.logger.OnBalanceChange(s.address, s.Balance().ToBig(), amount.ToBig(), reason)
|
||||||
}
|
}
|
||||||
|
@ -541,7 +498,7 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
|
||||||
newContract: s.newContract,
|
newContract: s.newContract,
|
||||||
}
|
}
|
||||||
if s.trie != nil {
|
if s.trie != nil {
|
||||||
obj.trie = db.db.CopyTrie(s.trie)
|
obj.trie = mustCopyTrie(s.trie)
|
||||||
}
|
}
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
@ -589,14 +546,10 @@ func (s *stateObject) CodeSize() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
|
func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
|
||||||
prevcode := s.Code()
|
s.db.journal.setCode(s.address)
|
||||||
s.db.journal.append(codeChange{
|
|
||||||
account: &s.address,
|
|
||||||
prevhash: s.CodeHash(),
|
|
||||||
prevcode: prevcode,
|
|
||||||
})
|
|
||||||
if s.db.logger != nil && s.db.logger.OnCodeChange != nil {
|
if s.db.logger != nil && s.db.logger.OnCodeChange != nil {
|
||||||
s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), prevcode, codeHash, code)
|
// TODO remove prevcode from this callback
|
||||||
|
s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), nil, codeHash, code)
|
||||||
}
|
}
|
||||||
s.setCode(codeHash, code)
|
s.setCode(codeHash, code)
|
||||||
}
|
}
|
||||||
|
@ -608,10 +561,7 @@ func (s *stateObject) setCode(codeHash common.Hash, code []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateObject) SetNonce(nonce uint64) {
|
func (s *stateObject) SetNonce(nonce uint64) {
|
||||||
s.db.journal.append(nonceChange{
|
s.db.journal.nonceChange(s.address, s.data.Nonce)
|
||||||
account: &s.address,
|
|
||||||
prev: s.data.Nonce,
|
|
||||||
})
|
|
||||||
if s.db.logger != nil && s.db.logger.OnNonceChange != nil {
|
if s.db.logger != nil && s.db.logger.OnNonceChange != nil {
|
||||||
s.db.logger.OnNonceChange(s.address, s.data.Nonce, nonce)
|
s.db.logger.OnNonceChange(s.address, s.data.Nonce, nonce)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,27 +26,25 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
type stateEnv struct {
|
type stateEnv struct {
|
||||||
db ethdb.Database
|
|
||||||
state *StateDB
|
state *StateDB
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStateEnv() *stateEnv {
|
func newStateEnv() *stateEnv {
|
||||||
db := rawdb.NewMemoryDatabase()
|
sdb, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||||
sdb, _ := New(types.EmptyRootHash, NewDatabase(db), nil)
|
return &stateEnv{state: sdb}
|
||||||
return &stateEnv{db: db, state: sdb}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDump(t *testing.T) {
|
func TestDump(t *testing.T) {
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
triedb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
||||||
sdb, _ := New(types.EmptyRootHash, tdb, nil)
|
tdb := NewDatabase(triedb, nil)
|
||||||
s := &stateEnv{db: db, state: sdb}
|
sdb, _ := New(types.EmptyRootHash, tdb)
|
||||||
|
s := &stateEnv{state: sdb}
|
||||||
|
|
||||||
// generate a few entries
|
// generate a few entries
|
||||||
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
||||||
|
@ -62,7 +60,7 @@ func TestDump(t *testing.T) {
|
||||||
root, _ := s.state.Commit(0, false)
|
root, _ := s.state.Commit(0, false)
|
||||||
|
|
||||||
// check that DumpToCollector contains the state objects that are in trie
|
// check that DumpToCollector contains the state objects that are in trie
|
||||||
s.state, _ = New(root, tdb, nil)
|
s.state, _ = New(root, tdb)
|
||||||
got := string(s.state.Dump(nil))
|
got := string(s.state.Dump(nil))
|
||||||
want := `{
|
want := `{
|
||||||
"root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2",
|
"root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2",
|
||||||
|
@ -101,9 +99,10 @@ func TestDump(t *testing.T) {
|
||||||
|
|
||||||
func TestIterativeDump(t *testing.T) {
|
func TestIterativeDump(t *testing.T) {
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
triedb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
||||||
sdb, _ := New(types.EmptyRootHash, tdb, nil)
|
tdb := NewDatabase(triedb, nil)
|
||||||
s := &stateEnv{db: db, state: sdb}
|
sdb, _ := New(types.EmptyRootHash, tdb)
|
||||||
|
s := &stateEnv{state: sdb}
|
||||||
|
|
||||||
// generate a few entries
|
// generate a few entries
|
||||||
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
||||||
|
@ -119,7 +118,7 @@ func TestIterativeDump(t *testing.T) {
|
||||||
s.state.updateStateObject(obj1)
|
s.state.updateStateObject(obj1)
|
||||||
s.state.updateStateObject(obj2)
|
s.state.updateStateObject(obj2)
|
||||||
root, _ := s.state.Commit(0, false)
|
root, _ := s.state.Commit(0, false)
|
||||||
s.state, _ = New(root, tdb, nil)
|
s.state, _ = New(root, tdb)
|
||||||
|
|
||||||
b := &bytes.Buffer{}
|
b := &bytes.Buffer{}
|
||||||
s.state.IterativeDump(nil, json.NewEncoder(b))
|
s.state.IterativeDump(nil, json.NewEncoder(b))
|
||||||
|
@ -195,7 +194,7 @@ func TestSnapshotEmpty(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateObjectRevert(t *testing.T) {
|
func TestCreateObjectRevert(t *testing.T) {
|
||||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
state, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||||
addr := common.BytesToAddress([]byte("so0"))
|
addr := common.BytesToAddress([]byte("so0"))
|
||||||
snap := state.Snapshot()
|
snap := state.Snapshot()
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"maps"
|
"maps"
|
||||||
"math/big"
|
"math/big"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -48,11 +47,6 @@ import (
|
||||||
// TriesInMemory represents the number of layers that are kept in RAM.
|
// TriesInMemory represents the number of layers that are kept in RAM.
|
||||||
const TriesInMemory = 128
|
const TriesInMemory = 128
|
||||||
|
|
||||||
type revision struct {
|
|
||||||
id int
|
|
||||||
journalIndex int
|
|
||||||
}
|
|
||||||
|
|
||||||
type mutationType int
|
type mutationType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -88,10 +82,8 @@ type StateDB struct {
|
||||||
db Database
|
db Database
|
||||||
prefetcher *triePrefetcher
|
prefetcher *triePrefetcher
|
||||||
trie Trie
|
trie Trie
|
||||||
hasher crypto.KeccakState
|
|
||||||
logger *tracing.Hooks
|
logger *tracing.Hooks
|
||||||
snaps *snapshot.Tree // Nil if snapshot is not available
|
reader Reader
|
||||||
snap snapshot.Snapshot // Nil if snapshot is not available
|
|
||||||
|
|
||||||
// originalRoot is the pre-state root, before any changes were made.
|
// originalRoot is the pre-state root, before any changes were made.
|
||||||
// It will be updated when the Commit is called.
|
// It will be updated when the Commit is called.
|
||||||
|
@ -137,6 +129,7 @@ type StateDB struct {
|
||||||
|
|
||||||
// Per-transaction access list
|
// Per-transaction access list
|
||||||
accessList *accessList
|
accessList *accessList
|
||||||
|
accessEvents *AccessEvents
|
||||||
|
|
||||||
// Transient storage
|
// Transient storage
|
||||||
transientStorage transientStorage
|
transientStorage transientStorage
|
||||||
|
@ -144,8 +137,6 @@ type StateDB struct {
|
||||||
// Journal of state modifications. This is the backbone of
|
// Journal of state modifications. This is the backbone of
|
||||||
// Snapshot and RevertToSnapshot.
|
// Snapshot and RevertToSnapshot.
|
||||||
journal *journal
|
journal *journal
|
||||||
validRevisions []revision
|
|
||||||
nextRevisionId int
|
|
||||||
|
|
||||||
// State witness if cross validation is needed
|
// State witness if cross validation is needed
|
||||||
witness *stateless.Witness
|
witness *stateless.Witness
|
||||||
|
@ -158,28 +149,32 @@ type StateDB struct {
|
||||||
StorageReads time.Duration
|
StorageReads time.Duration
|
||||||
StorageUpdates time.Duration
|
StorageUpdates time.Duration
|
||||||
StorageCommits time.Duration
|
StorageCommits time.Duration
|
||||||
SnapshotAccountReads time.Duration
|
|
||||||
SnapshotStorageReads time.Duration
|
|
||||||
SnapshotCommits time.Duration
|
SnapshotCommits time.Duration
|
||||||
TrieDBCommits time.Duration
|
TrieDBCommits time.Duration
|
||||||
|
|
||||||
AccountUpdated int
|
AccountLoaded int // Number of accounts retrieved from the database during the state transition
|
||||||
StorageUpdated atomic.Int64
|
AccountUpdated int // Number of accounts updated during the state transition
|
||||||
AccountDeleted int
|
AccountDeleted int // Number of accounts deleted during the state transition
|
||||||
StorageDeleted atomic.Int64
|
StorageLoaded int // Number of storage slots retrieved from the database during the state transition
|
||||||
|
StorageUpdated atomic.Int64 // Number of storage slots updated during the state transition
|
||||||
|
StorageDeleted atomic.Int64 // Number of storage slots deleted during the state transition
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new state from a given trie.
|
// New creates a new state from a given trie.
|
||||||
func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) {
|
func New(root common.Hash, db Database) (*StateDB, error) {
|
||||||
tr, err := db.OpenTrie(root)
|
tr, err := db.OpenTrie(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
reader, err := db.Reader(root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
sdb := &StateDB{
|
sdb := &StateDB{
|
||||||
db: db,
|
db: db,
|
||||||
trie: tr,
|
trie: tr,
|
||||||
originalRoot: root,
|
originalRoot: root,
|
||||||
snaps: snaps,
|
reader: reader,
|
||||||
stateObjects: make(map[common.Address]*stateObject),
|
stateObjects: make(map[common.Address]*stateObject),
|
||||||
stateObjectsDestruct: make(map[common.Address]*stateObject),
|
stateObjectsDestruct: make(map[common.Address]*stateObject),
|
||||||
mutations: make(map[common.Address]*mutation),
|
mutations: make(map[common.Address]*mutation),
|
||||||
|
@ -188,10 +183,9 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
|
||||||
journal: newJournal(),
|
journal: newJournal(),
|
||||||
accessList: newAccessList(),
|
accessList: newAccessList(),
|
||||||
transientStorage: newTransientStorage(),
|
transientStorage: newTransientStorage(),
|
||||||
hasher: crypto.NewKeccakState(),
|
|
||||||
}
|
}
|
||||||
if sdb.snaps != nil {
|
if db.TrieDB().IsVerkle() {
|
||||||
sdb.snap = sdb.snaps.Snapshot(root)
|
sdb.accessEvents = NewAccessEvents(db.PointCache())
|
||||||
}
|
}
|
||||||
return sdb, nil
|
return sdb, nil
|
||||||
}
|
}
|
||||||
|
@ -206,18 +200,11 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) {
|
||||||
// commit phase, most of the needed data is already hot.
|
// commit phase, most of the needed data is already hot.
|
||||||
func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) {
|
func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) {
|
||||||
// Terminate any previously running prefetcher
|
// Terminate any previously running prefetcher
|
||||||
if s.prefetcher != nil {
|
s.StopPrefetcher()
|
||||||
s.prefetcher.terminate(false)
|
|
||||||
s.prefetcher.report()
|
|
||||||
s.prefetcher = nil
|
|
||||||
}
|
|
||||||
// Enable witness collection if requested
|
// Enable witness collection if requested
|
||||||
s.witness = witness
|
s.witness = witness
|
||||||
|
|
||||||
// If snapshots are enabled, start prefethers explicitly
|
|
||||||
if s.snap != nil {
|
|
||||||
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, witness == nil)
|
|
||||||
|
|
||||||
// With the switch to the Proof-of-Stake consensus algorithm, block production
|
// With the switch to the Proof-of-Stake consensus algorithm, block production
|
||||||
// rewards are now handled at the consensus layer. Consequently, a block may
|
// rewards are now handled at the consensus layer. Consequently, a block may
|
||||||
// have no state transitions if it contains no transactions and no withdrawals.
|
// have no state transitions if it contains no transactions and no withdrawals.
|
||||||
|
@ -227,10 +214,10 @@ func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness)
|
||||||
// To prevent this, the account trie is always scheduled for prefetching once
|
// To prevent this, the account trie is always scheduled for prefetching once
|
||||||
// the prefetcher is constructed. For more details, see:
|
// the prefetcher is constructed. For more details, see:
|
||||||
// https://github.com/ethereum/go-ethereum/issues/29880
|
// https://github.com/ethereum/go-ethereum/issues/29880
|
||||||
|
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, witness == nil)
|
||||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil, false); err != nil {
|
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil, false); err != nil {
|
||||||
log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err)
|
log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopPrefetcher terminates a running prefetcher and reports any leftover stats
|
// StopPrefetcher terminates a running prefetcher and reports any leftover stats
|
||||||
|
@ -256,7 +243,7 @@ func (s *StateDB) Error() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) AddLog(log *types.Log) {
|
func (s *StateDB) AddLog(log *types.Log) {
|
||||||
s.journal.append(addLogChange{txhash: s.thash})
|
s.journal.logChange(s.thash)
|
||||||
|
|
||||||
log.TxHash = s.thash
|
log.TxHash = s.thash
|
||||||
log.TxIndex = uint(s.txIndex)
|
log.TxIndex = uint(s.txIndex)
|
||||||
|
@ -290,7 +277,6 @@ func (s *StateDB) Logs() []*types.Log {
|
||||||
// AddPreimage records a SHA3 preimage seen by the VM.
|
// AddPreimage records a SHA3 preimage seen by the VM.
|
||||||
func (s *StateDB) AddPreimage(hash common.Hash, preimage []byte) {
|
func (s *StateDB) AddPreimage(hash common.Hash, preimage []byte) {
|
||||||
if _, ok := s.preimages[hash]; !ok {
|
if _, ok := s.preimages[hash]; !ok {
|
||||||
s.journal.append(addPreimageChange{hash: hash})
|
|
||||||
s.preimages[hash] = slices.Clone(preimage)
|
s.preimages[hash] = slices.Clone(preimage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,14 +288,14 @@ func (s *StateDB) Preimages() map[common.Hash][]byte {
|
||||||
|
|
||||||
// AddRefund adds gas to the refund counter
|
// AddRefund adds gas to the refund counter
|
||||||
func (s *StateDB) AddRefund(gas uint64) {
|
func (s *StateDB) AddRefund(gas uint64) {
|
||||||
s.journal.append(refundChange{prev: s.refund})
|
s.journal.refundChange(s.refund)
|
||||||
s.refund += gas
|
s.refund += gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubRefund removes gas from the refund counter.
|
// SubRefund removes gas from the refund counter.
|
||||||
// This method will panic if the refund counter goes below zero
|
// This method will panic if the refund counter goes below zero
|
||||||
func (s *StateDB) SubRefund(gas uint64) {
|
func (s *StateDB) SubRefund(gas uint64) {
|
||||||
s.journal.append(refundChange{prev: s.refund})
|
s.journal.refundChange(s.refund)
|
||||||
if gas > s.refund {
|
if gas > s.refund {
|
||||||
panic(fmt.Sprintf("Refund counter below zero (gas: %d > refund: %d)", gas, s.refund))
|
panic(fmt.Sprintf("Refund counter below zero (gas: %d > refund: %d)", gas, s.refund))
|
||||||
}
|
}
|
||||||
|
@ -506,20 +492,17 @@ func (s *StateDB) SelfDestruct(addr common.Address) {
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var (
|
// Regardless of whether it is already destructed or not, we do have to
|
||||||
prev = new(uint256.Int).Set(stateObject.Balance())
|
// journal the balance-change, if we set it to zero here.
|
||||||
n = new(uint256.Int)
|
if !stateObject.Balance().IsZero() {
|
||||||
)
|
stateObject.SetBalance(new(uint256.Int), tracing.BalanceDecreaseSelfdestruct)
|
||||||
s.journal.append(selfDestructChange{
|
|
||||||
account: &addr,
|
|
||||||
prev: stateObject.selfDestructed,
|
|
||||||
prevbalance: prev,
|
|
||||||
})
|
|
||||||
if s.logger != nil && s.logger.OnBalanceChange != nil && prev.Sign() > 0 {
|
|
||||||
s.logger.OnBalanceChange(addr, prev.ToBig(), n.ToBig(), tracing.BalanceDecreaseSelfdestruct)
|
|
||||||
}
|
}
|
||||||
|
// If it is already marked as self-destructed, we do not need to add it
|
||||||
|
// for journalling a second time.
|
||||||
|
if !stateObject.selfDestructed {
|
||||||
|
s.journal.destruct(addr)
|
||||||
stateObject.markSelfdestructed()
|
stateObject.markSelfdestructed()
|
||||||
stateObject.data.Balance = n
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) Selfdestruct6780(addr common.Address) {
|
func (s *StateDB) Selfdestruct6780(addr common.Address) {
|
||||||
|
@ -540,11 +523,7 @@ func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash)
|
||||||
if prev == value {
|
if prev == value {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.journal.append(transientStorageChange{
|
s.journal.transientStateChange(addr, key, prev)
|
||||||
account: &addr,
|
|
||||||
key: key,
|
|
||||||
prevalue: prev,
|
|
||||||
})
|
|
||||||
s.setTransientState(addr, key, value)
|
s.setTransientState(addr, key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,7 +546,7 @@ func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common
|
||||||
func (s *StateDB) updateStateObject(obj *stateObject) {
|
func (s *StateDB) updateStateObject(obj *stateObject) {
|
||||||
// Encode the account and update the account trie
|
// Encode the account and update the account trie
|
||||||
addr := obj.Address()
|
addr := obj.Address()
|
||||||
if err := s.trie.UpdateAccount(addr, &obj.data); err != nil {
|
if err := s.trie.UpdateAccount(addr, &obj.data, len(obj.code)); err != nil {
|
||||||
s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err))
|
s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err))
|
||||||
}
|
}
|
||||||
if obj.dirtyCode {
|
if obj.dirtyCode {
|
||||||
|
@ -593,56 +572,30 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
||||||
if _, ok := s.stateObjectsDestruct[addr]; ok {
|
if _, ok := s.stateObjectsDestruct[addr]; ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// If no live objects are available, attempt to use snapshots
|
s.AccountLoaded++
|
||||||
var data *types.StateAccount
|
|
||||||
if s.snap != nil {
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes()))
|
acct, err := s.reader.Account(addr)
|
||||||
s.SnapshotAccountReads += time.Since(start)
|
if err != nil {
|
||||||
if err == nil {
|
s.setError(fmt.Errorf("getStateObject (%x) error: %w", addr.Bytes(), err))
|
||||||
if acc == nil {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
data = &types.StateAccount{
|
|
||||||
Nonce: acc.Nonce,
|
|
||||||
Balance: acc.Balance,
|
|
||||||
CodeHash: acc.CodeHash,
|
|
||||||
Root: common.BytesToHash(acc.Root),
|
|
||||||
}
|
|
||||||
if len(data.CodeHash) == 0 {
|
|
||||||
data.CodeHash = types.EmptyCodeHash.Bytes()
|
|
||||||
}
|
|
||||||
if data.Root == (common.Hash{}) {
|
|
||||||
data.Root = types.EmptyRootHash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If snapshot unavailable or reading from it failed, load from the database
|
|
||||||
if data == nil {
|
|
||||||
start := time.Now()
|
|
||||||
var err error
|
|
||||||
data, err = s.trie.GetAccount(addr)
|
|
||||||
s.AccountReads += time.Since(start)
|
s.AccountReads += time.Since(start)
|
||||||
|
|
||||||
if err != nil {
|
// Short circuit if the account is not found
|
||||||
s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %w", addr.Bytes(), err))
|
if acct == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if data == nil {
|
// Schedule the resolved account for prefetching if it's enabled.
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Independent of where we loaded the data from, add it to the prefetcher.
|
|
||||||
// Whilst this would be a bit weird if snapshots are disabled, but we still
|
|
||||||
// want the trie nodes to end up in the prefetcher too, so just push through.
|
|
||||||
if s.prefetcher != nil {
|
if s.prefetcher != nil {
|
||||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]}, true); err != nil {
|
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]}, true); err != nil {
|
||||||
log.Error("Failed to prefetch account", "addr", addr, "err", err)
|
log.Error("Failed to prefetch account", "addr", addr, "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert into the live set
|
// Insert into the live set
|
||||||
obj := newObject(s, addr, data)
|
obj := newObject(s, addr, acct)
|
||||||
s.setStateObject(obj)
|
s.setStateObject(obj)
|
||||||
|
s.AccountLoaded++
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,7 +616,7 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject {
|
||||||
// existing account with the given address, otherwise it will be silently overwritten.
|
// existing account with the given address, otherwise it will be silently overwritten.
|
||||||
func (s *StateDB) createObject(addr common.Address) *stateObject {
|
func (s *StateDB) createObject(addr common.Address) *stateObject {
|
||||||
obj := newObject(s, addr, nil)
|
obj := newObject(s, addr, nil)
|
||||||
s.journal.append(createObjectChange{account: &addr})
|
s.journal.createObject(addr)
|
||||||
s.setStateObject(obj)
|
s.setStateObject(obj)
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
@ -685,7 +638,7 @@ func (s *StateDB) CreateContract(addr common.Address) {
|
||||||
obj := s.getStateObject(addr)
|
obj := s.getStateObject(addr)
|
||||||
if !obj.newContract {
|
if !obj.newContract {
|
||||||
obj.newContract = true
|
obj.newContract = true
|
||||||
s.journal.append(createContractChange{account: addr})
|
s.journal.createContract(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,8 +648,8 @@ func (s *StateDB) Copy() *StateDB {
|
||||||
// Copy all the basic fields, initialize the memory ones
|
// Copy all the basic fields, initialize the memory ones
|
||||||
state := &StateDB{
|
state := &StateDB{
|
||||||
db: s.db,
|
db: s.db,
|
||||||
trie: s.db.CopyTrie(s.trie),
|
trie: mustCopyTrie(s.trie),
|
||||||
hasher: crypto.NewKeccakState(),
|
reader: s.reader.Copy(),
|
||||||
originalRoot: s.originalRoot,
|
originalRoot: s.originalRoot,
|
||||||
stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)),
|
stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)),
|
||||||
stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)),
|
stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)),
|
||||||
|
@ -708,20 +661,23 @@ func (s *StateDB) Copy() *StateDB {
|
||||||
logs: make(map[common.Hash][]*types.Log, len(s.logs)),
|
logs: make(map[common.Hash][]*types.Log, len(s.logs)),
|
||||||
logSize: s.logSize,
|
logSize: s.logSize,
|
||||||
preimages: maps.Clone(s.preimages),
|
preimages: maps.Clone(s.preimages),
|
||||||
journal: s.journal.copy(),
|
|
||||||
validRevisions: slices.Clone(s.validRevisions),
|
|
||||||
nextRevisionId: s.nextRevisionId,
|
|
||||||
|
|
||||||
// In order for the block producer to be able to use and make additions
|
// Do we need to copy the access list and transient storage?
|
||||||
// to the snapshot tree, we need to copy that as well. Otherwise, any
|
// In practice: No. At the start of a transaction, these two lists are empty.
|
||||||
// block mined by ourselves will cause gaps in the tree, and force the
|
// In practice, we only ever copy state _between_ transactions/blocks, never
|
||||||
// miner to operate trie-backed only.
|
// in the middle of a transaction. However, it doesn't cost us much to copy
|
||||||
snaps: s.snaps,
|
// empty lists, so we do it anyway to not blow up if we ever decide copy them
|
||||||
snap: s.snap,
|
// in the middle of a transaction.
|
||||||
|
accessList: s.accessList.Copy(),
|
||||||
|
transientStorage: s.transientStorage.Copy(),
|
||||||
|
journal: s.journal.copy(),
|
||||||
}
|
}
|
||||||
if s.witness != nil {
|
if s.witness != nil {
|
||||||
state.witness = s.witness.Copy()
|
state.witness = s.witness.Copy()
|
||||||
}
|
}
|
||||||
|
if s.accessEvents != nil {
|
||||||
|
state.accessEvents = s.accessEvents.Copy()
|
||||||
|
}
|
||||||
// Deep copy cached state objects.
|
// Deep copy cached state objects.
|
||||||
for addr, obj := range s.stateObjects {
|
for addr, obj := range s.stateObjects {
|
||||||
state.stateObjects[addr] = obj.deepCopy(state)
|
state.stateObjects[addr] = obj.deepCopy(state)
|
||||||
|
@ -743,39 +699,17 @@ func (s *StateDB) Copy() *StateDB {
|
||||||
}
|
}
|
||||||
state.logs[hash] = cpy
|
state.logs[hash] = cpy
|
||||||
}
|
}
|
||||||
// Do we need to copy the access list and transient storage?
|
|
||||||
// In practice: No. At the start of a transaction, these two lists are empty.
|
|
||||||
// In practice, we only ever copy state _between_ transactions/blocks, never
|
|
||||||
// in the middle of a transaction. However, it doesn't cost us much to copy
|
|
||||||
// empty lists, so we do it anyway to not blow up if we ever decide copy them
|
|
||||||
// in the middle of a transaction.
|
|
||||||
state.accessList = s.accessList.Copy()
|
|
||||||
state.transientStorage = s.transientStorage.Copy()
|
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot returns an identifier for the current revision of the state.
|
// Snapshot returns an identifier for the current revision of the state.
|
||||||
func (s *StateDB) Snapshot() int {
|
func (s *StateDB) Snapshot() int {
|
||||||
id := s.nextRevisionId
|
return s.journal.snapshot()
|
||||||
s.nextRevisionId++
|
|
||||||
s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()})
|
|
||||||
return id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RevertToSnapshot reverts all state changes made since the given revision.
|
// RevertToSnapshot reverts all state changes made since the given revision.
|
||||||
func (s *StateDB) RevertToSnapshot(revid int) {
|
func (s *StateDB) RevertToSnapshot(revid int) {
|
||||||
// Find the snapshot in the stack of valid snapshots.
|
s.journal.revertToSnapshot(revid, s)
|
||||||
idx := sort.Search(len(s.validRevisions), func(i int) bool {
|
|
||||||
return s.validRevisions[i].id >= revid
|
|
||||||
})
|
|
||||||
if idx == len(s.validRevisions) || s.validRevisions[idx].id != revid {
|
|
||||||
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
|
|
||||||
}
|
|
||||||
snapshot := s.validRevisions[idx].journalIndex
|
|
||||||
|
|
||||||
// Replay the journal to undo changes and remove invalidated snapshots
|
|
||||||
s.journal.revert(s, snapshot)
|
|
||||||
s.validRevisions = s.validRevisions[:idx]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRefund returns the current value of the refund counter.
|
// GetRefund returns the current value of the refund counter.
|
||||||
|
@ -882,8 +816,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// If witness building is enabled, gather all the read-only accesses
|
// If witness building is enabled, gather all the read-only accesses.
|
||||||
if s.witness != nil {
|
// Skip witness collection in Verkle mode, they will be gathered
|
||||||
|
// together at the end.
|
||||||
|
if s.witness != nil && !s.db.TrieDB().IsVerkle() {
|
||||||
// Pull in anything that has been accessed before destruction
|
// Pull in anything that has been accessed before destruction
|
||||||
for _, obj := range s.stateObjectsDestruct {
|
for _, obj := range s.stateObjectsDestruct {
|
||||||
// Skip any objects that haven't touched their storage
|
// Skip any objects that haven't touched their storage
|
||||||
|
@ -924,7 +860,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
|
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
|
||||||
// here could result in losing uncommitted changes from storage.
|
// here could result in losing uncommitted changes from storage.
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
if s.prefetcher != nil && (s.trie == nil || !s.trie.IsVerkle()) {
|
if s.prefetcher != nil {
|
||||||
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil {
|
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil {
|
||||||
log.Error("Failed to retrieve account pre-fetcher trie")
|
log.Error("Failed to retrieve account pre-fetcher trie")
|
||||||
} else {
|
} else {
|
||||||
|
@ -989,19 +925,16 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) clearJournalAndRefund() {
|
func (s *StateDB) clearJournalAndRefund() {
|
||||||
if len(s.journal.entries) > 0 {
|
s.journal.reset()
|
||||||
s.journal = newJournal()
|
|
||||||
s.refund = 0
|
s.refund = 0
|
||||||
}
|
|
||||||
s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entries
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fastDeleteStorage is the function that efficiently deletes the storage trie
|
// fastDeleteStorage is the function that efficiently deletes the storage trie
|
||||||
// of a specific account. It leverages the associated state snapshot for fast
|
// of a specific account. It leverages the associated state snapshot for fast
|
||||||
// storage iteration and constructs trie node deletion markers by creating
|
// storage iteration and constructs trie node deletion markers by creating
|
||||||
// stack trie with iterated slots.
|
// stack trie with iterated slots.
|
||||||
func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||||
iter, err := s.snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{})
|
iter, err := snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -1079,10 +1012,11 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root
|
||||||
// The fast approach can be failed if the snapshot is not fully
|
// The fast approach can be failed if the snapshot is not fully
|
||||||
// generated, or it's internally corrupted. Fallback to the slow
|
// generated, or it's internally corrupted. Fallback to the slow
|
||||||
// one just in case.
|
// one just in case.
|
||||||
if s.snap != nil {
|
snaps := s.db.Snapshot()
|
||||||
slots, nodes, err = s.fastDeleteStorage(addrHash, root)
|
if snaps != nil {
|
||||||
|
slots, nodes, err = s.fastDeleteStorage(snaps, addrHash, root)
|
||||||
}
|
}
|
||||||
if s.snap == nil || err != nil {
|
if snaps == nil || err != nil {
|
||||||
slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root)
|
slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1286,6 +1220,8 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
|
||||||
if err := workers.Wait(); err != nil {
|
if err := workers.Wait(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
accountReadMeters.Mark(int64(s.AccountLoaded))
|
||||||
|
storageReadMeters.Mark(int64(s.StorageLoaded))
|
||||||
accountUpdatedMeter.Mark(int64(s.AccountUpdated))
|
accountUpdatedMeter.Mark(int64(s.AccountUpdated))
|
||||||
storageUpdatedMeter.Mark(s.StorageUpdated.Load())
|
storageUpdatedMeter.Mark(s.StorageUpdated.Load())
|
||||||
accountDeletedMeter.Mark(int64(s.AccountDeleted))
|
accountDeletedMeter.Mark(int64(s.AccountDeleted))
|
||||||
|
@ -1294,7 +1230,10 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
|
||||||
accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted))
|
accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted))
|
||||||
storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated))
|
storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated))
|
||||||
storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted))
|
storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted))
|
||||||
s.AccountUpdated, s.AccountDeleted = 0, 0
|
|
||||||
|
// Clear the metric markers
|
||||||
|
s.AccountLoaded, s.AccountUpdated, s.AccountDeleted = 0, 0, 0
|
||||||
|
s.StorageLoaded = 0
|
||||||
s.StorageUpdated.Store(0)
|
s.StorageUpdated.Store(0)
|
||||||
s.StorageDeleted.Store(0)
|
s.StorageDeleted.Store(0)
|
||||||
|
|
||||||
|
@ -1315,7 +1254,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Commit dirty contract code if any exists
|
// Commit dirty contract code if any exists
|
||||||
if db := s.db.DiskDB(); db != nil && len(ret.codes) > 0 {
|
if db := s.db.TrieDB().Disk(); db != nil && len(ret.codes) > 0 {
|
||||||
batch := db.NewBatch()
|
batch := db.NewBatch()
|
||||||
for _, code := range ret.codes {
|
for _, code := range ret.codes {
|
||||||
rawdb.WriteCode(batch, code.hash, code.blob)
|
rawdb.WriteCode(batch, code.hash, code.blob)
|
||||||
|
@ -1326,18 +1265,16 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU
|
||||||
}
|
}
|
||||||
if !ret.empty() {
|
if !ret.empty() {
|
||||||
// If snapshotting is enabled, update the snapshot tree with this new version
|
// If snapshotting is enabled, update the snapshot tree with this new version
|
||||||
if s.snap != nil {
|
if snap := s.db.Snapshot(); snap != nil {
|
||||||
s.snap = nil
|
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := s.snaps.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil {
|
if err := snap.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil {
|
||||||
log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err)
|
log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err)
|
||||||
}
|
}
|
||||||
// Keep 128 diff layers in the memory, persistent layer is 129th.
|
// Keep 128 diff layers in the memory, persistent layer is 129th.
|
||||||
// - head layer is paired with HEAD state
|
// - head layer is paired with HEAD state
|
||||||
// - head-1 layer is paired with HEAD-1 state
|
// - head-1 layer is paired with HEAD-1 state
|
||||||
// - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state
|
// - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state
|
||||||
if err := s.snaps.Cap(ret.root, TriesInMemory); err != nil {
|
if err := snap.Cap(ret.root, TriesInMemory); err != nil {
|
||||||
log.Warn("Failed to cap snapshot tree", "root", ret.root, "layers", TriesInMemory, "err", err)
|
log.Warn("Failed to cap snapshot tree", "root", ret.root, "layers", TriesInMemory, "err", err)
|
||||||
}
|
}
|
||||||
s.SnapshotCommits += time.Since(start)
|
s.SnapshotCommits += time.Since(start)
|
||||||
|
@ -1352,6 +1289,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU
|
||||||
s.TrieDBCommits += time.Since(start)
|
s.TrieDBCommits += time.Since(start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s.reader, _ = s.db.Reader(s.originalRoot)
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1419,7 +1357,7 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d
|
||||||
// AddAddressToAccessList adds the given address to the access list
|
// AddAddressToAccessList adds the given address to the access list
|
||||||
func (s *StateDB) AddAddressToAccessList(addr common.Address) {
|
func (s *StateDB) AddAddressToAccessList(addr common.Address) {
|
||||||
if s.accessList.AddAddress(addr) {
|
if s.accessList.AddAddress(addr) {
|
||||||
s.journal.append(accessListAddAccountChange{&addr})
|
s.journal.accessListAddAccount(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1431,13 +1369,10 @@ func (s *StateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) {
|
||||||
// scope of 'address' without having the 'address' become already added
|
// scope of 'address' without having the 'address' become already added
|
||||||
// to the access list (via call-variant, create, etc).
|
// to the access list (via call-variant, create, etc).
|
||||||
// Better safe than sorry, though
|
// Better safe than sorry, though
|
||||||
s.journal.append(accessListAddAccountChange{&addr})
|
s.journal.accessListAddAccount(addr)
|
||||||
}
|
}
|
||||||
if slotMod {
|
if slotMod {
|
||||||
s.journal.append(accessListAddSlotChange{
|
s.journal.accessListAddSlot(addr, slot)
|
||||||
address: &addr,
|
|
||||||
slot: &slot,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1470,6 +1405,7 @@ func (s *StateDB) markUpdate(addr common.Address) {
|
||||||
s.mutations[addr].typ = update
|
s.mutations[addr].typ = update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PointCache returns the point cache used by verkle tree.
|
||||||
func (s *StateDB) PointCache() *utils.PointCache {
|
func (s *StateDB) PointCache() *utils.PointCache {
|
||||||
return s.db.PointCache()
|
return s.db.PointCache()
|
||||||
}
|
}
|
||||||
|
@ -1478,3 +1414,7 @@ func (s *StateDB) PointCache() *utils.PointCache {
|
||||||
func (s *StateDB) Witness() *stateless.Witness {
|
func (s *StateDB) Witness() *stateless.Witness {
|
||||||
return s.witness
|
return s.witness
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) AccessEvents() *AccessEvents {
|
||||||
|
return s.accessEvents
|
||||||
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction
|
||||||
args: make([]int64, 1),
|
args: make([]int64, 1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SetState",
|
name: "SetStorage",
|
||||||
fn: func(a testAction, s *StateDB) {
|
fn: func(a testAction, s *StateDB) {
|
||||||
var key, val common.Hash
|
var key, val common.Hash
|
||||||
binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
|
binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
|
||||||
|
@ -197,7 +197,6 @@ func (test *stateTest) run() bool {
|
||||||
}
|
}
|
||||||
disk = rawdb.NewMemoryDatabase()
|
disk = rawdb.NewMemoryDatabase()
|
||||||
tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults})
|
tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults})
|
||||||
sdb = NewDatabaseWithNodeDB(disk, tdb)
|
|
||||||
byzantium = rand.Intn(2) == 0
|
byzantium = rand.Intn(2) == 0
|
||||||
)
|
)
|
||||||
defer disk.Close()
|
defer disk.Close()
|
||||||
|
@ -217,7 +216,7 @@ func (test *stateTest) run() bool {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
root = roots[len(roots)-1]
|
root = roots[len(roots)-1]
|
||||||
}
|
}
|
||||||
state, err := New(root, sdb, snaps)
|
state, err := New(root, NewDatabase(tdb, snaps))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ package state
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"math"
|
"math"
|
||||||
|
@ -53,8 +52,9 @@ func TestUpdateLeaks(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
tdb = triedb.NewDatabase(db, nil)
|
tdb = triedb.NewDatabase(db, nil)
|
||||||
|
sdb = NewDatabase(tdb, nil)
|
||||||
)
|
)
|
||||||
state, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(db, tdb), nil)
|
state, _ := New(types.EmptyRootHash, sdb)
|
||||||
|
|
||||||
// Update it with some accounts
|
// Update it with some accounts
|
||||||
for i := byte(0); i < 255; i++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
|
@ -90,8 +90,8 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
finalDb := rawdb.NewMemoryDatabase()
|
finalDb := rawdb.NewMemoryDatabase()
|
||||||
transNdb := triedb.NewDatabase(transDb, nil)
|
transNdb := triedb.NewDatabase(transDb, nil)
|
||||||
finalNdb := triedb.NewDatabase(finalDb, nil)
|
finalNdb := triedb.NewDatabase(finalDb, nil)
|
||||||
transState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(transDb, transNdb), nil)
|
transState, _ := New(types.EmptyRootHash, NewDatabase(transNdb, nil))
|
||||||
finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil)
|
finalState, _ := New(types.EmptyRootHash, NewDatabase(finalNdb, nil))
|
||||||
|
|
||||||
modify := func(state *StateDB, addr common.Address, i, tweak byte) {
|
modify := func(state *StateDB, addr common.Address, i, tweak byte) {
|
||||||
state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak)), tracing.BalanceChangeUnspecified)
|
state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak)), tracing.BalanceChangeUnspecified)
|
||||||
|
@ -166,7 +166,7 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
// https://github.com/ethereum/go-ethereum/pull/15549.
|
// https://github.com/ethereum/go-ethereum/pull/15549.
|
||||||
func TestCopy(t *testing.T) {
|
func TestCopy(t *testing.T) {
|
||||||
// Create a random state test to copy and modify "independently"
|
// Create a random state test to copy and modify "independently"
|
||||||
orig, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
orig, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||||
|
|
||||||
for i := byte(0); i < 255; i++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||||
|
@ -230,8 +230,8 @@ func TestCopy(t *testing.T) {
|
||||||
// TestCopyWithDirtyJournal tests if Copy can correct create a equal copied
|
// TestCopyWithDirtyJournal tests if Copy can correct create a equal copied
|
||||||
// stateDB with dirty journal present.
|
// stateDB with dirty journal present.
|
||||||
func TestCopyWithDirtyJournal(t *testing.T) {
|
func TestCopyWithDirtyJournal(t *testing.T) {
|
||||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
db := NewDatabaseForTesting()
|
||||||
orig, _ := New(types.EmptyRootHash, db, nil)
|
orig, _ := New(types.EmptyRootHash, db)
|
||||||
|
|
||||||
// Fill up the initial states
|
// Fill up the initial states
|
||||||
for i := byte(0); i < 255; i++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
|
@ -241,7 +241,7 @@ func TestCopyWithDirtyJournal(t *testing.T) {
|
||||||
orig.updateStateObject(obj)
|
orig.updateStateObject(obj)
|
||||||
}
|
}
|
||||||
root, _ := orig.Commit(0, true)
|
root, _ := orig.Commit(0, true)
|
||||||
orig, _ = New(root, db, nil)
|
orig, _ = New(root, db)
|
||||||
|
|
||||||
// modify all in memory without finalizing
|
// modify all in memory without finalizing
|
||||||
for i := byte(0); i < 255; i++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
|
@ -274,8 +274,8 @@ func TestCopyWithDirtyJournal(t *testing.T) {
|
||||||
// It then proceeds to make changes to S1. Those changes are _not_ supposed
|
// It then proceeds to make changes to S1. Those changes are _not_ supposed
|
||||||
// to affect S2. This test checks that the copy properly deep-copies the objectstate
|
// to affect S2. This test checks that the copy properly deep-copies the objectstate
|
||||||
func TestCopyObjectState(t *testing.T) {
|
func TestCopyObjectState(t *testing.T) {
|
||||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
db := NewDatabaseForTesting()
|
||||||
orig, _ := New(types.EmptyRootHash, db, nil)
|
orig, _ := New(types.EmptyRootHash, db)
|
||||||
|
|
||||||
// Fill up the initial states
|
// Fill up the initial states
|
||||||
for i := byte(0); i < 5; i++ {
|
for i := byte(0); i < 5; i++ {
|
||||||
|
@ -360,7 +360,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
||||||
args: make([]int64, 1),
|
args: make([]int64, 1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SetState",
|
name: "SetStorage",
|
||||||
fn: func(a testAction, s *StateDB) {
|
fn: func(a testAction, s *StateDB) {
|
||||||
var key, val common.Hash
|
var key, val common.Hash
|
||||||
binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
|
binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
|
||||||
|
@ -372,6 +372,12 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
||||||
{
|
{
|
||||||
name: "SetCode",
|
name: "SetCode",
|
||||||
fn: func(a testAction, s *StateDB) {
|
fn: func(a testAction, s *StateDB) {
|
||||||
|
// SetCode can only be performed in case the addr does
|
||||||
|
// not already hold code
|
||||||
|
if c := s.GetCode(addr); len(c) > 0 {
|
||||||
|
// no-op
|
||||||
|
return
|
||||||
|
}
|
||||||
code := make([]byte, 16)
|
code := make([]byte, 16)
|
||||||
binary.BigEndian.PutUint64(code, uint64(a.args[0]))
|
binary.BigEndian.PutUint64(code, uint64(a.args[0]))
|
||||||
binary.BigEndian.PutUint64(code[8:], uint64(a.args[1]))
|
binary.BigEndian.PutUint64(code[8:], uint64(a.args[1]))
|
||||||
|
@ -521,7 +527,7 @@ func (test *snapshotTest) String() string {
|
||||||
func (test *snapshotTest) run() bool {
|
func (test *snapshotTest) run() bool {
|
||||||
// Run all actions and create snapshots.
|
// Run all actions and create snapshots.
|
||||||
var (
|
var (
|
||||||
state, _ = New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
state, _ = New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||||
snapshotRevs = make([]int, len(test.snapshots))
|
snapshotRevs = make([]int, len(test.snapshots))
|
||||||
sindex = 0
|
sindex = 0
|
||||||
checkstates = make([]*StateDB, len(test.snapshots))
|
checkstates = make([]*StateDB, len(test.snapshots))
|
||||||
|
@ -693,7 +699,7 @@ func TestTouchDelete(t *testing.T) {
|
||||||
s := newStateEnv()
|
s := newStateEnv()
|
||||||
s.state.getOrNewStateObject(common.Address{})
|
s.state.getOrNewStateObject(common.Address{})
|
||||||
root, _ := s.state.Commit(0, false)
|
root, _ := s.state.Commit(0, false)
|
||||||
s.state, _ = New(root, s.state.db, s.state.snaps)
|
s.state, _ = New(root, s.state.db)
|
||||||
|
|
||||||
snapshot := s.state.Snapshot()
|
snapshot := s.state.Snapshot()
|
||||||
s.state.AddBalance(common.Address{}, new(uint256.Int), tracing.BalanceChangeUnspecified)
|
s.state.AddBalance(common.Address{}, new(uint256.Int), tracing.BalanceChangeUnspecified)
|
||||||
|
@ -710,7 +716,7 @@ func TestTouchDelete(t *testing.T) {
|
||||||
// TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy.
|
// TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy.
|
||||||
// See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512
|
// See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512
|
||||||
func TestCopyOfCopy(t *testing.T) {
|
func TestCopyOfCopy(t *testing.T) {
|
||||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
state, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||||
addr := common.HexToAddress("aaaa")
|
addr := common.HexToAddress("aaaa")
|
||||||
state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified)
|
state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified)
|
||||||
|
|
||||||
|
@ -727,8 +733,8 @@ func TestCopyOfCopy(t *testing.T) {
|
||||||
//
|
//
|
||||||
// See https://github.com/ethereum/go-ethereum/issues/20106.
|
// See https://github.com/ethereum/go-ethereum/issues/20106.
|
||||||
func TestCopyCommitCopy(t *testing.T) {
|
func TestCopyCommitCopy(t *testing.T) {
|
||||||
tdb := NewDatabase(rawdb.NewMemoryDatabase())
|
tdb := NewDatabaseForTesting()
|
||||||
state, _ := New(types.EmptyRootHash, tdb, nil)
|
state, _ := New(types.EmptyRootHash, tdb)
|
||||||
|
|
||||||
// Create an account and check if the retrieved balance is correct
|
// Create an account and check if the retrieved balance is correct
|
||||||
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
||||||
|
@ -781,7 +787,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Commit state, ensure states can be loaded from disk
|
// Commit state, ensure states can be loaded from disk
|
||||||
root, _ := state.Commit(0, false)
|
root, _ := state.Commit(0, false)
|
||||||
state, _ = New(root, tdb, nil)
|
state, _ = New(root, tdb)
|
||||||
if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||||
t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42)
|
t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
|
@ -801,7 +807,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||||
//
|
//
|
||||||
// See https://github.com/ethereum/go-ethereum/issues/20106.
|
// See https://github.com/ethereum/go-ethereum/issues/20106.
|
||||||
func TestCopyCopyCommitCopy(t *testing.T) {
|
func TestCopyCopyCommitCopy(t *testing.T) {
|
||||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
state, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||||
|
|
||||||
// Create an account and check if the retrieved balance is correct
|
// Create an account and check if the retrieved balance is correct
|
||||||
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
||||||
|
@ -870,8 +876,8 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
||||||
|
|
||||||
// TestCommitCopy tests the copy from a committed state is not fully functional.
|
// TestCommitCopy tests the copy from a committed state is not fully functional.
|
||||||
func TestCommitCopy(t *testing.T) {
|
func TestCommitCopy(t *testing.T) {
|
||||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
db := NewDatabaseForTesting()
|
||||||
state, _ := New(types.EmptyRootHash, db, nil)
|
state, _ := New(types.EmptyRootHash, db)
|
||||||
|
|
||||||
// Create an account and check if the retrieved balance is correct
|
// Create an account and check if the retrieved balance is correct
|
||||||
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
||||||
|
@ -896,7 +902,7 @@ func TestCommitCopy(t *testing.T) {
|
||||||
}
|
}
|
||||||
root, _ := state.Commit(0, true)
|
root, _ := state.Commit(0, true)
|
||||||
|
|
||||||
state, _ = New(root, db, nil)
|
state, _ = New(root, db)
|
||||||
state.SetState(addr, skey2, sval2)
|
state.SetState(addr, skey2, sval2)
|
||||||
state.Commit(1, true)
|
state.Commit(1, true)
|
||||||
|
|
||||||
|
@ -909,10 +915,10 @@ func TestCommitCopy(t *testing.T) {
|
||||||
t.Fatalf("unexpected code: have %x", code)
|
t.Fatalf("unexpected code: have %x", code)
|
||||||
}
|
}
|
||||||
// Miss slots because of non-functional trie after commit
|
// Miss slots because of non-functional trie after commit
|
||||||
if val := copied.GetState(addr, skey1); val != (common.Hash{}) {
|
if val := copied.GetState(addr, skey1); val != sval1 {
|
||||||
t.Fatalf("unexpected storage slot: have %x", sval1)
|
t.Fatalf("unexpected storage slot: have %x", val)
|
||||||
}
|
}
|
||||||
if val := copied.GetCommittedState(addr, skey1); val != (common.Hash{}) {
|
if val := copied.GetCommittedState(addr, skey1); val != sval1 {
|
||||||
t.Fatalf("unexpected storage slot: have %x", val)
|
t.Fatalf("unexpected storage slot: have %x", val)
|
||||||
}
|
}
|
||||||
// Slots cached in the stateDB, available after commit
|
// Slots cached in the stateDB, available after commit
|
||||||
|
@ -922,9 +928,6 @@ func TestCommitCopy(t *testing.T) {
|
||||||
if val := copied.GetCommittedState(addr, skey2); val != sval2 {
|
if val := copied.GetCommittedState(addr, skey2); val != sval2 {
|
||||||
t.Fatalf("unexpected storage slot: have %x", val)
|
t.Fatalf("unexpected storage slot: have %x", val)
|
||||||
}
|
}
|
||||||
if !errors.Is(copied.Error(), trie.ErrCommitted) {
|
|
||||||
t.Fatalf("unexpected state error, %v", copied.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDeleteCreateRevert tests a weird state transition corner case that we hit
|
// TestDeleteCreateRevert tests a weird state transition corner case that we hit
|
||||||
|
@ -937,13 +940,13 @@ func TestCommitCopy(t *testing.T) {
|
||||||
// first, but the journal wiped the entire state object on create-revert.
|
// first, but the journal wiped the entire state object on create-revert.
|
||||||
func TestDeleteCreateRevert(t *testing.T) {
|
func TestDeleteCreateRevert(t *testing.T) {
|
||||||
// Create an initial state with a single contract
|
// Create an initial state with a single contract
|
||||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
state, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||||
|
|
||||||
addr := common.BytesToAddress([]byte("so"))
|
addr := common.BytesToAddress([]byte("so"))
|
||||||
state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
|
state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
|
||||||
|
|
||||||
root, _ := state.Commit(0, false)
|
root, _ := state.Commit(0, false)
|
||||||
state, _ = New(root, state.db, state.snaps)
|
state, _ = New(root, state.db)
|
||||||
|
|
||||||
// Simulate self-destructing in one transaction, then create-reverting in another
|
// Simulate self-destructing in one transaction, then create-reverting in another
|
||||||
state.SelfDestruct(addr)
|
state.SelfDestruct(addr)
|
||||||
|
@ -955,7 +958,7 @@ func TestDeleteCreateRevert(t *testing.T) {
|
||||||
|
|
||||||
// Commit the entire state and make sure we don't crash and have the correct state
|
// Commit the entire state and make sure we don't crash and have the correct state
|
||||||
root, _ = state.Commit(0, true)
|
root, _ = state.Commit(0, true)
|
||||||
state, _ = New(root, state.db, state.snaps)
|
state, _ = New(root, state.db)
|
||||||
|
|
||||||
if state.getStateObject(addr) != nil {
|
if state.getStateObject(addr) != nil {
|
||||||
t.Fatalf("self-destructed contract came alive")
|
t.Fatalf("self-destructed contract came alive")
|
||||||
|
@ -986,10 +989,10 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
|
||||||
CleanCacheSize: 0,
|
CleanCacheSize: 0,
|
||||||
}}) // disable caching
|
}}) // disable caching
|
||||||
}
|
}
|
||||||
db := NewDatabaseWithNodeDB(memDb, tdb)
|
db := NewDatabase(tdb, nil)
|
||||||
|
|
||||||
var root common.Hash
|
var root common.Hash
|
||||||
state, _ := New(types.EmptyRootHash, db, nil)
|
state, _ := New(types.EmptyRootHash, db)
|
||||||
addr := common.BytesToAddress([]byte("so"))
|
addr := common.BytesToAddress([]byte("so"))
|
||||||
{
|
{
|
||||||
state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
|
state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
|
||||||
|
@ -1003,7 +1006,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
|
||||||
tdb.Commit(root, false)
|
tdb.Commit(root, false)
|
||||||
}
|
}
|
||||||
// Create a new state on the old root
|
// Create a new state on the old root
|
||||||
state, _ = New(root, db, nil)
|
state, _ = New(root, db)
|
||||||
// Now we clear out the memdb
|
// Now we clear out the memdb
|
||||||
it := memDb.NewIterator(nil, nil)
|
it := memDb.NewIterator(nil, nil)
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
|
@ -1036,9 +1039,8 @@ func TestStateDBAccessList(t *testing.T) {
|
||||||
return common.HexToHash(a)
|
return common.HexToHash(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
memDb := rawdb.NewMemoryDatabase()
|
db := NewDatabaseForTesting()
|
||||||
db := NewDatabase(memDb)
|
state, _ := New(types.EmptyRootHash, db)
|
||||||
state, _ := New(types.EmptyRootHash, db, nil)
|
|
||||||
state.accessList = newAccessList()
|
state.accessList = newAccessList()
|
||||||
|
|
||||||
verifyAddrs := func(astrings ...string) {
|
verifyAddrs := func(astrings ...string) {
|
||||||
|
@ -1207,9 +1209,9 @@ func TestFlushOrderDataLoss(t *testing.T) {
|
||||||
// Create a state trie with many accounts and slots
|
// Create a state trie with many accounts and slots
|
||||||
var (
|
var (
|
||||||
memdb = rawdb.NewMemoryDatabase()
|
memdb = rawdb.NewMemoryDatabase()
|
||||||
triedb = triedb.NewDatabase(memdb, nil)
|
tdb = triedb.NewDatabase(memdb, triedb.HashDefaults)
|
||||||
statedb = NewDatabaseWithNodeDB(memdb, triedb)
|
statedb = NewDatabase(tdb, nil)
|
||||||
state, _ = New(types.EmptyRootHash, statedb, nil)
|
state, _ = New(types.EmptyRootHash, statedb)
|
||||||
)
|
)
|
||||||
for a := byte(0); a < 10; a++ {
|
for a := byte(0); a < 10; a++ {
|
||||||
state.CreateAccount(common.Address{a})
|
state.CreateAccount(common.Address{a})
|
||||||
|
@ -1221,15 +1223,15 @@ func TestFlushOrderDataLoss(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to commit state trie: %v", err)
|
t.Fatalf("failed to commit state trie: %v", err)
|
||||||
}
|
}
|
||||||
triedb.Reference(root, common.Hash{})
|
tdb.Reference(root, common.Hash{})
|
||||||
if err := triedb.Cap(1024); err != nil {
|
if err := tdb.Cap(1024); err != nil {
|
||||||
t.Fatalf("failed to cap trie dirty cache: %v", err)
|
t.Fatalf("failed to cap trie dirty cache: %v", err)
|
||||||
}
|
}
|
||||||
if err := triedb.Commit(root, false); err != nil {
|
if err := tdb.Commit(root, false); err != nil {
|
||||||
t.Fatalf("failed to commit state trie: %v", err)
|
t.Fatalf("failed to commit state trie: %v", err)
|
||||||
}
|
}
|
||||||
// Reopen the state trie from flushed disk and verify it
|
// Reopen the state trie from flushed disk and verify it
|
||||||
state, err = New(root, NewDatabase(memdb), nil)
|
state, err = New(root, NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to reopen state trie: %v", err)
|
t.Fatalf("failed to reopen state trie: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1243,9 +1245,8 @@ func TestFlushOrderDataLoss(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStateDBTransientStorage(t *testing.T) {
|
func TestStateDBTransientStorage(t *testing.T) {
|
||||||
memDb := rawdb.NewMemoryDatabase()
|
db := NewDatabaseForTesting()
|
||||||
db := NewDatabase(memDb)
|
state, _ := New(types.EmptyRootHash, db)
|
||||||
state, _ := New(types.EmptyRootHash, db, nil)
|
|
||||||
|
|
||||||
key := common.Hash{0x01}
|
key := common.Hash{0x01}
|
||||||
value := common.Hash{0x02}
|
value := common.Hash{0x02}
|
||||||
|
@ -1280,9 +1281,9 @@ func TestDeleteStorage(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
disk = rawdb.NewMemoryDatabase()
|
disk = rawdb.NewMemoryDatabase()
|
||||||
tdb = triedb.NewDatabase(disk, nil)
|
tdb = triedb.NewDatabase(disk, nil)
|
||||||
db = NewDatabaseWithNodeDB(disk, tdb)
|
|
||||||
snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash)
|
snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash)
|
||||||
state, _ = New(types.EmptyRootHash, db, snaps)
|
db = NewDatabase(tdb, snaps)
|
||||||
|
state, _ = New(types.EmptyRootHash, db)
|
||||||
addr = common.HexToAddress("0x1")
|
addr = common.HexToAddress("0x1")
|
||||||
)
|
)
|
||||||
// Initialize account and populate storage
|
// Initialize account and populate storage
|
||||||
|
@ -1294,9 +1295,10 @@ func TestDeleteStorage(t *testing.T) {
|
||||||
state.SetState(addr, slot, value)
|
state.SetState(addr, slot, value)
|
||||||
}
|
}
|
||||||
root, _ := state.Commit(0, true)
|
root, _ := state.Commit(0, true)
|
||||||
|
|
||||||
// Init phase done, create two states, one with snap and one without
|
// Init phase done, create two states, one with snap and one without
|
||||||
fastState, _ := New(root, db, snaps)
|
fastState, _ := New(root, NewDatabase(tdb, snaps))
|
||||||
slowState, _ := New(root, db, nil)
|
slowState, _ := New(root, NewDatabase(tdb, nil))
|
||||||
|
|
||||||
obj := fastState.getOrNewStateObject(addr)
|
obj := fastState.getOrNewStateObject(addr)
|
||||||
storageRoot := obj.data.Root
|
storageRoot := obj.data.Root
|
||||||
|
@ -1334,8 +1336,8 @@ func TestStorageDirtiness(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
disk = rawdb.NewMemoryDatabase()
|
disk = rawdb.NewMemoryDatabase()
|
||||||
tdb = triedb.NewDatabase(disk, nil)
|
tdb = triedb.NewDatabase(disk, nil)
|
||||||
db = NewDatabaseWithNodeDB(disk, tdb)
|
db = NewDatabase(tdb, nil)
|
||||||
state, _ = New(types.EmptyRootHash, db, nil)
|
state, _ = New(types.EmptyRootHash, db)
|
||||||
addr = common.HexToAddress("0x1")
|
addr = common.HexToAddress("0x1")
|
||||||
checkDirty = func(key common.Hash, value common.Hash, dirty bool) {
|
checkDirty = func(key common.Hash, value common.Hash, dirty bool) {
|
||||||
obj := state.getStateObject(addr)
|
obj := state.getStateObject(addr)
|
||||||
|
|
|
@ -53,8 +53,8 @@ func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, c
|
||||||
}
|
}
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
nodeDb := triedb.NewDatabase(db, config)
|
nodeDb := triedb.NewDatabase(db, config)
|
||||||
sdb := NewDatabaseWithNodeDB(db, nodeDb)
|
sdb := NewDatabase(nodeDb, nil)
|
||||||
state, _ := New(types.EmptyRootHash, sdb, nil)
|
state, _ := New(types.EmptyRootHash, sdb)
|
||||||
|
|
||||||
// Fill it with some arbitrary data
|
// Fill it with some arbitrary data
|
||||||
var accounts []*testAccount
|
var accounts []*testAccount
|
||||||
|
@ -94,7 +94,7 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, scheme string, root com
|
||||||
config.PathDB = pathdb.Defaults
|
config.PathDB = pathdb.Defaults
|
||||||
}
|
}
|
||||||
// Check root availability and state contents
|
// Check root availability and state contents
|
||||||
state, err := New(root, NewDatabaseWithConfig(db, &config), nil)
|
state, err := New(root, NewDatabase(triedb.NewDatabase(db, &config), nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create state trie at %x: %v", root, err)
|
t.Fatalf("failed to create state trie at %x: %v", root, err)
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ func checkStateConsistency(db ethdb.Database, scheme string, root common.Hash) e
|
||||||
if scheme == rawdb.PathScheme {
|
if scheme == rawdb.PathScheme {
|
||||||
config.PathDB = pathdb.Defaults
|
config.PathDB = pathdb.Defaults
|
||||||
}
|
}
|
||||||
state, err := New(root, NewDatabaseWithConfig(db, config), nil)
|
state, err := New(root, NewDatabase(triedb.NewDatabase(db, config), nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ var (
|
||||||
//
|
//
|
||||||
// Note, the prefetcher's API is not thread safe.
|
// Note, the prefetcher's API is not thread safe.
|
||||||
type triePrefetcher struct {
|
type triePrefetcher struct {
|
||||||
|
verkle bool // Flag whether the prefetcher is in verkle mode
|
||||||
db Database // Database to fetch trie nodes through
|
db Database // Database to fetch trie nodes through
|
||||||
root common.Hash // Root hash of the account trie for metrics
|
root common.Hash // Root hash of the account trie for metrics
|
||||||
fetchers map[string]*subfetcher // Subfetchers for each trie
|
fetchers map[string]*subfetcher // Subfetchers for each trie
|
||||||
|
@ -66,6 +67,7 @@ type triePrefetcher struct {
|
||||||
func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher {
|
func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher {
|
||||||
prefix := triePrefetchMetricsPrefix + namespace
|
prefix := triePrefetchMetricsPrefix + namespace
|
||||||
return &triePrefetcher{
|
return &triePrefetcher{
|
||||||
|
verkle: db.TrieDB().IsVerkle(),
|
||||||
db: db,
|
db: db,
|
||||||
root: root,
|
root: root,
|
||||||
fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map
|
fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map
|
||||||
|
@ -196,12 +198,18 @@ func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie {
|
||||||
func (p *triePrefetcher) used(owner common.Hash, root common.Hash, used [][]byte) {
|
func (p *triePrefetcher) used(owner common.Hash, root common.Hash, used [][]byte) {
|
||||||
if fetcher := p.fetchers[p.trieID(owner, root)]; fetcher != nil {
|
if fetcher := p.fetchers[p.trieID(owner, root)]; fetcher != nil {
|
||||||
fetcher.wait() // ensure the fetcher's idle before poking in its internals
|
fetcher.wait() // ensure the fetcher's idle before poking in its internals
|
||||||
fetcher.used = used
|
fetcher.used = append(fetcher.used, used...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// trieID returns an unique trie identifier consists the trie owner and root hash.
|
// trieID returns an unique trie identifier consists the trie owner and root hash.
|
||||||
func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string {
|
func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string {
|
||||||
|
// The trie in verkle is only identified by state root
|
||||||
|
if p.verkle {
|
||||||
|
return p.root.Hex()
|
||||||
|
}
|
||||||
|
// The trie in merkle is either identified by state root (account trie),
|
||||||
|
// or identified by the owner and trie root (storage trie)
|
||||||
trieID := make([]byte, common.HashLength*2)
|
trieID := make([]byte, common.HashLength*2)
|
||||||
copy(trieID, owner.Bytes())
|
copy(trieID, owner.Bytes())
|
||||||
copy(trieID[common.HashLength:], root.Bytes())
|
copy(trieID[common.HashLength:], root.Bytes())
|
||||||
|
@ -320,29 +328,47 @@ func (sf *subfetcher) terminate(async bool) {
|
||||||
<-sf.term
|
<-sf.term
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// openTrie resolves the target trie from database for prefetching.
|
||||||
|
func (sf *subfetcher) openTrie() error {
|
||||||
|
// Open the verkle tree if the sub-fetcher is in verkle mode. Note, there is
|
||||||
|
// only a single fetcher for verkle.
|
||||||
|
if sf.db.TrieDB().IsVerkle() {
|
||||||
|
tr, err := sf.db.OpenTrie(sf.state)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Trie prefetcher failed opening verkle trie", "root", sf.root, "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sf.trie = tr
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Open the merkle tree if the sub-fetcher is in merkle mode
|
||||||
|
if sf.owner == (common.Hash{}) {
|
||||||
|
tr, err := sf.db.OpenTrie(sf.state)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Trie prefetcher failed opening account trie", "root", sf.root, "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sf.trie = tr
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
tr, err := sf.db.OpenStorageTrie(sf.state, sf.addr, sf.root, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Trie prefetcher failed opening storage trie", "root", sf.root, "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sf.trie = tr
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// loop loads newly-scheduled trie tasks as they are received and loads them, stopping
|
// loop loads newly-scheduled trie tasks as they are received and loads them, stopping
|
||||||
// when requested.
|
// when requested.
|
||||||
func (sf *subfetcher) loop() {
|
func (sf *subfetcher) loop() {
|
||||||
// No matter how the loop stops, signal anyone waiting that it's terminated
|
// No matter how the loop stops, signal anyone waiting that it's terminated
|
||||||
defer close(sf.term)
|
defer close(sf.term)
|
||||||
|
|
||||||
// Start by opening the trie and stop processing if it fails
|
if err := sf.openTrie(); err != nil {
|
||||||
if sf.owner == (common.Hash{}) {
|
|
||||||
trie, err := sf.db.OpenTrie(sf.root)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sf.trie = trie
|
|
||||||
} else {
|
|
||||||
trie, err := sf.db.OpenStorageTrie(sf.state, sf.addr, sf.root, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sf.trie = trie
|
|
||||||
}
|
|
||||||
// Trie opened successfully, keep prefetching items
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-sf.wake:
|
case <-sf.wake:
|
||||||
|
|
|
@ -24,11 +24,14 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/testrand"
|
||||||
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
func filledStateDB() *StateDB {
|
func filledStateDB() *StateDB {
|
||||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
state, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||||
|
|
||||||
// Create an account and check if the retrieved balance is correct
|
// Create an account and check if the retrieved balance is correct
|
||||||
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
||||||
|
@ -62,3 +65,47 @@ func TestUseAfterTerminate(t *testing.T) {
|
||||||
t.Errorf("Prefetcher returned nil trie after terminate")
|
t.Errorf("Prefetcher returned nil trie after terminate")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVerklePrefetcher(t *testing.T) {
|
||||||
|
disk := rawdb.NewMemoryDatabase()
|
||||||
|
db := triedb.NewDatabase(disk, triedb.VerkleDefaults)
|
||||||
|
sdb := NewDatabase(db, nil)
|
||||||
|
|
||||||
|
state, err := New(types.EmptyRootHash, sdb)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to initialize state: %v", err)
|
||||||
|
}
|
||||||
|
// Create an account and check if the retrieved balance is correct
|
||||||
|
addr := testrand.Address()
|
||||||
|
skey := testrand.Hash()
|
||||||
|
sval := testrand.Hash()
|
||||||
|
|
||||||
|
state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie
|
||||||
|
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||||
|
state.SetState(addr, skey, sval) // Change the storage trie
|
||||||
|
root, _ := state.Commit(0, true)
|
||||||
|
|
||||||
|
state, _ = New(root, sdb)
|
||||||
|
sRoot := state.GetStorageRoot(addr)
|
||||||
|
fetcher := newTriePrefetcher(sdb, root, "", false)
|
||||||
|
|
||||||
|
// Read account
|
||||||
|
fetcher.prefetch(common.Hash{}, root, common.Address{}, [][]byte{
|
||||||
|
addr.Bytes(),
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
// Read storage slot
|
||||||
|
fetcher.prefetch(crypto.Keccak256Hash(addr.Bytes()), sRoot, addr, [][]byte{
|
||||||
|
skey.Bytes(),
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
fetcher.terminate(false)
|
||||||
|
accountTrie := fetcher.trie(common.Hash{}, root)
|
||||||
|
storageTrie := fetcher.trie(crypto.Keccak256Hash(addr.Bytes()), sRoot)
|
||||||
|
|
||||||
|
rootA := accountTrie.Hash()
|
||||||
|
rootB := storageTrie.Hash()
|
||||||
|
if rootA != rootB {
|
||||||
|
t.Fatal("Two different tries are retrieved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
@ -54,7 +53,7 @@ func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StatePro
|
||||||
// Process returns the receipts and logs accumulated during the process and
|
// Process returns the receipts and logs accumulated during the process and
|
||||||
// returns the amount of gas that was used in the process. If any of the
|
// returns the amount of gas that was used in the process. If any of the
|
||||||
// transactions failed to execute due to insufficient gas it will return an error.
|
// transactions failed to execute due to insufficient gas it will return an error.
|
||||||
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) {
|
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
|
||||||
var (
|
var (
|
||||||
receipts types.Receipts
|
receipts types.Receipts
|
||||||
usedGas = new(uint64)
|
usedGas = new(uint64)
|
||||||
|
@ -72,36 +71,49 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
var (
|
var (
|
||||||
context vm.BlockContext
|
context vm.BlockContext
|
||||||
signer = types.MakeSigner(p.config, header.Number, header.Time)
|
signer = types.MakeSigner(p.config, header.Number, header.Time)
|
||||||
|
err error
|
||||||
)
|
)
|
||||||
context = NewEVMBlockContext(header, p.chain, nil)
|
context = NewEVMBlockContext(header, p.chain, nil)
|
||||||
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
|
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
|
||||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||||
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
||||||
}
|
}
|
||||||
|
if p.config.IsPrague(block.Number(), block.Time()) {
|
||||||
|
ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
|
||||||
|
}
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
|
|
||||||
receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
|
receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
allLogs = append(allLogs, receipt.Logs...)
|
allLogs = append(allLogs, receipt.Logs...)
|
||||||
}
|
}
|
||||||
// Fail if Shanghai not enabled and len(withdrawals) is non-zero.
|
// Read requests if Prague is enabled.
|
||||||
withdrawals := block.Withdrawals()
|
var requests types.Requests
|
||||||
if len(withdrawals) > 0 && !p.config.IsShanghai(block.Number(), block.Time()) {
|
if p.config.IsPrague(block.Number(), block.Time()) {
|
||||||
return nil, nil, 0, errors.New("withdrawals before shanghai")
|
requests, err = ParseDepositLogs(allLogs, p.config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||||
p.chain.engine.Finalize(p.chain, header, statedb, block.Body())
|
p.chain.engine.Finalize(p.chain, header, statedb, block.Body())
|
||||||
|
|
||||||
return receipts, allLogs, *usedGas, nil
|
return &ProcessResult{
|
||||||
|
Receipts: receipts,
|
||||||
|
Requests: requests,
|
||||||
|
Logs: allLogs,
|
||||||
|
GasUsed: *usedGas,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
|
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
|
||||||
|
@ -135,9 +147,14 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
||||||
}
|
}
|
||||||
*usedGas += result.UsedGas
|
*usedGas += result.UsedGas
|
||||||
|
|
||||||
|
return MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeReceipt generates the receipt object for a transaction given its execution result.
|
||||||
|
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt {
|
||||||
// Create a new receipt for the transaction, storing the intermediate root and gas used
|
// Create a new receipt for the transaction, storing the intermediate root and gas used
|
||||||
// by the tx.
|
// by the tx.
|
||||||
receipt = &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
|
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas}
|
||||||
if result.Failed() {
|
if result.Failed() {
|
||||||
receipt.Status = types.ReceiptStatusFailed
|
receipt.Status = types.ReceiptStatusFailed
|
||||||
} else {
|
} else {
|
||||||
|
@ -152,17 +169,23 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the transaction created a contract, store the creation address in the receipt.
|
// If the transaction created a contract, store the creation address in the receipt.
|
||||||
if msg.To == nil {
|
if tx.To() == nil {
|
||||||
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge the tx-local access event into the "block-local" one, in order to collect
|
||||||
|
// all values, so that the witness can be built.
|
||||||
|
if statedb.GetTrie().IsVerkle() {
|
||||||
|
statedb.AccessEvents().Merge(evm.AccessEvents)
|
||||||
|
}
|
||||||
|
|
||||||
// Set the receipt logs and create the bloom filter.
|
// Set the receipt logs and create the bloom filter.
|
||||||
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash)
|
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash)
|
||||||
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
||||||
receipt.BlockHash = blockHash
|
receipt.BlockHash = blockHash
|
||||||
receipt.BlockNumber = blockNumber
|
receipt.BlockNumber = blockNumber
|
||||||
receipt.TransactionIndex = uint(statedb.TxIndex())
|
receipt.TransactionIndex = uint(statedb.TxIndex())
|
||||||
return receipt, err
|
return receipt
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyTransaction attempts to apply a transaction to the given state database
|
// ApplyTransaction attempts to apply a transaction to the given state database
|
||||||
|
@ -184,11 +207,13 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
||||||
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
||||||
// contract. This method is exported to be used in tests.
|
// contract. This method is exported to be used in tests.
|
||||||
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
|
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
|
||||||
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil {
|
if tracer := vmenv.Config.Tracer; tracer != nil {
|
||||||
vmenv.Config.Tracer.OnSystemCallStart()
|
if tracer.OnSystemCallStart != nil {
|
||||||
|
tracer.OnSystemCallStart()
|
||||||
|
}
|
||||||
|
if tracer.OnSystemCallEnd != nil {
|
||||||
|
defer tracer.OnSystemCallEnd()
|
||||||
}
|
}
|
||||||
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil {
|
|
||||||
defer vmenv.Config.Tracer.OnSystemCallEnd()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
|
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
|
||||||
|
@ -207,3 +232,46 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
|
||||||
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
statedb.Finalise(true)
|
statedb.Finalise(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProcessParentBlockHash stores the parent block hash in the history storage contract
|
||||||
|
// as per EIP-2935.
|
||||||
|
func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
|
||||||
|
if tracer := vmenv.Config.Tracer; tracer != nil {
|
||||||
|
if tracer.OnSystemCallStart != nil {
|
||||||
|
tracer.OnSystemCallStart()
|
||||||
|
}
|
||||||
|
if tracer.OnSystemCallEnd != nil {
|
||||||
|
defer tracer.OnSystemCallEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &Message{
|
||||||
|
From: params.SystemAddress,
|
||||||
|
GasLimit: 30_000_000,
|
||||||
|
GasPrice: common.Big0,
|
||||||
|
GasFeeCap: common.Big0,
|
||||||
|
GasTipCap: common.Big0,
|
||||||
|
To: ¶ms.HistoryStorageAddress,
|
||||||
|
Data: prevHash.Bytes(),
|
||||||
|
}
|
||||||
|
vmenv.Reset(NewEVMTxContext(msg), statedb)
|
||||||
|
statedb.AddAddressToAccessList(params.HistoryStorageAddress)
|
||||||
|
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
|
statedb.Finalise(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
||||||
|
// BeaconDepositContract.
|
||||||
|
func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) (types.Requests, error) {
|
||||||
|
deposits := make(types.Requests, 0)
|
||||||
|
for _, log := range logs {
|
||||||
|
if log.Address == config.DepositContractAddress {
|
||||||
|
d, err := types.UnpackIntoDeposit(log.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to parse deposit data: %v", err)
|
||||||
|
}
|
||||||
|
deposits = append(deposits, types.NewRequest(d))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deposits, nil
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"encoding/binary"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -29,11 +30,14 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
|
"github.com/ethereum/go-verkle"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
@ -128,7 +132,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil)
|
||||||
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
|
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -288,7 +292,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
)
|
)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
for i, tt := range []struct {
|
for i, tt := range []struct {
|
||||||
|
@ -327,7 +331,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil)
|
||||||
)
|
)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
for i, tt := range []struct {
|
for i, tt := range []struct {
|
||||||
|
@ -476,18 +480,45 @@ func TestProcessVerkle(t *testing.T) {
|
||||||
// genesis := gspec.MustCommit(bcdb, triedb)
|
// genesis := gspec.MustCommit(bcdb, triedb)
|
||||||
cacheConfig := DefaultCacheConfigWithScheme("path")
|
cacheConfig := DefaultCacheConfigWithScheme("path")
|
||||||
cacheConfig.SnapshotLimit = 0
|
cacheConfig.SnapshotLimit = 0
|
||||||
blockchain, _ := NewBlockChain(bcdb, cacheConfig, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(bcdb, cacheConfig, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
txCost1 := params.TxGas
|
txCost1 := params.TxGas
|
||||||
txCost2 := params.TxGas
|
txCost2 := params.TxGas
|
||||||
contractCreationCost := intrinsicContractCreationGas + uint64(2039 /* execution costs */)
|
contractCreationCost := intrinsicContractCreationGas +
|
||||||
codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + uint64(57444 /* execution costs */)
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* creation with value */
|
||||||
|
739 /* execution costs */
|
||||||
|
codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas +
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (tx) */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at pc=0x20) */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */
|
||||||
|
params.WitnessChunkReadCost + /* SLOAD in constructor */
|
||||||
|
params.WitnessChunkWriteCost + /* SSTORE in constructor */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at PC=0x121) */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */
|
||||||
|
params.WitnessChunkReadCost + /* SLOAD in constructor */
|
||||||
|
params.WitnessChunkWriteCost + /* SSTORE in constructor */
|
||||||
|
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash for tx creation */
|
||||||
|
15*(params.WitnessChunkReadCost+params.WitnessChunkWriteCost) + /* code chunks #0..#14 */
|
||||||
|
4844 /* execution costs */
|
||||||
blockGasUsagesExpected := []uint64{
|
blockGasUsagesExpected := []uint64{
|
||||||
txCost1*2 + txCost2,
|
txCost1*2 + txCost2,
|
||||||
txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas,
|
txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas,
|
||||||
}
|
}
|
||||||
_, chain, _, _, _ := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) {
|
_, chain, _, proofs, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) {
|
||||||
gen.SetPoS()
|
gen.SetPoS()
|
||||||
|
|
||||||
// TODO need to check that the tx cost provided is the exact amount used (no remaining left-over)
|
// TODO need to check that the tx cost provided is the exact amount used (no remaining left-over)
|
||||||
|
@ -508,7 +539,17 @@ func TestProcessVerkle(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Log("inserting blocks into the chain")
|
// Check proof for both blocks
|
||||||
|
err := verkle.Verify(proofs[0], gspec.ToBlock().Root().Bytes(), chain[0].Root().Bytes(), statediffs[0])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = verkle.Verify(proofs[1], chain[0].Root().Bytes(), chain[1].Root().Bytes(), statediffs[1])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("verified verkle proof, inserting blocks into the chain")
|
||||||
|
|
||||||
endnum, err := blockchain.InsertChain(chain)
|
endnum, err := blockchain.InsertChain(chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -528,3 +569,54 @@ func TestProcessVerkle(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProcessParentBlockHash(t *testing.T) {
|
||||||
|
var (
|
||||||
|
chainConfig = params.MergedTestChainConfig
|
||||||
|
hashA = common.Hash{0x01}
|
||||||
|
hashB = common.Hash{0x02}
|
||||||
|
header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)}
|
||||||
|
parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)}
|
||||||
|
coinbase = common.Address{}
|
||||||
|
)
|
||||||
|
test := func(statedb *state.StateDB) {
|
||||||
|
statedb.SetNonce(params.HistoryStorageAddress, 1)
|
||||||
|
statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode)
|
||||||
|
statedb.IntermediateRoot(true)
|
||||||
|
|
||||||
|
vmContext := NewEVMBlockContext(header, nil, &coinbase)
|
||||||
|
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
||||||
|
ProcessParentBlockHash(header.ParentHash, evm, statedb)
|
||||||
|
|
||||||
|
vmContext = NewEVMBlockContext(parent, nil, &coinbase)
|
||||||
|
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
||||||
|
ProcessParentBlockHash(parent.ParentHash, evm, statedb)
|
||||||
|
|
||||||
|
// make sure that the state is correct
|
||||||
|
if have := getParentBlockHash(statedb, 1); have != hashA {
|
||||||
|
t.Errorf("want parent hash %v, have %v", hashA, have)
|
||||||
|
}
|
||||||
|
if have := getParentBlockHash(statedb, 0); have != hashB {
|
||||||
|
t.Errorf("want parent hash %v, have %v", hashB, have)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Run("MPT", func(t *testing.T) {
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
|
test(statedb)
|
||||||
|
})
|
||||||
|
t.Run("Verkle", func(t *testing.T) {
|
||||||
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme)
|
||||||
|
cacheConfig.SnapshotLimit = 0
|
||||||
|
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true))
|
||||||
|
statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabase(triedb, nil))
|
||||||
|
test(statedb)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash {
|
||||||
|
ringIndex := number % params.HistoryServeWindow
|
||||||
|
var key common.Hash
|
||||||
|
binary.BigEndian.PutUint64(key[24:], ringIndex)
|
||||||
|
return statedb.GetState(params.HistoryStorageAddress, key)
|
||||||
|
}
|
||||||
|
|
|
@ -142,10 +142,13 @@ type Message struct {
|
||||||
BlobGasFeeCap *big.Int
|
BlobGasFeeCap *big.Int
|
||||||
BlobHashes []common.Hash
|
BlobHashes []common.Hash
|
||||||
|
|
||||||
// When SkipAccountChecks is true, the message nonce is not checked against the
|
// When SkipNonceChecks is true, the message nonce is not checked against the
|
||||||
// account nonce in state. It also disables checking that the sender is an EOA.
|
// account nonce in state.
|
||||||
// This field will be set to true for operations like RPC eth_call.
|
// This field will be set to true for operations like RPC eth_call.
|
||||||
SkipAccountChecks bool
|
SkipNonceChecks bool
|
||||||
|
|
||||||
|
// When SkipFromEOACheck is true, the message sender is not checked to be an EOA.
|
||||||
|
SkipFromEOACheck bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionToMessage converts a transaction into a Message.
|
// TransactionToMessage converts a transaction into a Message.
|
||||||
|
@ -160,7 +163,8 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
|
||||||
Value: tx.Value(),
|
Value: tx.Value(),
|
||||||
Data: tx.Data(),
|
Data: tx.Data(),
|
||||||
AccessList: tx.AccessList(),
|
AccessList: tx.AccessList(),
|
||||||
SkipAccountChecks: false,
|
SkipNonceChecks: false,
|
||||||
|
SkipFromEOACheck: false,
|
||||||
BlobHashes: tx.BlobHashes(),
|
BlobHashes: tx.BlobHashes(),
|
||||||
BlobGasFeeCap: tx.BlobGasFeeCap(),
|
BlobGasFeeCap: tx.BlobGasFeeCap(),
|
||||||
}
|
}
|
||||||
|
@ -280,7 +284,7 @@ func (st *StateTransition) buyGas() error {
|
||||||
func (st *StateTransition) preCheck() error {
|
func (st *StateTransition) preCheck() error {
|
||||||
// Only check transactions that are not fake
|
// Only check transactions that are not fake
|
||||||
msg := st.msg
|
msg := st.msg
|
||||||
if !msg.SkipAccountChecks {
|
if !msg.SkipNonceChecks {
|
||||||
// Make sure this transaction's nonce is correct.
|
// Make sure this transaction's nonce is correct.
|
||||||
stNonce := st.state.GetNonce(msg.From)
|
stNonce := st.state.GetNonce(msg.From)
|
||||||
if msgNonce := msg.Nonce; stNonce < msgNonce {
|
if msgNonce := msg.Nonce; stNonce < msgNonce {
|
||||||
|
@ -293,6 +297,8 @@ func (st *StateTransition) preCheck() error {
|
||||||
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
||||||
msg.From.Hex(), stNonce)
|
msg.From.Hex(), stNonce)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if !msg.SkipFromEOACheck {
|
||||||
// Make sure the sender is an EOA
|
// Make sure the sender is an EOA
|
||||||
codeHash := st.state.GetCodeHash(msg.From)
|
codeHash := st.state.GetCodeHash(msg.From)
|
||||||
if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash {
|
if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash {
|
||||||
|
@ -470,7 +476,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
|
|
||||||
// add the coinbase to the witness iff the fee is greater than 0
|
// add the coinbase to the witness iff the fee is greater than 0
|
||||||
if rules.IsEIP4762 && fee.Sign() != 0 {
|
if rules.IsEIP4762 && fee.Sign() != 0 {
|
||||||
st.evm.AccessEvents.BalanceGas(st.evm.Context.Coinbase, true)
|
st.evm.AccessEvents.AddAccount(st.evm.Context.Coinbase, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,8 +42,7 @@ import (
|
||||||
func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (common.Hash, common.Hash, error) {
|
func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (common.Hash, common.Hash, error) {
|
||||||
// Create and populate the state database to serve as the stateless backend
|
// Create and populate the state database to serve as the stateless backend
|
||||||
memdb := witness.MakeHashDB()
|
memdb := witness.MakeHashDB()
|
||||||
|
db, err := state.New(witness.Root(), state.NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), nil))
|
||||||
db, err := state.New(witness.Root(), state.NewDatabaseWithConfig(memdb, triedb.HashDefaults), nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, common.Hash{}, err
|
return common.Hash{}, common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
@ -58,15 +57,15 @@ func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (c
|
||||||
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
||||||
|
|
||||||
// Run the stateless blocks processing and self-validate certain fields
|
// Run the stateless blocks processing and self-validate certain fields
|
||||||
receipts, _, usedGas, err := processor.Process(witness.Block, db, vm.Config{})
|
res, err := processor.Process(witness.Block, db, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, common.Hash{}, err
|
return common.Hash{}, common.Hash{}, err
|
||||||
}
|
}
|
||||||
if err = validator.ValidateState(witness.Block, db, receipts, usedGas, true); err != nil {
|
if err = validator.ValidateState(witness.Block, db, res, true); err != nil {
|
||||||
return common.Hash{}, common.Hash{}, err
|
return common.Hash{}, common.Hash{}, err
|
||||||
}
|
}
|
||||||
// Almost everything validated, but receipt and state root needs to be returned
|
// Almost everything validated, but receipt and state root needs to be returned
|
||||||
receiptRoot := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
|
||||||
stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number()))
|
stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number()))
|
||||||
|
|
||||||
return receiptRoot, stateRoot, nil
|
return receiptRoot, stateRoot, nil
|
||||||
|
|
|
@ -101,9 +101,7 @@ func (w *Witness) AddState(nodes map[string]struct{}) {
|
||||||
w.lock.Lock()
|
w.lock.Lock()
|
||||||
defer w.lock.Unlock()
|
defer w.lock.Unlock()
|
||||||
|
|
||||||
for node := range nodes {
|
maps.Copy(w.State, nodes)
|
||||||
w.State[node] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it
|
// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it
|
||||||
|
|
|
@ -2,6 +2,24 @@
|
||||||
|
|
||||||
All notable changes to the tracing interface will be documented in this file.
|
All notable changes to the tracing interface will be documented in this file.
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Modified types
|
||||||
|
|
||||||
|
- `GasChangeReason` has been extended with the following reasons which will be enabled only post-Verkle. There shouldn't be any gas changes with those reasons prior to the fork.
|
||||||
|
- `GasChangeWitnessContractCollisionCheck` flags the event of adding to the witness when checking for contract address collision.
|
||||||
|
|
||||||
|
## [v1.14.4]
|
||||||
|
|
||||||
|
This release contained only minor extensions to the tracing interface.
|
||||||
|
|
||||||
|
### Modified types
|
||||||
|
|
||||||
|
- `GasChangeReason` has been extended with the following reasons that will only be active post-Verkle.
|
||||||
|
- `GasChangeWitnessContractInit` flags the event of adding to the witness during the contract creation initialization step.
|
||||||
|
- `GasChangeWitnessContractCreation` flags the event of adding to the witness during the contract creation finalization step.
|
||||||
|
- `GasChangeWitnessCodeChunk` flags the event of adding one or more contract code chunks to the witness.
|
||||||
|
|
||||||
## [v1.14.3]
|
## [v1.14.3]
|
||||||
|
|
||||||
There have been minor backwards-compatible changes to the tracing interface to explicitly mark the execution of **system** contracts. As of now the only system call updates the parent beacon block root as per [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). Other system calls are being considered for the future hardfork.
|
There have been minor backwards-compatible changes to the tracing interface to explicitly mark the execution of **system** contracts. As of now the only system call updates the parent beacon block root as per [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). Other system calls are being considered for the future hardfork.
|
||||||
|
@ -75,6 +93,7 @@ The hooks `CaptureStart` and `CaptureEnd` have been removed. These hooks signale
|
||||||
- `CaptureState` -> `OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error)`. `op` is of type `byte` which can be cast to `vm.OpCode` when necessary. A `*vm.ScopeContext` is not passed anymore. It is replaced by `tracing.OpContext` which offers access to the memory, stack and current contract.
|
- `CaptureState` -> `OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error)`. `op` is of type `byte` which can be cast to `vm.OpCode` when necessary. A `*vm.ScopeContext` is not passed anymore. It is replaced by `tracing.OpContext` which offers access to the memory, stack and current contract.
|
||||||
- `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above.
|
- `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above.
|
||||||
|
|
||||||
[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.0...master
|
[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.8...master
|
||||||
[v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0
|
[v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0
|
||||||
[v1.14.3]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.3
|
[v1.14.3]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.3
|
||||||
|
[v1.14.4]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.4
|
||||||
|
|
|
@ -300,12 +300,14 @@ const (
|
||||||
GasChangeCallStorageColdAccess GasChangeReason = 13
|
GasChangeCallStorageColdAccess GasChangeReason = 13
|
||||||
// GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert.
|
// GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert.
|
||||||
GasChangeCallFailedExecution GasChangeReason = 14
|
GasChangeCallFailedExecution GasChangeReason = 14
|
||||||
// GasChangeWitnessContractInit is the amount charged for adding to the witness during the contract creation initialization step
|
// GasChangeWitnessContractInit flags the event of adding to the witness during the contract creation initialization step.
|
||||||
GasChangeWitnessContractInit GasChangeReason = 15
|
GasChangeWitnessContractInit GasChangeReason = 15
|
||||||
// GasChangeWitnessContractCreation is the amount charged for adding to the witness during the contract creation finalization step
|
// GasChangeWitnessContractCreation flags the event of adding to the witness during the contract creation finalization step.
|
||||||
GasChangeWitnessContractCreation GasChangeReason = 16
|
GasChangeWitnessContractCreation GasChangeReason = 16
|
||||||
// GasChangeWitnessCodeChunk is the amount charged for touching one or more contract code chunks
|
// GasChangeWitnessCodeChunk flags the event of adding one or more contract code chunks to the witness.
|
||||||
GasChangeWitnessCodeChunk GasChangeReason = 17
|
GasChangeWitnessCodeChunk GasChangeReason = 17
|
||||||
|
// GasChangeWitnessContractCollisionCheck flags the event of adding to the witness when checking for contract address collision.
|
||||||
|
GasChangeWitnessContractCollisionCheck GasChangeReason = 18
|
||||||
|
|
||||||
// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
|
// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
|
||||||
// it will be "manually" tracked by a direct emit of the gas change event.
|
// it will be "manually" tracked by a direct emit of the gas change event.
|
||||||
|
|
|
@ -566,7 +566,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||||
ids []uint64
|
ids []uint64
|
||||||
nonces []uint64
|
nonces []uint64
|
||||||
)
|
)
|
||||||
for txs[0].nonce < next {
|
for len(txs) > 0 && txs[0].nonce < next {
|
||||||
ids = append(ids, txs[0].id)
|
ids = append(ids, txs[0].id)
|
||||||
nonces = append(nonces, txs[0].nonce)
|
nonces = append(nonces, txs[0].nonce)
|
||||||
|
|
||||||
|
@ -940,7 +940,7 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]*
|
||||||
}
|
}
|
||||||
// Generate the set of transactions per address to pull back into the pool,
|
// Generate the set of transactions per address to pull back into the pool,
|
||||||
// also updating the rest along the way
|
// also updating the rest along the way
|
||||||
reinject := make(map[common.Address][]*types.Transaction)
|
reinject := make(map[common.Address][]*types.Transaction, len(transactors))
|
||||||
for addr := range transactors {
|
for addr := range transactors {
|
||||||
// Generate the set that was lost to reinject into the pool
|
// Generate the set that was lost to reinject into the pool
|
||||||
lost := make([]*types.Transaction, 0, len(discarded[addr]))
|
lost := make([]*types.Transaction, 0, len(discarded[addr]))
|
||||||
|
@ -949,7 +949,9 @@ func (p *BlobPool) reorg(oldHead, newHead *types.Header) (map[common.Address][]*
|
||||||
lost = append(lost, tx)
|
lost = append(lost, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(lost) > 0 {
|
||||||
reinject[addr] = lost
|
reinject[addr] = lost
|
||||||
|
}
|
||||||
|
|
||||||
// Update the set that was already reincluded to track the blocks in limbo
|
// Update the set that was already reincluded to track the blocks in limbo
|
||||||
for _, tx := range types.TxDifference(included[addr], discarded[addr]) {
|
for _, tx := range types.TxDifference(included[addr], discarded[addr]) {
|
||||||
|
@ -1155,11 +1157,11 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error {
|
||||||
)
|
)
|
||||||
switch {
|
switch {
|
||||||
case tx.GasFeeCapIntCmp(minGasFeeCap.ToBig()) < 0:
|
case tx.GasFeeCapIntCmp(minGasFeeCap.ToBig()) < 0:
|
||||||
return fmt.Errorf("%w: new tx gas fee cap %v <= %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasFeeCap(), prev.execFeeCap, p.config.PriceBump)
|
return fmt.Errorf("%w: new tx gas fee cap %v < %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasFeeCap(), prev.execFeeCap, p.config.PriceBump)
|
||||||
case tx.GasTipCapIntCmp(minGasTipCap.ToBig()) < 0:
|
case tx.GasTipCapIntCmp(minGasTipCap.ToBig()) < 0:
|
||||||
return fmt.Errorf("%w: new tx gas tip cap %v <= %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasTipCap(), prev.execTipCap, p.config.PriceBump)
|
return fmt.Errorf("%w: new tx gas tip cap %v < %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasTipCap(), prev.execTipCap, p.config.PriceBump)
|
||||||
case tx.BlobGasFeeCapIntCmp(minBlobGasFeeCap.ToBig()) < 0:
|
case tx.BlobGasFeeCapIntCmp(minBlobGasFeeCap.ToBig()) < 0:
|
||||||
return fmt.Errorf("%w: new tx blob gas fee cap %v <= %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.BlobGasFeeCap(), prev.blobFeeCap, p.config.PriceBump)
|
return fmt.Errorf("%w: new tx blob gas fee cap %v < %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.BlobGasFeeCap(), prev.blobFeeCap, p.config.PriceBump)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -33,14 +33,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool"
|
"github.com/ethereum/go-ethereum/core/txpool"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
@ -545,7 +543,7 @@ func TestOpenDrops(t *testing.T) {
|
||||||
store.Close()
|
store.Close()
|
||||||
|
|
||||||
// Create a blob pool out of the pre-seeded data
|
// Create a blob pool out of the pre-seeded data
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
|
||||||
|
@ -676,7 +674,7 @@ func TestOpenIndex(t *testing.T) {
|
||||||
store.Close()
|
store.Close()
|
||||||
|
|
||||||
// Create a blob pool out of the pre-seeded data
|
// Create a blob pool out of the pre-seeded data
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
statedb.Commit(0, true)
|
statedb.Commit(0, true)
|
||||||
|
|
||||||
|
@ -776,7 +774,7 @@ func TestOpenHeap(t *testing.T) {
|
||||||
store.Close()
|
store.Close()
|
||||||
|
|
||||||
// Create a blob pool out of the pre-seeded data
|
// Create a blob pool out of the pre-seeded data
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
|
@ -856,7 +854,7 @@ func TestOpenCap(t *testing.T) {
|
||||||
// with a high cap to ensure everything was persisted previously
|
// with a high cap to ensure everything was persisted previously
|
||||||
for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} {
|
for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} {
|
||||||
// Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction
|
// Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
|
@ -1266,7 +1264,7 @@ func TestAdd(t *testing.T) {
|
||||||
keys = make(map[string]*ecdsa.PrivateKey)
|
keys = make(map[string]*ecdsa.PrivateKey)
|
||||||
addrs = make(map[string]common.Address)
|
addrs = make(map[string]common.Address)
|
||||||
)
|
)
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
for acc, seed := range tt.seeds {
|
for acc, seed := range tt.seeds {
|
||||||
// Generate a new random key/address for the seed account
|
// Generate a new random key/address for the seed account
|
||||||
keys[acc], _ = crypto.GenerateKey()
|
keys[acc], _ = crypto.GenerateKey()
|
||||||
|
@ -1328,7 +1326,7 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) {
|
||||||
basefee = uint64(1050)
|
basefee = uint64(1050)
|
||||||
blobfee = uint64(105)
|
blobfee = uint64(105)
|
||||||
signer = types.LatestSigner(testChainConfig)
|
signer = types.LatestSigner(testChainConfig)
|
||||||
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
chain = &testBlockChain{
|
chain = &testBlockChain{
|
||||||
config: testChainConfig,
|
config: testChainConfig,
|
||||||
basefee: uint256.NewInt(basefee),
|
basefee: uint256.NewInt(basefee),
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
@ -80,7 +79,7 @@ func TestTransactionFutureAttack(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the limit enforcement with
|
// Create the pool to test the limit enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
config.GlobalQueue = 100
|
config.GlobalQueue = 100
|
||||||
|
@ -117,7 +116,7 @@ func TestTransactionFutureAttack(t *testing.T) {
|
||||||
func TestTransactionFuture1559(t *testing.T) {
|
func TestTransactionFuture1559(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||||
pool := New(testTxPoolConfig, blockchain)
|
pool := New(testTxPoolConfig, blockchain)
|
||||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||||
|
@ -150,7 +149,7 @@ func TestTransactionFuture1559(t *testing.T) {
|
||||||
func TestTransactionZAttack(t *testing.T) {
|
func TestTransactionZAttack(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||||
pool := New(testTxPoolConfig, blockchain)
|
pool := New(testTxPoolConfig, blockchain)
|
||||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||||
|
@ -218,7 +217,7 @@ func TestTransactionZAttack(t *testing.T) {
|
||||||
|
|
||||||
func BenchmarkFutureAttack(b *testing.B) {
|
func BenchmarkFutureAttack(b *testing.B) {
|
||||||
// Create the pool to test the limit enforcement with
|
// Create the pool to test the limit enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
config.GlobalQueue = 100
|
config.GlobalQueue = 100
|
||||||
|
|
|
@ -31,7 +31,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool"
|
"github.com/ethereum/go-ethereum/core/txpool"
|
||||||
|
@ -160,7 +159,7 @@ func setupPool() (*LegacyPool, *ecdsa.PrivateKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.PrivateKey) {
|
func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.PrivateKey) {
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(config, 10000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(config, 10000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
|
@ -251,7 +250,7 @@ func (c *testChain) State() (*state.StateDB, error) {
|
||||||
// a state change between those fetches.
|
// a state change between those fetches.
|
||||||
stdb := c.statedb
|
stdb := c.statedb
|
||||||
if *c.trigger {
|
if *c.trigger {
|
||||||
c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
// simulate that the new head block included tx0 and tx1
|
// simulate that the new head block included tx0 and tx1
|
||||||
c.statedb.SetNonce(c.address, 2)
|
c.statedb.SetNonce(c.address, 2)
|
||||||
c.statedb.SetBalance(c.address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified)
|
c.statedb.SetBalance(c.address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified)
|
||||||
|
@ -269,7 +268,7 @@ func TestStateChangeDuringReset(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
trigger = false
|
trigger = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -468,7 +467,7 @@ func TestChainFork(t *testing.T) {
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
resetState := func() {
|
resetState := func() {
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified)
|
||||||
|
|
||||||
pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
|
pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
|
||||||
|
@ -497,7 +496,7 @@ func TestDoubleNonce(t *testing.T) {
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
resetState := func() {
|
resetState := func() {
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified)
|
statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified)
|
||||||
|
|
||||||
pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
|
pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
|
||||||
|
@ -697,7 +696,7 @@ func TestPostponing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the postponing with
|
// Create the pool to test the postponing with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
pool := New(testTxPoolConfig, blockchain)
|
pool := New(testTxPoolConfig, blockchain)
|
||||||
|
@ -910,7 +909,7 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the limit enforcement with
|
// Create the pool to test the limit enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
@ -1003,7 +1002,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) {
|
||||||
evictionInterval = time.Millisecond * 100
|
evictionInterval = time.Millisecond * 100
|
||||||
|
|
||||||
// Create the pool to test the non-expiration enforcement
|
// Create the pool to test the non-expiration enforcement
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
@ -1189,7 +1188,7 @@ func TestPendingGlobalLimiting(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the limit enforcement with
|
// Create the pool to test the limit enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
@ -1291,7 +1290,7 @@ func TestCapClearsFromAll(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the limit enforcement with
|
// Create the pool to test the limit enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
@ -1326,7 +1325,7 @@ func TestPendingMinimumAllowance(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the limit enforcement with
|
// Create the pool to test the limit enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
@ -1375,7 +1374,7 @@ func TestRepricing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
pool := New(testTxPoolConfig, blockchain)
|
pool := New(testTxPoolConfig, blockchain)
|
||||||
|
@ -1495,7 +1494,7 @@ func TestMinGasPriceEnforced(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(eip1559Config, 10000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(eip1559Config, 10000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
txPoolConfig := DefaultConfig
|
txPoolConfig := DefaultConfig
|
||||||
|
@ -1668,7 +1667,7 @@ func TestRepricingKeepsLocals(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
pool := New(testTxPoolConfig, blockchain)
|
pool := New(testTxPoolConfig, blockchain)
|
||||||
|
@ -1742,7 +1741,7 @@ func TestUnderpricing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
@ -1857,7 +1856,7 @@ func TestStableUnderpricing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
@ -2090,7 +2089,7 @@ func TestDeduplication(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
pool := New(testTxPoolConfig, blockchain)
|
pool := New(testTxPoolConfig, blockchain)
|
||||||
|
@ -2157,7 +2156,7 @@ func TestReplacement(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
pool := New(testTxPoolConfig, blockchain)
|
pool := New(testTxPoolConfig, blockchain)
|
||||||
|
@ -2363,7 +2362,7 @@ func testJournaling(t *testing.T, nolocals bool) {
|
||||||
os.Remove(journal)
|
os.Remove(journal)
|
||||||
|
|
||||||
// Create the original pool to inject transaction into the journal
|
// Create the original pool to inject transaction into the journal
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
@ -2464,7 +2463,7 @@ func TestStatusCheck(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the status retrievals with
|
// Create the pool to test the status retrievals with
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||||
|
|
||||||
pool := New(testTxPoolConfig, blockchain)
|
pool := New(testTxPoolConfig, blockchain)
|
||||||
|
|
|
@ -33,9 +33,8 @@ type Validator interface {
|
||||||
// ValidateBody validates the given block's content.
|
// ValidateBody validates the given block's content.
|
||||||
ValidateBody(block *types.Block) error
|
ValidateBody(block *types.Block) error
|
||||||
|
|
||||||
// ValidateState validates the given statedb and optionally the receipts and
|
// ValidateState validates the given statedb and optionally the process result.
|
||||||
// gas used.
|
ValidateState(block *types.Block, state *state.StateDB, res *ProcessResult, stateless bool) error
|
||||||
ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error
|
|
||||||
|
|
||||||
// ValidateWitness cross validates a block execution with stateless remote clients.
|
// ValidateWitness cross validates a block execution with stateless remote clients.
|
||||||
ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error
|
ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error
|
||||||
|
@ -54,5 +53,13 @@ type Processor interface {
|
||||||
// Process processes the state changes according to the Ethereum rules by running
|
// Process processes the state changes according to the Ethereum rules by running
|
||||||
// the transaction messages using the statedb and applying any rewards to both
|
// the transaction messages using the statedb and applying any rewards to both
|
||||||
// the processor (coinbase) and any included uncles.
|
// the processor (coinbase) and any included uncles.
|
||||||
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error)
|
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessResult contains the values computed by Process.
|
||||||
|
type ProcessResult struct {
|
||||||
|
Receipts types.Receipts
|
||||||
|
Requests types.Requests
|
||||||
|
Logs []*types.Log
|
||||||
|
GasUsed uint64
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-verkle"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A BlockNonce is a 64-bit hash which proves (combined with the
|
// A BlockNonce is a 64-bit hash which proves (combined with the
|
||||||
|
@ -59,6 +60,13 @@ func (n *BlockNonce) UnmarshalText(input []byte) error {
|
||||||
return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
|
return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecutionWitness represents the witness + proof used in a verkle context,
|
||||||
|
// to provide the ability to execute a block statelessly.
|
||||||
|
type ExecutionWitness struct {
|
||||||
|
StateDiff verkle.StateDiff `json:"stateDiff"`
|
||||||
|
VerkleProof *verkle.VerkleProof `json:"verkleProof"`
|
||||||
|
}
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
|
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
|
||||||
//go:generate go run ../../rlp/rlpgen -type Header -out gen_header_rlp.go
|
//go:generate go run ../../rlp/rlpgen -type Header -out gen_header_rlp.go
|
||||||
|
|
||||||
|
@ -94,6 +102,9 @@ type Header struct {
|
||||||
|
|
||||||
// ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers.
|
// ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers.
|
||||||
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||||
|
|
||||||
|
// RequestsHash was added by EIP-7685 and is ignored in legacy headers.
|
||||||
|
RequestsHash *common.Hash `json:"requestsRoot" rlp:"optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// field type overrides for gencodec
|
// field type overrides for gencodec
|
||||||
|
@ -155,10 +166,11 @@ func (h *Header) SanityCheck() error {
|
||||||
// EmptyBody returns true if there is no additional 'body' to complete the header
|
// EmptyBody returns true if there is no additional 'body' to complete the header
|
||||||
// that is: no transactions, no uncles and no withdrawals.
|
// that is: no transactions, no uncles and no withdrawals.
|
||||||
func (h *Header) EmptyBody() bool {
|
func (h *Header) EmptyBody() bool {
|
||||||
if h.WithdrawalsHash != nil {
|
var (
|
||||||
return h.TxHash == EmptyTxsHash && *h.WithdrawalsHash == EmptyWithdrawalsHash
|
emptyWithdrawals = h.WithdrawalsHash == nil || *h.WithdrawalsHash == EmptyWithdrawalsHash
|
||||||
}
|
emptyRequests = h.RequestsHash == nil || *h.RequestsHash == EmptyReceiptsHash
|
||||||
return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash
|
)
|
||||||
|
return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash && emptyWithdrawals && emptyRequests
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmptyReceipts returns true if there are no receipts for this header/block.
|
// EmptyReceipts returns true if there are no receipts for this header/block.
|
||||||
|
@ -172,6 +184,7 @@ type Body struct {
|
||||||
Transactions []*Transaction
|
Transactions []*Transaction
|
||||||
Uncles []*Header
|
Uncles []*Header
|
||||||
Withdrawals []*Withdrawal `rlp:"optional"`
|
Withdrawals []*Withdrawal `rlp:"optional"`
|
||||||
|
Requests []*Request `rlp:"optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block represents an Ethereum block.
|
// Block represents an Ethereum block.
|
||||||
|
@ -196,6 +209,12 @@ type Block struct {
|
||||||
uncles []*Header
|
uncles []*Header
|
||||||
transactions Transactions
|
transactions Transactions
|
||||||
withdrawals Withdrawals
|
withdrawals Withdrawals
|
||||||
|
requests Requests
|
||||||
|
|
||||||
|
// witness is not an encoded part of the block body.
|
||||||
|
// It is held in Block in order for easy relaying to the places
|
||||||
|
// that process it.
|
||||||
|
witness *ExecutionWitness
|
||||||
|
|
||||||
// caches
|
// caches
|
||||||
hash atomic.Pointer[common.Hash]
|
hash atomic.Pointer[common.Hash]
|
||||||
|
@ -213,6 +232,7 @@ type extblock struct {
|
||||||
Txs []*Transaction
|
Txs []*Transaction
|
||||||
Uncles []*Header
|
Uncles []*Header
|
||||||
Withdrawals []*Withdrawal `rlp:"optional"`
|
Withdrawals []*Withdrawal `rlp:"optional"`
|
||||||
|
Requests []*Request `rlp:"optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlock creates a new block. The input data is copied, changes to header and to the
|
// NewBlock creates a new block. The input data is copied, changes to header and to the
|
||||||
|
@ -229,6 +249,7 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher
|
||||||
txs = body.Transactions
|
txs = body.Transactions
|
||||||
uncles = body.Uncles
|
uncles = body.Uncles
|
||||||
withdrawals = body.Withdrawals
|
withdrawals = body.Withdrawals
|
||||||
|
requests = body.Requests
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(txs) == 0 {
|
if len(txs) == 0 {
|
||||||
|
@ -267,6 +288,17 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher TrieHasher
|
||||||
b.withdrawals = slices.Clone(withdrawals)
|
b.withdrawals = slices.Clone(withdrawals)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if requests == nil {
|
||||||
|
b.header.RequestsHash = nil
|
||||||
|
} else if len(requests) == 0 {
|
||||||
|
b.header.RequestsHash = &EmptyRequestsHash
|
||||||
|
b.requests = Requests{}
|
||||||
|
} else {
|
||||||
|
h := DeriveSha(Requests(requests), hasher)
|
||||||
|
b.header.RequestsHash = &h
|
||||||
|
b.requests = slices.Clone(requests)
|
||||||
|
}
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +334,10 @@ func CopyHeader(h *Header) *Header {
|
||||||
cpy.ParentBeaconRoot = new(common.Hash)
|
cpy.ParentBeaconRoot = new(common.Hash)
|
||||||
*cpy.ParentBeaconRoot = *h.ParentBeaconRoot
|
*cpy.ParentBeaconRoot = *h.ParentBeaconRoot
|
||||||
}
|
}
|
||||||
|
if h.RequestsHash != nil {
|
||||||
|
cpy.RequestsHash = new(common.Hash)
|
||||||
|
*cpy.RequestsHash = *h.RequestsHash
|
||||||
|
}
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +348,7 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error {
|
||||||
if err := s.Decode(&eb); err != nil {
|
if err := s.Decode(&eb); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
b.header, b.uncles, b.transactions, b.withdrawals = eb.Header, eb.Uncles, eb.Txs, eb.Withdrawals
|
b.header, b.uncles, b.transactions, b.withdrawals, b.requests = eb.Header, eb.Uncles, eb.Txs, eb.Withdrawals, eb.Requests
|
||||||
b.size.Store(rlp.ListSize(size))
|
b.size.Store(rlp.ListSize(size))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -324,13 +360,14 @@ func (b *Block) EncodeRLP(w io.Writer) error {
|
||||||
Txs: b.transactions,
|
Txs: b.transactions,
|
||||||
Uncles: b.uncles,
|
Uncles: b.uncles,
|
||||||
Withdrawals: b.withdrawals,
|
Withdrawals: b.withdrawals,
|
||||||
|
Requests: b.requests,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Body returns the non-header content of the block.
|
// Body returns the non-header content of the block.
|
||||||
// Note the returned data is not an independent copy.
|
// Note the returned data is not an independent copy.
|
||||||
func (b *Block) Body() *Body {
|
func (b *Block) Body() *Body {
|
||||||
return &Body{b.transactions, b.uncles, b.withdrawals}
|
return &Body{b.transactions, b.uncles, b.withdrawals, b.requests}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors for body data. These do not return a copy because the content
|
// Accessors for body data. These do not return a copy because the content
|
||||||
|
@ -339,6 +376,7 @@ func (b *Block) Body() *Body {
|
||||||
func (b *Block) Uncles() []*Header { return b.uncles }
|
func (b *Block) Uncles() []*Header { return b.uncles }
|
||||||
func (b *Block) Transactions() Transactions { return b.transactions }
|
func (b *Block) Transactions() Transactions { return b.transactions }
|
||||||
func (b *Block) Withdrawals() Withdrawals { return b.withdrawals }
|
func (b *Block) Withdrawals() Withdrawals { return b.withdrawals }
|
||||||
|
func (b *Block) Requests() Requests { return b.requests }
|
||||||
|
|
||||||
func (b *Block) Transaction(hash common.Hash) *Transaction {
|
func (b *Block) Transaction(hash common.Hash) *Transaction {
|
||||||
for _, transaction := range b.transactions {
|
for _, transaction := range b.transactions {
|
||||||
|
@ -401,6 +439,9 @@ func (b *Block) BlobGasUsed() *uint64 {
|
||||||
return blobGasUsed
|
return blobGasUsed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecutionWitness returns the verkle execution witneess + proof for a block
|
||||||
|
func (b *Block) ExecutionWitness() *ExecutionWitness { return b.witness }
|
||||||
|
|
||||||
// Size returns the true RLP encoded storage size of the block, either by encoding
|
// Size returns the true RLP encoded storage size of the block, either by encoding
|
||||||
// and returning it, or returning a previously cached value.
|
// and returning it, or returning a previously cached value.
|
||||||
func (b *Block) Size() uint64 {
|
func (b *Block) Size() uint64 {
|
||||||
|
@ -448,6 +489,7 @@ func (b *Block) WithSeal(header *Header) *Block {
|
||||||
transactions: b.transactions,
|
transactions: b.transactions,
|
||||||
uncles: b.uncles,
|
uncles: b.uncles,
|
||||||
withdrawals: b.withdrawals,
|
withdrawals: b.withdrawals,
|
||||||
|
witness: b.witness,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,6 +501,8 @@ func (b *Block) WithBody(body Body) *Block {
|
||||||
transactions: slices.Clone(body.Transactions),
|
transactions: slices.Clone(body.Transactions),
|
||||||
uncles: make([]*Header, len(body.Uncles)),
|
uncles: make([]*Header, len(body.Uncles)),
|
||||||
withdrawals: slices.Clone(body.Withdrawals),
|
withdrawals: slices.Clone(body.Withdrawals),
|
||||||
|
requests: slices.Clone(body.Requests),
|
||||||
|
witness: b.witness,
|
||||||
}
|
}
|
||||||
for i := range body.Uncles {
|
for i := range body.Uncles {
|
||||||
block.uncles[i] = CopyHeader(body.Uncles[i])
|
block.uncles[i] = CopyHeader(body.Uncles[i])
|
||||||
|
@ -466,6 +510,17 @@ func (b *Block) WithBody(body Body) *Block {
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Block) WithWitness(witness *ExecutionWitness) *Block {
|
||||||
|
return &Block{
|
||||||
|
header: b.header,
|
||||||
|
transactions: b.transactions,
|
||||||
|
uncles: b.uncles,
|
||||||
|
withdrawals: b.withdrawals,
|
||||||
|
requests: b.requests,
|
||||||
|
witness: witness,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Hash returns the keccak256 hash of b's header.
|
// Hash returns the keccak256 hash of b's header.
|
||||||
// The hash is computed on the first call and cached thereafter.
|
// The hash is computed on the first call and cached thereafter.
|
||||||
func (b *Block) Hash() common.Hash {
|
func (b *Block) Hash() common.Hash {
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
// 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 types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run github.com/fjl/gencodec -type Deposit -field-override depositMarshaling -out gen_deposit_json.go
|
||||||
|
|
||||||
|
// Deposit contains EIP-6110 deposit data.
|
||||||
|
type Deposit struct {
|
||||||
|
PublicKey [48]byte `json:"pubkey"` // public key of validator
|
||||||
|
WithdrawalCredentials common.Hash `json:"withdrawalCredentials"` // beneficiary of the validator funds
|
||||||
|
Amount uint64 `json:"amount"` // deposit size in Gwei
|
||||||
|
Signature [96]byte `json:"signature"` // signature over deposit msg
|
||||||
|
Index uint64 `json:"index"` // deposit count value
|
||||||
|
}
|
||||||
|
|
||||||
|
// field type overrides for gencodec
|
||||||
|
type depositMarshaling struct {
|
||||||
|
PublicKey hexutil.Bytes
|
||||||
|
WithdrawalCredentials hexutil.Bytes
|
||||||
|
Amount hexutil.Uint64
|
||||||
|
Signature hexutil.Bytes
|
||||||
|
Index hexutil.Uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deposits implements DerivableList for requests.
|
||||||
|
type Deposits []*Deposit
|
||||||
|
|
||||||
|
// Len returns the length of s.
|
||||||
|
func (s Deposits) Len() int { return len(s) }
|
||||||
|
|
||||||
|
// EncodeIndex encodes the i'th deposit to s.
|
||||||
|
func (s Deposits) EncodeIndex(i int, w *bytes.Buffer) {
|
||||||
|
rlp.Encode(w, s[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnpackIntoDeposit unpacks a serialized DepositEvent.
|
||||||
|
func UnpackIntoDeposit(data []byte) (*Deposit, error) {
|
||||||
|
if len(data) != 576 {
|
||||||
|
return nil, fmt.Errorf("deposit wrong length: want 576, have %d", len(data))
|
||||||
|
}
|
||||||
|
var d Deposit
|
||||||
|
// The ABI encodes the position of dynamic elements first. Since there are 5
|
||||||
|
// elements, skip over the positional data. The first 32 bytes of dynamic
|
||||||
|
// elements also encode their actual length. Skip over that value too.
|
||||||
|
b := 32*5 + 32
|
||||||
|
// PublicKey is the first element. ABI encoding pads values to 32 bytes, so
|
||||||
|
// despite BLS public keys being length 48, the value length here is 64. Then
|
||||||
|
// skip over the next length value.
|
||||||
|
copy(d.PublicKey[:], data[b:b+48])
|
||||||
|
b += 48 + 16 + 32
|
||||||
|
// WithdrawalCredentials is 32 bytes. Read that value then skip over next
|
||||||
|
// length.
|
||||||
|
copy(d.WithdrawalCredentials[:], data[b:b+32])
|
||||||
|
b += 32 + 32
|
||||||
|
// Amount is 8 bytes, but it is padded to 32. Skip over it and the next
|
||||||
|
// length.
|
||||||
|
d.Amount = binary.LittleEndian.Uint64(data[b : b+8])
|
||||||
|
b += 8 + 24 + 32
|
||||||
|
// Signature is 96 bytes. Skip over it and the next length.
|
||||||
|
copy(d.Signature[:], data[b:b+96])
|
||||||
|
b += 96 + 32
|
||||||
|
// Amount is 8 bytes.
|
||||||
|
d.Index = binary.LittleEndian.Uint64(data[b : b+8])
|
||||||
|
|
||||||
|
return &d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Deposit) requestType() byte { return DepositRequestType }
|
||||||
|
func (d *Deposit) encode(b *bytes.Buffer) error { return rlp.Encode(b, d) }
|
||||||
|
func (d *Deposit) decode(input []byte) error { return rlp.DecodeBytes(input, d) }
|
||||||
|
func (d *Deposit) copy() RequestData {
|
||||||
|
return &Deposit{
|
||||||
|
PublicKey: d.PublicKey,
|
||||||
|
WithdrawalCredentials: d.WithdrawalCredentials,
|
||||||
|
Amount: d.Amount,
|
||||||
|
Signature: d.Signature,
|
||||||
|
Index: d.Index,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
// 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 types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
depositABI = abi.ABI{Methods: map[string]abi.Method{"DepositEvent": depositEvent}}
|
||||||
|
bytesT, _ = abi.NewType("bytes", "", nil)
|
||||||
|
depositEvent = abi.NewMethod("DepositEvent", "DepositEvent", abi.Function, "", false, false, []abi.Argument{
|
||||||
|
{Name: "pubkey", Type: bytesT, Indexed: false},
|
||||||
|
{Name: "withdrawal_credentials", Type: bytesT, Indexed: false},
|
||||||
|
{Name: "amount", Type: bytesT, Indexed: false},
|
||||||
|
{Name: "signature", Type: bytesT, Indexed: false},
|
||||||
|
{Name: "index", Type: bytesT, Indexed: false}}, nil,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// FuzzUnpackIntoDeposit tries roundtrip packing and unpacking of deposit events.
|
||||||
|
func FuzzUnpackIntoDeposit(f *testing.F) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
pubkey string
|
||||||
|
wxCred string
|
||||||
|
amount string
|
||||||
|
sig string
|
||||||
|
index string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
pubkey: "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
|
||||||
|
wxCred: "2222222222222222222222222222222222222222222222222222222222222222",
|
||||||
|
amount: "3333333333333333",
|
||||||
|
sig: "444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444",
|
||||||
|
index: "5555555555555555",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
f.Add(common.FromHex(tt.pubkey), common.FromHex(tt.wxCred), common.FromHex(tt.amount), common.FromHex(tt.sig), common.FromHex(tt.index))
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Fuzz(func(t *testing.T, p []byte, w []byte, a []byte, s []byte, i []byte) {
|
||||||
|
var (
|
||||||
|
pubkey [48]byte
|
||||||
|
wxCred [32]byte
|
||||||
|
amount [8]byte
|
||||||
|
sig [96]byte
|
||||||
|
index [8]byte
|
||||||
|
)
|
||||||
|
copy(pubkey[:], p)
|
||||||
|
copy(wxCred[:], w)
|
||||||
|
copy(amount[:], a)
|
||||||
|
copy(sig[:], s)
|
||||||
|
copy(index[:], i)
|
||||||
|
|
||||||
|
want := Deposit{
|
||||||
|
PublicKey: pubkey,
|
||||||
|
WithdrawalCredentials: wxCred,
|
||||||
|
Amount: binary.LittleEndian.Uint64(amount[:]),
|
||||||
|
Signature: sig,
|
||||||
|
Index: binary.LittleEndian.Uint64(index[:]),
|
||||||
|
}
|
||||||
|
out, err := depositABI.Pack("DepositEvent", want.PublicKey[:], want.WithdrawalCredentials[:], amount[:], want.Signature[:], index[:])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error packing deposit: %v", err)
|
||||||
|
}
|
||||||
|
got, err := UnpackIntoDeposit(out[4:])
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error unpacking deposit: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(want, *got) {
|
||||||
|
t.Errorf("roundtrip failed: want %v, got %v", want, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = (*depositMarshaling)(nil)
|
||||||
|
|
||||||
|
// MarshalJSON marshals as JSON.
|
||||||
|
func (d Deposit) MarshalJSON() ([]byte, error) {
|
||||||
|
type Deposit struct {
|
||||||
|
PublicKey hexutil.Bytes `json:"pubkey"`
|
||||||
|
WithdrawalCredentials hexutil.Bytes `json:"withdrawalCredentials"`
|
||||||
|
Amount hexutil.Uint64 `json:"amount"`
|
||||||
|
Signature hexutil.Bytes `json:"signature"`
|
||||||
|
Index hexutil.Uint64 `json:"index"`
|
||||||
|
}
|
||||||
|
var enc Deposit
|
||||||
|
enc.PublicKey = d.PublicKey[:]
|
||||||
|
enc.WithdrawalCredentials = d.WithdrawalCredentials[:]
|
||||||
|
enc.Amount = hexutil.Uint64(d.Amount)
|
||||||
|
enc.Signature = d.Signature[:]
|
||||||
|
enc.Index = hexutil.Uint64(d.Index)
|
||||||
|
return json.Marshal(&enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
|
func (d *Deposit) UnmarshalJSON(input []byte) error {
|
||||||
|
type Deposit struct {
|
||||||
|
PublicKey *hexutil.Bytes `json:"pubkey"`
|
||||||
|
WithdrawalCredentials *hexutil.Bytes `json:"withdrawalCredentials"`
|
||||||
|
Amount *hexutil.Uint64 `json:"amount"`
|
||||||
|
Signature *hexutil.Bytes `json:"signature"`
|
||||||
|
Index *hexutil.Uint64 `json:"index"`
|
||||||
|
}
|
||||||
|
var dec Deposit
|
||||||
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if dec.PublicKey != nil {
|
||||||
|
if len(*dec.PublicKey) != len(d.PublicKey) {
|
||||||
|
return errors.New("field 'pubkey' has wrong length, need 48 items")
|
||||||
|
}
|
||||||
|
copy(d.PublicKey[:], *dec.PublicKey)
|
||||||
|
}
|
||||||
|
if dec.WithdrawalCredentials != nil {
|
||||||
|
if len(*dec.WithdrawalCredentials) != len(d.WithdrawalCredentials) {
|
||||||
|
return errors.New("field 'withdrawalCredentials' has wrong length, need 32 items")
|
||||||
|
}
|
||||||
|
copy(d.WithdrawalCredentials[:], *dec.WithdrawalCredentials)
|
||||||
|
}
|
||||||
|
if dec.Amount != nil {
|
||||||
|
d.Amount = uint64(*dec.Amount)
|
||||||
|
}
|
||||||
|
if dec.Signature != nil {
|
||||||
|
if len(*dec.Signature) != len(d.Signature) {
|
||||||
|
return errors.New("field 'signature' has wrong length, need 96 items")
|
||||||
|
}
|
||||||
|
copy(d.Signature[:], *dec.Signature)
|
||||||
|
}
|
||||||
|
if dec.Index != nil {
|
||||||
|
d.Index = uint64(*dec.Index)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue