mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 06:06:44 +00:00
Merge tag 'v1.14.10' into lmartins/upstream_merge_v1.14.10
This commit is contained in:
commit
fc2198bedd
276 changed files with 8415 additions and 3118 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -30,6 +30,14 @@ cover.out
|
|||
/build/bin/
|
||||
/geth*.zip
|
||||
|
||||
# used by the build/ci.go archive + upload tool
|
||||
/geth*.tar.gz
|
||||
/geth*.tar.gz.sig
|
||||
/geth*.tar.gz.asc
|
||||
/geth*.zip.sig
|
||||
/geth*.zip.asc
|
||||
|
||||
|
||||
# travis
|
||||
profile.tmp
|
||||
profile.cov
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ issues:
|
|||
- path: crypto/bn256/
|
||||
linters:
|
||||
- revive
|
||||
- path: cmd/utils/flags.go
|
||||
text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead."
|
||||
- path: cmd/utils/flags.go
|
||||
text: "SA1019: ethconfig.Defaults.TxLookupLimit is deprecated: use 'TransactionHistory' instead."
|
||||
- path: internal/build/pgp.go
|
||||
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
|
||||
- path: core/vm/contracts.go
|
||||
|
|
|
|||
34
.travis.yml
34
.travis.yml
|
|
@ -27,8 +27,8 @@ jobs:
|
|||
if: type = push
|
||||
os: linux
|
||||
arch: amd64
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- docker
|
||||
services:
|
||||
|
|
@ -44,8 +44,8 @@ jobs:
|
|||
if: type = push
|
||||
os: linux
|
||||
arch: arm64
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- docker
|
||||
services:
|
||||
|
|
@ -85,9 +85,9 @@ jobs:
|
|||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
dist: noble
|
||||
dist: focal
|
||||
sudo: required
|
||||
go: 1.22.x
|
||||
go: 1.23.x
|
||||
env:
|
||||
- azure-linux
|
||||
git:
|
||||
|
|
@ -99,6 +99,7 @@ jobs:
|
|||
|
||||
# build 386
|
||||
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
||||
- git status --porcelain
|
||||
- go run build/ci.go install -dlgo -arch 386
|
||||
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||
|
||||
|
|
@ -158,12 +159,13 @@ jobs:
|
|||
if: type = push
|
||||
os: osx
|
||||
osx_image: xcode14.2
|
||||
go: 1.22.x
|
||||
go: 1.23.1 # See https://github.com/ethereum/go-ethereum/pull/30478
|
||||
env:
|
||||
- azure-osx
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
script:
|
||||
- ln -sf /Users/travis/gopath/bin/go1.23.1 /usr/local/bin/go # Work around travis go-setup bug
|
||||
- go run build/ci.go install -dlgo
|
||||
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||
- go run build/ci.go install -dlgo -arch arm64
|
||||
|
|
@ -174,8 +176,8 @@ jobs:
|
|||
if: type = push
|
||||
os: linux
|
||||
arch: amd64
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
script:
|
||||
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
|
|
@ -190,7 +192,7 @@ jobs:
|
|||
|
||||
- stage: build
|
||||
os: linux
|
||||
dist: noble
|
||||
dist: focal
|
||||
go: 1.22.x
|
||||
script:
|
||||
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||
|
|
@ -199,8 +201,8 @@ jobs:
|
|||
- stage: build
|
||||
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
||||
os: linux
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
git:
|
||||
|
|
@ -215,8 +217,8 @@ jobs:
|
|||
- stage: build
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- azure-purge
|
||||
git:
|
||||
|
|
@ -228,8 +230,8 @@ jobs:
|
|||
- stage: build
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
dist: focal
|
||||
go: 1.23.x
|
||||
env:
|
||||
- racetests
|
||||
script:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
FROM golang:latest
|
||||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.23-alpine as builder
|
||||
|
||||
ARG BOR_DIR=/var/lib/bor
|
||||
ENV BOR_DIR=$BOR_DIR
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.22.1-alpine as builder
|
||||
FROM golang:1.23-alpine as builder
|
||||
|
||||
RUN apk add --no-cache make gcc musl-dev linux-headers git
|
||||
|
||||
|
|
|
|||
|
|
@ -1326,3 +1326,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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ func (b *SimulatedBackend) rollback(parent *types.Block) {
|
|||
blocks, _ := core.GenerateChain(b.config, parent, ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
|
||||
|
||||
b.pendingBlock = blocks[0]
|
||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.blockchain.StateCache(), nil)
|
||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.blockchain.StateCache())
|
||||
}
|
||||
|
||||
// Fork creates a side-chain that can be used to simulate reorgs.
|
||||
|
|
@ -699,7 +699,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
|||
GasTipCap: call.GasTipCap,
|
||||
Data: call.Data,
|
||||
AccessList: call.AccessList,
|
||||
SkipAccountChecks: true,
|
||||
SkipNonceChecks: true,
|
||||
}
|
||||
|
||||
// Create a new environment which holds all relevant information
|
||||
|
|
@ -709,7 +709,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
|||
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
||||
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
|
||||
return core.ApplyMessage(vmEnv, msg, gasPool, context.Background())
|
||||
return core.ApplyMessage(vmEnv, msg, gasPool)
|
||||
}
|
||||
|
||||
// SendTransaction updates the pending block to include the given transaction.
|
||||
|
|
@ -744,7 +744,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
|||
return err
|
||||
}
|
||||
b.pendingBlock = blocks[0]
|
||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil)
|
||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database())
|
||||
b.pendingReceipts = receipts[0]
|
||||
return nil
|
||||
}
|
||||
|
|
@ -867,7 +867,7 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
|
|||
return err
|
||||
}
|
||||
b.pendingBlock = blocks[0]
|
||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil)
|
||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,9 @@ func TestWaitDeployed(t *testing.T) {
|
|||
}()
|
||||
|
||||
// Send and mine the transaction.
|
||||
backend.SendTransaction(ctx, tx)
|
||||
if err := backend.SendTransaction(ctx, tx); err != nil {
|
||||
t.Errorf("test %q: failed to send transaction: %v", name, err)
|
||||
}
|
||||
backend.Commit()
|
||||
|
||||
select {
|
||||
|
|
@ -122,7 +124,9 @@ func TestWaitDeployedCornerCases(t *testing.T) {
|
|||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
backend.SendTransaction(ctx, tx)
|
||||
if err := backend.SendTransaction(ctx, tx); err != nil {
|
||||
t.Errorf("failed to send transaction: %q", err)
|
||||
}
|
||||
backend.Commit()
|
||||
notContractCreation := errors.New("tx is not contract creation")
|
||||
if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != notContractCreation.Error() {
|
||||
|
|
@ -140,6 +144,8 @@ func TestWaitDeployedCornerCases(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
backend.SendTransaction(ctx, tx)
|
||||
if err := backend.SendTransaction(ctx, tx); err != nil {
|
||||
t.Errorf("failed to send transaction: %q", err)
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -238,8 +238,13 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
|
|||
typ.T = FunctionTy
|
||||
typ.Size = 24
|
||||
default:
|
||||
if strings.HasPrefix(internalType, "contract ") {
|
||||
typ.Size = 20
|
||||
typ.T = AddressTy
|
||||
} else {
|
||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
0
beacon/blsync/block_sync.go
Executable file → Normal file
0
beacon/blsync/block_sync.go
Executable file → Normal file
|
|
@ -70,7 +70,10 @@ func TestBlockSync(t *testing.T) {
|
|||
t.Helper()
|
||||
var expNumber, headNumber uint64
|
||||
if expHead != nil {
|
||||
p, _ := expHead.ExecutionPayload()
|
||||
p, err := expHead.ExecutionPayload()
|
||||
if err != nil {
|
||||
t.Fatalf("expHead.ExecutionPayload() failed: %v", err)
|
||||
}
|
||||
expNumber = p.NumberU64()
|
||||
}
|
||||
select {
|
||||
|
|
|
|||
|
|
@ -56,32 +56,17 @@ var (
|
|||
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}),
|
||||
Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"),
|
||||
}
|
||||
|
||||
GoerliConfig = lightClientConfig{
|
||||
ChainConfig: (&types.ChainConfig{
|
||||
GenesisValidatorsRoot: common.HexToHash("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb"),
|
||||
GenesisTime: 1614588812,
|
||||
}).
|
||||
AddFork("GENESIS", 0, []byte{0, 0, 16, 32}).
|
||||
AddFork("ALTAIR", 36660, []byte{1, 0, 16, 32}).
|
||||
AddFork("BELLATRIX", 112260, []byte{2, 0, 16, 32}).
|
||||
AddFork("CAPELLA", 162304, []byte{3, 0, 16, 32}).
|
||||
AddFork("DENEB", 231680, []byte{4, 0, 16, 32}),
|
||||
Checkpoint: common.HexToHash("0x53a0f4f0a378e2c4ae0a9ee97407eb69d0d737d8d8cd0a5fb1093f42f7b81c49"),
|
||||
}
|
||||
)
|
||||
|
||||
func makeChainConfig(ctx *cli.Context) lightClientConfig {
|
||||
var config lightClientConfig
|
||||
customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name)
|
||||
utils.CheckExclusive(ctx, utils.MainnetFlag, utils.GoerliFlag, utils.SepoliaFlag, utils.BeaconConfigFlag)
|
||||
utils.CheckExclusive(ctx, utils.MainnetFlag, utils.SepoliaFlag, utils.BeaconConfigFlag)
|
||||
switch {
|
||||
case ctx.Bool(utils.MainnetFlag.Name):
|
||||
config = MainnetConfig
|
||||
case ctx.Bool(utils.SepoliaFlag.Name):
|
||||
config = SepoliaConfig
|
||||
case ctx.Bool(utils.GoerliFlag.Name):
|
||||
config = GoerliConfig
|
||||
default:
|
||||
if !customConfig {
|
||||
config = MainnetConfig
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
|||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||
Deposits types.Deposits `json:"depositRequests"`
|
||||
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||
}
|
||||
|
||||
var enc ExecutableData
|
||||
|
|
@ -61,6 +63,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
|
|||
enc.Withdrawals = e.Withdrawals
|
||||
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
|
||||
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
|
||||
enc.Deposits = e.Deposits
|
||||
enc.ExecutionWitness = e.ExecutionWitness
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +88,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
|||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
|
||||
Deposits *types.Deposits `json:"depositRequests"`
|
||||
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||
}
|
||||
|
||||
var dec ExecutableData
|
||||
|
|
@ -187,5 +193,11 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
|
|||
if dec.ExcessBlobGas != nil {
|
||||
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
|
||||
}
|
||||
if dec.Deposits != nil {
|
||||
e.Deposits = *dec.Deposits
|
||||
}
|
||||
if dec.ExecutionWitness != nil {
|
||||
e.ExecutionWitness = dec.ExecutionWitness
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) {
|
|||
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
|
||||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||
Override bool `json:"shouldOverrideBuilder"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
}
|
||||
|
||||
var enc ExecutionPayloadEnvelope
|
||||
|
|
@ -26,6 +27,7 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) {
|
|||
enc.BlockValue = (*hexutil.Big)(e.BlockValue)
|
||||
enc.BlobsBundle = e.BlobsBundle
|
||||
enc.Override = e.Override
|
||||
enc.Witness = e.Witness
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
|
|
@ -36,6 +38,7 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
|
|||
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
|
||||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||
Override *bool `json:"shouldOverrideBuilder"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
}
|
||||
|
||||
var dec ExecutionPayloadEnvelope
|
||||
|
|
@ -60,5 +63,8 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
|
|||
if dec.Override != nil {
|
||||
e.Override = *dec.Override
|
||||
}
|
||||
if dec.Witness != nil {
|
||||
e.Witness = dec.Witness
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ type ExecutableData struct {
|
|||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
||||
Deposits types.Deposits `json:"depositRequests"`
|
||||
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
|
||||
}
|
||||
|
||||
// JSON type overrides for executableData.
|
||||
|
|
@ -92,6 +94,14 @@ type executableDataMarshaling struct {
|
|||
ExcessBlobGas *hexutil.Uint64
|
||||
}
|
||||
|
||||
// StatelessPayloadStatusV1 is the result of a stateless payload execution.
|
||||
type StatelessPayloadStatusV1 struct {
|
||||
Status string `json:"status"`
|
||||
StateRoot common.Hash `json:"stateRoot"`
|
||||
ReceiptsRoot common.Hash `json:"receiptsRoot"`
|
||||
ValidationError *string `json:"validationError"`
|
||||
}
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go
|
||||
|
||||
type ExecutionPayloadEnvelope struct {
|
||||
|
|
@ -99,6 +109,7 @@ type ExecutionPayloadEnvelope struct {
|
|||
BlockValue *big.Int `json:"blockValue" gencodec:"required"`
|
||||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||
Override bool `json:"shouldOverrideBuilder"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
}
|
||||
|
||||
type BlobsBundleV1 struct {
|
||||
|
|
@ -114,6 +125,7 @@ type executionPayloadEnvelopeMarshaling struct {
|
|||
|
||||
type PayloadStatusV1 struct {
|
||||
Status string `json:"status"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
LatestValidHash *common.Hash `json:"latestValidHash"`
|
||||
ValidationError *string `json:"validationError"`
|
||||
}
|
||||
|
|
@ -201,6 +213,20 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
|||
// Withdrawals value will propagate through the returned block. Empty
|
||||
// Withdrawals value must be passed via non-nil, length 0 value in data.
|
||||
func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
|
||||
block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block.Hash() != data.BlockHash {
|
||||
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used
|
||||
// for stateless execution, so it skips checking if the executable data hashes to
|
||||
// the requested hash (stateless has to *compute* the root hash, it's not given).
|
||||
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
|
||||
txs, err := decodeTransactions(data.Transactions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -235,7 +261,19 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
|||
h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil))
|
||||
withdrawalsRoot = &h
|
||||
}
|
||||
|
||||
// Compute requestsHash if any requests are non-nil.
|
||||
var (
|
||||
requestsHash *common.Hash
|
||||
requests types.Requests
|
||||
)
|
||||
if data.Deposits != nil {
|
||||
requests = make(types.Requests, 0)
|
||||
for _, d := range data.Deposits {
|
||||
requests = append(requests, types.NewRequest(d))
|
||||
}
|
||||
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
|
||||
requestsHash = &h
|
||||
}
|
||||
header := &types.Header{
|
||||
ParentHash: data.ParentHash,
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
|
|
@ -256,13 +294,12 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
|||
ExcessBlobGas: data.ExcessBlobGas,
|
||||
BlobGasUsed: data.BlobGasUsed,
|
||||
ParentBeaconRoot: beaconRoot,
|
||||
RequestsHash: requestsHash,
|
||||
}
|
||||
block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals})
|
||||
if block.Hash() != data.BlockHash {
|
||||
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash())
|
||||
}
|
||||
|
||||
return block, nil
|
||||
return types.NewBlockWithHeader(header).
|
||||
WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests}).
|
||||
WithWitness(data.ExecutionWitness),
|
||||
nil
|
||||
}
|
||||
|
||||
// BlockToExecutableData constructs the ExecutableData structure by filling the
|
||||
|
|
@ -286,6 +323,7 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
|
|||
Withdrawals: block.Withdrawals(),
|
||||
BlobGasUsed: block.BlobGasUsed(),
|
||||
ExcessBlobGas: block.ExcessBlobGas(),
|
||||
ExecutionWitness: block.ExecutionWitness(),
|
||||
}
|
||||
bundle := BlobsBundleV1{
|
||||
Commitments: make([]hexutil.Bytes, 0),
|
||||
|
|
@ -299,13 +337,30 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
|
|||
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
|
||||
}
|
||||
}
|
||||
setRequests(block.Requests(), data)
|
||||
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
|
||||
}
|
||||
|
||||
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
|
||||
type ExecutionPayloadBodyV1 struct {
|
||||
// setRequests differentiates the different request types and
|
||||
// assigns them to the associated fields in ExecutableData.
|
||||
func setRequests(requests types.Requests, data *ExecutableData) {
|
||||
if requests != nil {
|
||||
// If requests is non-nil, it means deposits are available in block and we
|
||||
// should return an empty slice instead of nil if there are no deposits.
|
||||
data.Deposits = make(types.Deposits, 0)
|
||||
}
|
||||
for _, r := range requests {
|
||||
if d, ok := r.Inner().(*types.Deposit); ok {
|
||||
data.Deposits = append(data.Deposits, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange
|
||||
type ExecutionPayloadBody struct {
|
||||
TransactionData []hexutil.Bytes `json:"transactions"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
Deposits types.Deposits `json:"depositRequests"`
|
||||
}
|
||||
|
||||
// Client identifiers to support ClientVersionV1.
|
||||
|
|
|
|||
0
beacon/light/api/api_server.go
Executable file → Normal file
0
beacon/light/api/api_server.go
Executable file → Normal file
49
beacon/light/api/light_api.go
Executable file → Normal file
49
beacon/light/api/light_api.go
Executable file → Normal file
|
|
@ -23,6 +23,8 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -120,8 +122,12 @@ func NewBeaconLightApi(url string, customHeaders map[string]string) *BeaconLight
|
|||
}
|
||||
}
|
||||
|
||||
func (api *BeaconLightApi) httpGet(path string) ([]byte, error) {
|
||||
req, err := http.NewRequest("GET", api.url+path, nil)
|
||||
func (api *BeaconLightApi) httpGet(path string, params url.Values) ([]byte, error) {
|
||||
uri, err := api.buildURL(path, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := http.NewRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -145,17 +151,16 @@ func (api *BeaconLightApi) httpGet(path string) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (api *BeaconLightApi) httpGetf(format string, params ...any) ([]byte, error) {
|
||||
return api.httpGet(fmt.Sprintf(format, params...))
|
||||
}
|
||||
|
||||
// GetBestUpdatesAndCommittees fetches and validates LightClientUpdate for given
|
||||
// period and full serialized committee for the next period (committee root hash
|
||||
// equals update.NextSyncCommitteeRoot).
|
||||
// Note that the results are validated but the update signature should be verified
|
||||
// by the caller as its validity depends on the update chain.
|
||||
func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64) ([]*types.LightClientUpdate, []*types.SerializedSyncCommittee, error) {
|
||||
resp, err := api.httpGetf("/eth/v1/beacon/light_client/updates?start_period=%d&count=%d", firstPeriod, count)
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/updates", map[string][]string{
|
||||
"start_period": {strconv.FormatUint(firstPeriod, 10)},
|
||||
"count": {strconv.FormatUint(count, 10)},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -192,7 +197,7 @@ func (api *BeaconLightApi) GetBestUpdatesAndCommittees(firstPeriod, count uint64
|
|||
// See data structure definition here:
|
||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
|
||||
func (api *BeaconLightApi) GetOptimisticUpdate() (types.OptimisticUpdate, error) {
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update")
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/optimistic_update", nil)
|
||||
if err != nil {
|
||||
return types.OptimisticUpdate{}, err
|
||||
}
|
||||
|
|
@ -245,7 +250,7 @@ func decodeOptimisticUpdate(enc []byte) (types.OptimisticUpdate, error) {
|
|||
// See data structure definition here:
|
||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
|
||||
func (api *BeaconLightApi) GetFinalityUpdate() (types.FinalityUpdate, error) {
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update")
|
||||
resp, err := api.httpGet("/eth/v1/beacon/light_client/finality_update", nil)
|
||||
if err != nil {
|
||||
return types.FinalityUpdate{}, err
|
||||
}
|
||||
|
|
@ -311,7 +316,7 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool,
|
|||
} else {
|
||||
blockId = blockRoot.Hex()
|
||||
}
|
||||
resp, err := api.httpGetf("/eth/v1/beacon/headers/%s", blockId)
|
||||
resp, err := api.httpGet(fmt.Sprintf("/eth/v1/beacon/headers/%s", blockId), nil)
|
||||
if err != nil {
|
||||
return types.Header{}, false, false, err
|
||||
}
|
||||
|
|
@ -342,7 +347,7 @@ func (api *BeaconLightApi) GetHeader(blockRoot common.Hash) (types.Header, bool,
|
|||
|
||||
// GetCheckpointData fetches and validates bootstrap data belonging to the given checkpoint.
|
||||
func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types.BootstrapData, error) {
|
||||
resp, err := api.httpGetf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:])
|
||||
resp, err := api.httpGet(fmt.Sprintf("/eth/v1/beacon/light_client/bootstrap/0x%x", checkpointHash[:]), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -384,7 +389,7 @@ func (api *BeaconLightApi) GetCheckpointData(checkpointHash common.Hash) (*types
|
|||
}
|
||||
|
||||
func (api *BeaconLightApi) GetBeaconBlock(blockRoot common.Hash) (*types.BeaconBlock, error) {
|
||||
resp, err := api.httpGetf("/eth/v2/beacon/blocks/0x%x", blockRoot)
|
||||
resp, err := api.httpGet(fmt.Sprintf("/eth/v2/beacon/blocks/0x%x", blockRoot), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -545,9 +550,13 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
|
|||
// established. It can only return nil when the context is canceled.
|
||||
func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream {
|
||||
for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) {
|
||||
path := "/eth/v1/events?topics=head&topics=light_client_finality_update&topics=light_client_optimistic_update"
|
||||
log.Trace("Sending event subscription request")
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil)
|
||||
uri, err := api.buildURL("/eth/v1/events", map[string][]string{"topics": {"head", "light_client_finality_update", "light_client_optimistic_update"}})
|
||||
if err != nil {
|
||||
listener.OnError(fmt.Errorf("error creating event subscription URL: %v", err))
|
||||
continue
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", uri, nil)
|
||||
if err != nil {
|
||||
listener.OnError(fmt.Errorf("error creating event subscription request: %v", err))
|
||||
continue
|
||||
|
|
@ -576,3 +585,15 @@ func ctxSleep(ctx context.Context, timeout time.Duration) (ok bool) {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (api *BeaconLightApi) buildURL(path string, params url.Values) (string, error) {
|
||||
uri, err := url.Parse(api.url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
uri = uri.JoinPath(path)
|
||||
if params != nil {
|
||||
uri.RawQuery = params.Encode()
|
||||
}
|
||||
return uri.String(), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,6 +201,34 @@ func TestUpdateSyncDifferentHeads(t *testing.T) {
|
|||
chain.ExpNextSyncPeriod(t, 17)
|
||||
}
|
||||
|
||||
func TestRangeLock(t *testing.T) {
|
||||
r := make(rangeLock)
|
||||
|
||||
// Lock from 0 to 99.
|
||||
r.lock(0, 100, 1)
|
||||
for i := 0; i < 100; i++ {
|
||||
if v, ok := r[uint64(i)]; v <= 0 || !ok {
|
||||
t.Fatalf("integer space: %d not locked", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock from 0 to 99.
|
||||
r.lock(0, 100, -1)
|
||||
for i := 0; i < 100; i++ {
|
||||
if v, ok := r[uint64(i)]; v > 0 || ok {
|
||||
t.Fatalf("integer space: %d is locked", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Lock from 0 to 99 then unlock from 10 to 59.
|
||||
r.lock(0, 100, 1)
|
||||
r.lock(10, 50, -1)
|
||||
first, count := r.firstUnlocked(0, 100)
|
||||
if first != 10 || count != 50 {
|
||||
t.Fatalf("unexpected first: %d or count: %d", first, count)
|
||||
}
|
||||
}
|
||||
|
||||
func testRespUpdate(request requestWithID) request.Response {
|
||||
var resp RespUpdates
|
||||
if request.request == nil {
|
||||
|
|
|
|||
|
|
@ -5,55 +5,56 @@
|
|||
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
||||
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
||||
|
||||
# version:golang 1.22.6
|
||||
# version:golang 1.23.1
|
||||
# https://go.dev/dl/
|
||||
9e48d99d519882579917d8189c17e98c373ce25abaebb98772e2927088992a51 go1.22.6.src.tar.gz
|
||||
eeb0cc42120cbae6d3695dae2e5420fa0e93a5db957db139b55efdb879dd9856 go1.22.6.aix-ppc64.tar.gz
|
||||
b47ac340f0b072943fed1f558a26eb260cc23bd21b8af175582e9103141d465b go1.22.6.darwin-amd64.pkg
|
||||
9c3c0124b01b5365f73a1489649f78f971ecf84844ad9ca58fde133096ddb61b go1.22.6.darwin-amd64.tar.gz
|
||||
14d0355ec1c0eeb213a16efa8635fac1f16067ef78a8173abf9a8c7b805e551e go1.22.6.darwin-arm64.pkg
|
||||
ebac39fd44fc22feed1bb519af431c84c55776e39b30f4fd62930da9c0cfd1e3 go1.22.6.darwin-arm64.tar.gz
|
||||
3695b10c722a4920c8a736284f8820c142e1e752f3a87f797a45c64366f7a173 go1.22.6.dragonfly-amd64.tar.gz
|
||||
a9b9570c80294a664d50b566d6bd1aa42465997d2d76a57936b32f55f5c69c63 go1.22.6.freebsd-386.tar.gz
|
||||
424a5618406800365fe3ad96a795fb55ce394bea3ff48eaf56d292bf7a916d1e go1.22.6.freebsd-amd64.tar.gz
|
||||
e0dce3a6dbe8e7e054d329dd4cb403935c63c0f7e22e693077aa60e12018b883 go1.22.6.freebsd-arm.tar.gz
|
||||
34930b01f58889c71f7a78c51c6c3bd2ce289ac7862c76dab691303cfa935fd1 go1.22.6.freebsd-arm64.tar.gz
|
||||
4c9d630e55d4d600a5b4297e59620c3bdfe63a441981682b3638e2fdda228a44 go1.22.6.freebsd-riscv64.tar.gz
|
||||
9ed63feaf2ef56c56f1cf0d9d3fab4006efd22a38e2f1f5252e95c6ac09332f3 go1.22.6.illumos-amd64.tar.gz
|
||||
9e680027b058beab10ce5938607660964b6d2c564bf50bdb01aa090dc5beda98 go1.22.6.linux-386.tar.gz
|
||||
999805bed7d9039ec3da1a53bfbcafc13e367da52aa823cb60b68ba22d44c616 go1.22.6.linux-amd64.tar.gz
|
||||
c15fa895341b8eaf7f219fada25c36a610eb042985dc1a912410c1c90098eaf2 go1.22.6.linux-arm64.tar.gz
|
||||
b566484fe89a54c525dd1a4cbfec903c1f6e8f0b7b3dbaf94c79bc9145391083 go1.22.6.linux-armv6l.tar.gz
|
||||
1ee6e1896aea856142d2af7045cea118995b39404aa61afd12677d023d47ee69 go1.22.6.linux-loong64.tar.gz
|
||||
fdd0e1a3e178f9bc79adf6ff1e3de4554ce581b4c468fd6e113c43fbbbe1eec6 go1.22.6.linux-mips.tar.gz
|
||||
d3e5a621fc5a07759e503a971af0b28ded6a7d6f5604ab511f51f930a18dd3e4 go1.22.6.linux-mips64.tar.gz
|
||||
01547606c5b5c1b0e5587b3afd65172860d2f4755e523785832905759ecce2d7 go1.22.6.linux-mips64le.tar.gz
|
||||
2cd771416ae03c11240cfdb551d66ab9a941077664f3727b966f94386c23b0fa go1.22.6.linux-mipsle.tar.gz
|
||||
6ef61d517777925e6bdb0321ea42d5f60acc20c1314dd902b9d0bfa3a5fd4fca go1.22.6.linux-ppc64.tar.gz
|
||||
9d99fce3f6f72a76630fe91ec0884dfe3db828def4713368424900fa98bb2bd6 go1.22.6.linux-ppc64le.tar.gz
|
||||
30be9c9b9cc4f044d4da9a33ee601ab7b3aff4246107d323a79e08888710754e go1.22.6.linux-riscv64.tar.gz
|
||||
82f3bae3ddb4ede45b848db48c5486fadb58551e74507bda45484257e7194a95 go1.22.6.linux-s390x.tar.gz
|
||||
85b2eb9d40a930bd3e75d0096a6eb5847aac86c5085e6d13a5845e9ef03f8d4b go1.22.6.netbsd-386.tar.gz
|
||||
6e9acbdc34fb2a942d547c47c9c1989bb6e32b4a37d57fb312499e2bb33b46b7 go1.22.6.netbsd-amd64.tar.gz
|
||||
e6eff3cf0038f2a9b0c9e01e228577a783bddcd8051222a3d949e24ee392e769 go1.22.6.netbsd-arm.tar.gz
|
||||
43a7e2ba22da700b844f7561e3dd5434540ed6c9781be2e9c42e8a8cbf558f8e go1.22.6.netbsd-arm64.tar.gz
|
||||
a90b758ccb45d8a17af8e140fafa1e97607de5a7ecd53a4c55f69258bfb043d0 go1.22.6.openbsd-386.tar.gz
|
||||
cc13436c4a644e55bedcea65981eb80ca8317b39b129f5563ab3b6da1391bd47 go1.22.6.openbsd-amd64.tar.gz
|
||||
aee34f61ba2b0a8f2618f5c7065e20da7714ce7651680509eda30728fe01ee88 go1.22.6.openbsd-arm.tar.gz
|
||||
c67d57daf8baada93c69c8fb02401270cd33159730b1f2d70d9e724ba1a918cf go1.22.6.openbsd-arm64.tar.gz
|
||||
03e1f96002e94a6b381bcf66a0a62b9d5f63148682a780d727840ad540185c7c go1.22.6.openbsd-ppc64.tar.gz
|
||||
0ac2b5bbe2c8a293d284512630e629bf0578aaa7b7b1f39ac4ee182c7924aaad go1.22.6.plan9-386.tar.gz
|
||||
f9afdab8a72a8d874f023f5605482cc94160843ac768dbd840e6f772d16578c7 go1.22.6.plan9-amd64.tar.gz
|
||||
4b9f01a47e6a29d57cbb3097b6770583336cef9c8f0d51d3d1451e42a851002e go1.22.6.plan9-arm.tar.gz
|
||||
46c2552ac7b8d6314a52e14e0a0761aaeebdd6aba5f531de386f4cf2b66ec723 go1.22.6.solaris-amd64.tar.gz
|
||||
a57821dab76af1ef7a6b62db1628f0caa74343e0c7cb829df9ce8ea0713a3e8e go1.22.6.windows-386.msi
|
||||
eb734bacc9aabca1273b61dd392bb84a9bb33783f5e2fff2cd6ab9885bbefbe6 go1.22.6.windows-386.zip
|
||||
1238a3e6892eb8a0eb3fe0640e18ab82ca21cc1a933f16897b2ad081f057b5da go1.22.6.windows-amd64.msi
|
||||
6023083a6e4d3199b44c37e9ba7b25d9674da20fd846a35ee5f9589d81c21a6a go1.22.6.windows-amd64.zip
|
||||
6791218c568a3d000cb36317506541d7fd67e7cfe613baaf361ca36cad5e2cd5 go1.22.6.windows-arm.msi
|
||||
ee41ca83bb07c4fd46a1d6b2d083519bb8ca156fcd9db37ee711234d43126e2f go1.22.6.windows-arm.zip
|
||||
91c6b3376612095315a0aeae4b03e3da34fabe9dfd4532d023e2a70f913cf22a go1.22.6.windows-arm64.msi
|
||||
7cf55f357ba8116cd3bff992980e20a704ba451b3dab341cf1787b133d900512 go1.22.6.windows-arm64.zip
|
||||
6ee44e298379d146a5e5aa6b1c5b5d5f5d0a3365eabdd70741e6e21340ec3b0d go1.23.1.src.tar.gz
|
||||
f17f2791717c15728ec63213a014e244c35f9c8846fb29f5a1b63d0c0556f756 go1.23.1.aix-ppc64.tar.gz
|
||||
dd9e772686ed908bcff94b6144322d4e2473a7dcd7c696b7e8b6d12f23c887fd go1.23.1.darwin-amd64.pkg
|
||||
488d9e4ca3e3ed513ee4edd91bef3a2360c65fa6d6be59cf79640bf840130a58 go1.23.1.darwin-amd64.tar.gz
|
||||
be34b488157ec69d94e26e1554558219a2c90789bcb7e3686965a7f9c8cfcbe7 go1.23.1.darwin-arm64.pkg
|
||||
e223795ca340e285a760a6446ce57a74500b30e57469a4109961d36184d3c05a go1.23.1.darwin-arm64.tar.gz
|
||||
6af626176923a6ae6c5de6dc1c864f38365793c0e4ecd0d6eab847bdc23953e5 go1.23.1.dragonfly-amd64.tar.gz
|
||||
cc957c1a019702e6cdc2e257202d42799011ebc1968b6c3bcd6b1965952607d5 go1.23.1.freebsd-386.tar.gz
|
||||
a7d57781c50bb80886a8f04066791956d45aa3eea0f83070c5268b6223afb2ff go1.23.1.freebsd-amd64.tar.gz
|
||||
c7b09f3fef456048e596db9bea746eb66796aeb82885622b0388feee18f36a3e go1.23.1.freebsd-arm.tar.gz
|
||||
b05cd6a77995a0c8439d88df124811c725fb78b942d0b6dd1643529d7ba62f1f go1.23.1.freebsd-arm64.tar.gz
|
||||
56236ae70be1613f2915943b94f53c96be5bffc0719314078facd778a89bc57e go1.23.1.freebsd-riscv64.tar.gz
|
||||
8644c52df4e831202114fd67c9fcaf1f7233ad27bf945ac53fa7217cf1a0349f go1.23.1.illumos-amd64.tar.gz
|
||||
cdee2f4e2efa001f7ee75c90f2efc310b63346cfbba7b549987e9139527c6b17 go1.23.1.linux-386.tar.gz
|
||||
49bbb517cfa9eee677e1e7897f7cf9cfdbcf49e05f61984a2789136de359f9bd go1.23.1.linux-amd64.tar.gz
|
||||
faec7f7f8ae53fda0f3d408f52182d942cc89ef5b7d3d9f23ff117437d4b2d2f go1.23.1.linux-arm64.tar.gz
|
||||
6c7832c7dcd8fb6d4eb308f672a725393403c74ee7be1aeccd8a443015df99de go1.23.1.linux-armv6l.tar.gz
|
||||
649ce3856ddc808c00b14a46232eab0bf95e7911cdf497010b17d76656f5ca4e go1.23.1.linux-loong64.tar.gz
|
||||
201911048f234e5a0c51ec94b1a11d4e47062fee4398b1d2faa6c820dc026724 go1.23.1.linux-mips.tar.gz
|
||||
2bce3743df463915e45d2612f9476ffb03d0b3750b1cb3879347de08715b5fc6 go1.23.1.linux-mips64.tar.gz
|
||||
54e301f266e33431b0703136e0bbd4cf02461b1ecedd37b7cbd90cb862a98e5f go1.23.1.linux-mips64le.tar.gz
|
||||
8efd495e93d17408c0803595cdc3bf13cb28e0f957aeabd9cc18245fb8e64019 go1.23.1.linux-mipsle.tar.gz
|
||||
52bd68689095831ad9af7160844c23b28bb8d0acd268de7e300ff5f0662b7a07 go1.23.1.linux-ppc64.tar.gz
|
||||
042888cae54b5fbfd9dd1e3b6bc4a5134879777fe6497fc4c62ec394b5ecf2da go1.23.1.linux-ppc64le.tar.gz
|
||||
1a4a609f0391bea202d9095453cbfaf7368fa88a04c206bf9dd715a738664dc3 go1.23.1.linux-riscv64.tar.gz
|
||||
47dc49ad45c45e192efa0df7dc7bc5403f5f2d15b5d0dc74ef3018154b616f4d go1.23.1.linux-s390x.tar.gz
|
||||
fbfbd5efa6a5d581ea7f5e65015f927db0e52135cab057e43d39d5482da54b61 go1.23.1.netbsd-386.tar.gz
|
||||
e96e1cc5cf36113ee6099d1a7306b22cd9c3f975a36bdff954c59f104f22b853 go1.23.1.netbsd-amd64.tar.gz
|
||||
c394dfc06bfc276a591209a37e09cd39089ec9a9cc3db30b94814ce2e39eb1d4 go1.23.1.netbsd-arm.tar.gz
|
||||
b3b35d64f32821a68b3e2994032dbefb81978f2ec3f218c7a770623b82d36b8e go1.23.1.netbsd-arm64.tar.gz
|
||||
3c775c4c16c182e33c2c4ac090d9a247a93b3fb18a3df01d87d490f29599faff go1.23.1.openbsd-386.tar.gz
|
||||
5edbe53b47c57b32707fd7154536fbe9eaa79053fea01650c93b54cdba13fc0f go1.23.1.openbsd-amd64.tar.gz
|
||||
c30903dd8fa98b8aca8e9db0962ce9f55502aed93e0ef41e5ae148aaa0088de1 go1.23.1.openbsd-arm.tar.gz
|
||||
12da183489e58f9c6b357bc1b626f85ed7d4220cab31a49d6a49e6ac6a718b67 go1.23.1.openbsd-arm64.tar.gz
|
||||
9cc9aad37696a4a10c31dcec9e35a308de0b369dad354d54cf07406ac6fa7c6f go1.23.1.openbsd-ppc64.tar.gz
|
||||
e1d740dda062ce5a276a0c3ed7d8b6353238bc8ff405f63e2e3480bfd26a5ec5 go1.23.1.openbsd-riscv64.tar.gz
|
||||
da2a37f9987f01f096859230aa13ecc4ad2e7884465bce91004bc78c64435d65 go1.23.1.plan9-386.tar.gz
|
||||
fd8fff8b0697d55c4a4d02a8dc998192b80a9dc2a057647373d6ff607cad29de go1.23.1.plan9-amd64.tar.gz
|
||||
52efbc5804c1c86ba7868aa8ebbc31cc8c2a27b62a60fd57944970d48fc67525 go1.23.1.plan9-arm.tar.gz
|
||||
f54205f21e2143f2ada1bf1c00ddf64590f5139d5c3fb77cc06175f0d8cc7567 go1.23.1.solaris-amd64.tar.gz
|
||||
369a17f0cfd29e5c848e58ffe0d772da20abe334d1c7ca01dbcd55bb3db0b440 go1.23.1.windows-386.msi
|
||||
ab866f47d7be56e6b1c67f1d529bf4c23331a339fb0785f435a0552d352cb257 go1.23.1.windows-386.zip
|
||||
e99dac215ee437b9bb8f8b14bbfe0e8756882c1ed291f30818e8363bc9c047a5 go1.23.1.windows-amd64.msi
|
||||
32dedf277c86610e380e1765593edb66876f00223df71690bd6be68ee17675c0 go1.23.1.windows-amd64.zip
|
||||
23169c79dc6b54e0dffb25be6b67425ad9759392a58309bc057430a9bf4c8f6a go1.23.1.windows-arm.msi
|
||||
1a57615a09f13534f88e9f2d7efd5743535d1a5719b19e520eef965a634f8efb go1.23.1.windows-arm.zip
|
||||
313e1a543931ad8735b4df8969e00f5f4c2ef07be21f54015ede961a70263d35 go1.23.1.windows-arm64.msi
|
||||
64ad0954d2c33f556fb1018d62de091254aa6e3a94f1c8a8b16af0d3701d194e go1.23.1.windows-arm64.zip
|
||||
|
||||
# version:golangci 1.59.0
|
||||
# https://github.com/golangci/golangci-lint/releases/
|
||||
|
|
|
|||
82
build/ci.go
82
build/ci.go
|
|
@ -126,8 +126,6 @@ var (
|
|||
"focal", // 20.04, EOL: 04/2030
|
||||
"jammy", // 22.04, EOL: 04/2032
|
||||
"noble", // 24.04, EOL: 04/2034
|
||||
|
||||
"mantic", // 23.10, EOL: 07/2024
|
||||
}
|
||||
|
||||
// This is where the tests should be unpacked.
|
||||
|
|
@ -239,6 +237,10 @@ func doInstall(cmdline []string) {
|
|||
// buildFlags returns the go tool flags for building.
|
||||
func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) {
|
||||
var ld []string
|
||||
// See https://github.com/golang/go/issues/33772#issuecomment-528176001
|
||||
// We need to set --buildid to the linker here, and also pass --build-id to the
|
||||
// cgo-linker further down.
|
||||
ld = append(ld, "--buildid=none")
|
||||
if env.Commit != "" {
|
||||
ld = append(ld, "-X", "github.com/maticnetwork/bor/internal/version.gitCommit="+env.Commit)
|
||||
ld = append(ld, "-X", "github.com/maticnetwork/bor/internal/version.gitDate="+env.Date)
|
||||
|
|
@ -251,7 +253,11 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (
|
|||
if runtime.GOOS == "linux" {
|
||||
// Enforce the stacksize to 8M, which is the case on most platforms apart from
|
||||
// alpine Linux.
|
||||
extld := []string{"-Wl,-z,stack-size=0x800000"}
|
||||
// See https://sourceware.org/binutils/docs-2.23.1/ld/Options.html#Options
|
||||
// regarding the options --build-id=none and --strip-all. It is needed for
|
||||
// reproducible builds; removing references to temporary files in C-land, and
|
||||
// making build-id reproducably absent.
|
||||
extld := []string{"-Wl,-z,stack-size=0x800000,--build-id=none,--strip-all"}
|
||||
if staticLinking {
|
||||
extld = append(extld, "-static")
|
||||
// Under static linking, use of certain glibc features must be
|
||||
|
|
@ -298,7 +304,7 @@ func doTest(cmdline []string) {
|
|||
gotest := tc.Go("test")
|
||||
|
||||
// CI needs a bit more time for the statetests (default 10m).
|
||||
gotest.Args = append(gotest.Args, "-timeout=20m")
|
||||
gotest.Args = append(gotest.Args, "-timeout=30m")
|
||||
|
||||
// Enable CKZG backend in CI.
|
||||
gotest.Args = append(gotest.Args, "-tags=ckzg")
|
||||
|
|
@ -349,10 +355,10 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
|
|||
return filepath.Join(cachedir, base)
|
||||
}
|
||||
|
||||
// hashSourceFiles iterates all files under the top-level project directory
|
||||
// hashAllSourceFiles iterates all files under the top-level project directory
|
||||
// computing the hash of each file (excluding files within the tests
|
||||
// subrepo)
|
||||
func hashSourceFiles() (map[string]common.Hash, error) {
|
||||
func hashAllSourceFiles() (map[string]common.Hash, error) {
|
||||
res := make(map[string]common.Hash)
|
||||
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
|
||||
if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) {
|
||||
|
|
@ -379,6 +385,56 @@ func hashSourceFiles() (map[string]common.Hash, error) {
|
|||
return res, nil
|
||||
}
|
||||
|
||||
// hashSourceFiles iterates the provided set of filepaths (relative to the top-level geth project directory)
|
||||
// computing the hash of each file.
|
||||
func hashSourceFiles(files []string) (map[string]common.Hash, error) {
|
||||
res := make(map[string]common.Hash)
|
||||
for _, filePath := range files {
|
||||
f, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hasher := sha256.New()
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res[filePath] = common.Hash(hasher.Sum(nil))
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// compareHashedFilesets compares two maps (key is relative file path to top-level geth directory, value is its hash)
|
||||
// and returns the list of file paths whose hashes differed.
|
||||
func compareHashedFilesets(preHashes map[string]common.Hash, postHashes map[string]common.Hash) []string {
|
||||
updates := []string{}
|
||||
for path, postHash := range postHashes {
|
||||
preHash, ok := preHashes[path]
|
||||
if !ok || preHash != postHash {
|
||||
updates = append(updates, path)
|
||||
}
|
||||
}
|
||||
return updates
|
||||
}
|
||||
|
||||
func doGoModTidy() {
|
||||
targetFiles := []string{"go.mod", "go.sum"}
|
||||
preHashes, err := hashSourceFiles(targetFiles)
|
||||
if err != nil {
|
||||
log.Fatal("failed to hash go.mod/go.sum", "err", err)
|
||||
}
|
||||
tc := new(build.GoToolchain)
|
||||
c := tc.Go("mod", "tidy")
|
||||
build.MustRun(c)
|
||||
postHashes, err := hashSourceFiles(targetFiles)
|
||||
updates := compareHashedFilesets(preHashes, postHashes)
|
||||
for _, updatedFile := range updates {
|
||||
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
|
||||
}
|
||||
if len(updates) != 0 {
|
||||
log.Fatal("go.sum and/or go.mod were updated by running 'go mod tidy'")
|
||||
}
|
||||
}
|
||||
|
||||
// doGenerate ensures that re-generating generated files does not cause
|
||||
// any mutations in the source file tree: i.e. all generated files were
|
||||
// updated and committed. Any stale generated files are updated.
|
||||
|
|
@ -395,7 +451,7 @@ func doGenerate() {
|
|||
var preHashes map[string]common.Hash
|
||||
if *verify {
|
||||
var err error
|
||||
preHashes, err = hashSourceFiles()
|
||||
preHashes, err = hashAllSourceFiles()
|
||||
if err != nil {
|
||||
log.Fatal("failed to compute map of source hashes", "err", err)
|
||||
}
|
||||
|
|
@ -410,17 +466,11 @@ func doGenerate() {
|
|||
return
|
||||
}
|
||||
// Check if files were changed.
|
||||
postHashes, err := hashSourceFiles()
|
||||
postHashes, err := hashAllSourceFiles()
|
||||
if err != nil {
|
||||
log.Fatal("error computing source tree file hashes", "err", err)
|
||||
}
|
||||
updates := []string{}
|
||||
for path, postHash := range postHashes {
|
||||
preHash, ok := preHashes[path]
|
||||
if !ok || preHash != postHash {
|
||||
updates = append(updates, path)
|
||||
}
|
||||
}
|
||||
updates := compareHashedFilesets(preHashes, postHashes)
|
||||
for _, updatedFile := range updates {
|
||||
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
|
||||
}
|
||||
|
|
@ -443,6 +493,8 @@ func doLint(cmdline []string) {
|
|||
linter := downloadLinter(*cachedir)
|
||||
lflags := []string{"run", "--config", ".golangci.yml"}
|
||||
build.MustRunCommandWithOutput(linter, append(lflags, packages...)...)
|
||||
|
||||
doGoModTidy()
|
||||
fmt.Println("You have achieved perfection.")
|
||||
}
|
||||
|
||||
|
|
|
|||
0
build/deb/ethereum/completions/bash/geth
Executable file → Normal file
0
build/deb/ethereum/completions/bash/geth
Executable file → Normal file
0
build/goimports.sh
Executable file → Normal file
0
build/goimports.sh
Executable file → Normal file
0
build/travis_keepalive.sh
Executable file → Normal file
0
build/travis_keepalive.sh
Executable file → Normal file
|
|
@ -8,7 +8,8 @@ chain = "mainnet"
|
|||
# vmdebug = false
|
||||
datadir = "/var/lib/bor/data"
|
||||
# ancient = ""
|
||||
# "db.engine" = "leveldb"
|
||||
# "db.engine" = "pebble"
|
||||
# "state.scheme" = "path"
|
||||
# keystore = "/var/lib/bor/keystore"
|
||||
# "rpc.batchlimit" = 100
|
||||
# "rpc.returndatalimit" = 100000
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ func main() {
|
|||
//TODO datadir for optional permanent database
|
||||
utils.MainnetFlag,
|
||||
utils.SepoliaFlag,
|
||||
utils.GoerliFlag,
|
||||
utils.BlsyncApiFlag,
|
||||
utils.BlsyncJWTSecretFlag,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ GLOBAL OPTIONS:
|
|||
--loglevel value log level to emit to the screen (default: 4)
|
||||
--keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore")
|
||||
--configdir value Directory for Clef configuration (default: "$HOME/.clef")
|
||||
--chainid value Chain id to use for signing (1=mainnet, 5=Goerli) (default: 1)
|
||||
--chainid value Chain id to use for signing (1=mainnet, 17000=Holesky) (default: 1)
|
||||
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
|
||||
--nousb Disables monitoring for and managing USB hardware wallets
|
||||
--pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ var (
|
|||
chainIdFlag = &cli.Int64Flag{
|
||||
Name: "chainid",
|
||||
Value: params.MainnetChainConfig.ChainID.Int64(),
|
||||
Usage: "Chain id to use for signing (1=mainnet, 5=Goerli)",
|
||||
Usage: "Chain id to use for signing (1=mainnet, 17000=Holesky)",
|
||||
}
|
||||
rpcPortFlag = &cli.IntFlag{
|
||||
Name: "http.port",
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ set to standard output. The following filters are supported:
|
|||
- `-limit <N>` limits the output set to N entries, taking the top N nodes by score
|
||||
- `-ip <CIDR>` filters nodes by IP subnet
|
||||
- `-min-age <duration>` filters nodes by 'first seen' time
|
||||
- `-eth-network <mainnet/goerli/sepolia/holesky>` filters nodes by "eth" ENR entry
|
||||
- `-eth-network <mainnet/sepolia/holesky>` filters nodes by "eth" ENR entry
|
||||
- `-les-server` filters nodes by LES server support
|
||||
- `-snap` filters nodes by snap protocol support
|
||||
|
||||
|
|
|
|||
|
|
@ -98,8 +98,8 @@ func (c *cloudflareClient) checkZone(name string) error {
|
|||
if !strings.HasSuffix(name, "."+zone.Name) {
|
||||
return fmt.Errorf("CloudFlare zone name %q does not match name %q to be deployed", zone.Name, name)
|
||||
}
|
||||
|
||||
needPerms := map[string]bool{"#zone:edit": false, "#zone:read": false}
|
||||
// Necessary permissions for Cloudlare management - Zone:Read, DNS:Read, Zone:Edit, DNS:Edit
|
||||
needPerms := map[string]bool{"#zone:edit": false, "#zone:read": false, "#dns_records:read": false, "#dns_records:edit": false}
|
||||
for _, perm := range zone.Permissions {
|
||||
if _, ok := needPerms[perm]; ok {
|
||||
needPerms[perm] = true
|
||||
|
|
|
|||
0
cmd/devp2p/internal/ethtest/testdata/chain.rlp.gz
vendored
Executable file → Normal file
0
cmd/devp2p/internal/ethtest/testdata/chain.rlp.gz
vendored
Executable file → Normal file
|
|
@ -259,8 +259,6 @@ func ethFilter(args []string) (nodeFilter, error) {
|
|||
switch args[0] {
|
||||
case "mainnet":
|
||||
filter = forkid.NewStaticFilter(params.MainnetChainConfig, core.DefaultGenesisBlock().ToBlock())
|
||||
case "goerli":
|
||||
filter = forkid.NewStaticFilter(params.GoerliChainConfig, core.DefaultGoerliGenesisBlock().ToBlock())
|
||||
case "sepolia":
|
||||
filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock())
|
||||
case "bor-mumbai":
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ type ExecutionResult struct {
|
|||
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
|
||||
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
|
||||
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
|
||||
RequestsHash *common.Hash `json:"requestsRoot,omitempty"`
|
||||
DepositRequests *types.Deposits `json:"depositRequests,omitempty"`
|
||||
}
|
||||
|
||||
type ommer struct {
|
||||
|
|
@ -201,7 +203,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
|
||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
||||
}
|
||||
|
||||
if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number)) {
|
||||
var (
|
||||
prevNumber = pre.Env.Number - 1
|
||||
prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)]
|
||||
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
|
||||
)
|
||||
core.ProcessParentBlockHash(prevHash, evm, statedb)
|
||||
}
|
||||
for i := 0; txIt.Next(); i++ {
|
||||
tx, err := txIt.Tx()
|
||||
if err != nil {
|
||||
|
|
@ -253,7 +262,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||
}
|
||||
// (ret []byte, usedGas uint64, failed bool, err error)
|
||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool, nil)
|
||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
||||
if err != nil {
|
||||
statedb.RevertToSnapshot(snapshot)
|
||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
|
||||
|
|
@ -385,9 +394,31 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
|
||||
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
|
||||
}
|
||||
if chainConfig.IsPrague(vmContext.BlockNumber) {
|
||||
// Parse the requests from the logs
|
||||
var allLogs []*types.Log
|
||||
for _, receipt := range receipts {
|
||||
allLogs = append(allLogs, receipt.Logs...)
|
||||
}
|
||||
requests, err := core.ParseDepositLogs(allLogs, chainConfig)
|
||||
if err != nil {
|
||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
|
||||
}
|
||||
// Calculate the requests root
|
||||
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
|
||||
execRs.RequestsHash = &h
|
||||
// Get the deposits from the requests
|
||||
deposits := make(types.Deposits, 0)
|
||||
for _, req := range requests {
|
||||
if dep, ok := req.Inner().(*types.Deposit); ok {
|
||||
deposits = append(deposits, dep)
|
||||
}
|
||||
}
|
||||
execRs.DepositRequests = &deposits
|
||||
}
|
||||
// Re-create statedb instance with new root upon the updated database
|
||||
// for accessing latest states.
|
||||
statedb, err = state.New(root, statedb.Database(), nil)
|
||||
statedb, err = state.New(root, statedb.Database())
|
||||
if err != nil {
|
||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
|
||||
}
|
||||
|
|
@ -396,8 +427,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
}
|
||||
|
||||
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
|
||||
sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
||||
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
|
||||
tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
||||
sdb := state.NewDatabase(tdb, nil)
|
||||
statedb, _ := state.New(types.EmptyRootHash, sdb)
|
||||
for addr, a := range accounts {
|
||||
statedb.SetCode(addr, a.Code)
|
||||
statedb.SetNonce(addr, a.Nonce)
|
||||
|
|
@ -408,8 +440,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB
|
|||
}
|
||||
// Commit and re-open to start with a clean state.
|
||||
root, _ := statedb.Commit(0, false)
|
||||
statedb, _ = state.New(root, sdb, nil)
|
||||
|
||||
statedb, _ = state.New(root, sdb)
|
||||
return statedb
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ func runCmd(ctx *cli.Context) error {
|
|||
})
|
||||
defer triedb.Close()
|
||||
genesis := genesisConfig.MustCommit(db, triedb)
|
||||
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
||||
statedb, _ = state.New(genesis.Root(), sdb, nil)
|
||||
sdb := state.NewDatabase(triedb, nil)
|
||||
statedb, _ = state.New(genesis.Root(), sdb)
|
||||
chainConfig = genesisConfig.Config
|
||||
|
||||
if ctx.String(SenderFlag.Name) != "" {
|
||||
|
|
@ -297,7 +297,7 @@ func runCmd(ctx *cli.Context) error {
|
|||
fmt.Printf("Failed to commit changes %v\n", err)
|
||||
return err
|
||||
}
|
||||
dumpdb, err := state.New(root, sdb, nil)
|
||||
dumpdb, err := state.New(root, sdb)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to open statedb %v\n", err)
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error {
|
|||
result.Root = &root
|
||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||
if dump { // Dump any state to aid debugging
|
||||
cpy, _ := state.New(root, tstate.StateDB.Database(), nil)
|
||||
cpy, _ := state.New(root, tstate.StateDB.Database())
|
||||
dump := cpy.RawDump(nil)
|
||||
result.State = &dump
|
||||
}
|
||||
|
|
|
|||
|
|
@ -451,8 +451,6 @@ func importHistory(ctx *cli.Context) error {
|
|||
network = "mainnet"
|
||||
case ctx.Bool(utils.SepoliaFlag.Name):
|
||||
network = "sepolia"
|
||||
case ctx.Bool(utils.GoerliFlag.Name):
|
||||
network = "goerli"
|
||||
}
|
||||
} else {
|
||||
// No network flag set, try to determine network based on files
|
||||
|
|
@ -625,7 +623,7 @@ func dump(ctx *cli.Context) error {
|
|||
triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup
|
||||
defer triedb.Close()
|
||||
|
||||
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
state, err := state.New(root, state.NewDatabase(triedb, nil))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,8 +79,8 @@ var tomlSettings = toml.Config{
|
|||
},
|
||||
MissingField: func(rt reflect.Type, field string) error {
|
||||
id := fmt.Sprintf("%s.%s", rt.String(), field)
|
||||
if deprecated(id) {
|
||||
log.Warn("Config field is deprecated and won't have an effect", "name", id)
|
||||
if deprecatedConfigFields[id] {
|
||||
log.Warn(fmt.Sprintf("Config field '%s' is deprecated and won't have any effect.", id))
|
||||
return nil
|
||||
}
|
||||
var link string
|
||||
|
|
@ -91,6 +91,19 @@ var tomlSettings = toml.Config{
|
|||
},
|
||||
}
|
||||
|
||||
var deprecatedConfigFields = map[string]bool{
|
||||
"ethconfig.Config.EVMInterpreter": true,
|
||||
"ethconfig.Config.EWASMInterpreter": true,
|
||||
"ethconfig.Config.TrieCleanCacheJournal": true,
|
||||
"ethconfig.Config.TrieCleanCacheRejournal": true,
|
||||
"ethconfig.Config.LightServ": true,
|
||||
"ethconfig.Config.LightIngress": true,
|
||||
"ethconfig.Config.LightEgress": true,
|
||||
"ethconfig.Config.LightPeers": true,
|
||||
"ethconfig.Config.LightNoPrune": true,
|
||||
"ethconfig.Config.LightNoSyncServe": true,
|
||||
}
|
||||
|
||||
type ethstatsConfig struct {
|
||||
URL string `toml:",omitempty"`
|
||||
}
|
||||
|
|
@ -335,21 +348,6 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
func deprecated(field string) bool {
|
||||
switch field {
|
||||
case "ethconfig.Config.EVMInterpreter":
|
||||
return true
|
||||
case "ethconfig.Config.EWASMInterpreter":
|
||||
return true
|
||||
case "ethconfig.Config.TrieCleanCacheJournal":
|
||||
return true
|
||||
case "ethconfig.Config.TrieCleanCacheRejournal":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error {
|
||||
scryptN := keystore.StandardScryptN
|
||||
scryptP := keystore.StandardScryptP
|
||||
|
|
|
|||
|
|
@ -129,9 +129,7 @@ func remoteConsole(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
if path != "" {
|
||||
if ctx.Bool(utils.GoerliFlag.Name) {
|
||||
path = filepath.Join(path, "goerli")
|
||||
} else if ctx.Bool(utils.MumbaiFlag.Name) || ctx.Bool(utils.AmoyFlag.Name) || ctx.Bool(utils.BorMainnetFlag.Name) {
|
||||
if ctx.Bool(utils.MumbaiFlag.Name) || ctx.Bool(utils.AmoyFlag.Name) || ctx.Bool(utils.BorMainnetFlag.Name) {
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
path = filepath.Join(homeDir, "/.bor/data")
|
||||
} else if ctx.Bool(utils.SepoliaFlag.Name) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
ipcAPIs = "admin:1.0 bor: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 bor:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
||||
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||
)
|
||||
|
||||
|
|
@ -38,10 +38,10 @@ const (
|
|||
// memory and disk IO. If the args don't set --datadir, the
|
||||
// child g gets a temporary data directory.
|
||||
func runMinimalGeth(t *testing.T, args ...string) *testgeth {
|
||||
// --goerli to make the 'writing genesis to disk' faster (no accounts)
|
||||
// --holesky to make the 'writing genesis to disk' faster (no accounts)
|
||||
// --networkid=1337 to avoid cache bump
|
||||
// --syncmode=full to avoid allocating fast sync bloom
|
||||
allArgs := []string{"--goerli", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
|
||||
allArgs := []string{"--holesky", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
|
||||
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
|
||||
"--datadir.minfreedisk", "0"}
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ func TestConsoleWelcome(t *testing.T) {
|
|||
geth.SetTemplateFunc("gover", runtime.Version)
|
||||
geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
||||
geth.SetTemplateFunc("niltime", func() string {
|
||||
return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
})
|
||||
geth.SetTemplateFunc("apis", func() string { return ipcAPIs })
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
|
|||
attach.SetTemplateFunc("gover", runtime.Version)
|
||||
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
||||
attach.SetTemplateFunc("niltime", func() string {
|
||||
return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
})
|
||||
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
|
||||
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
|
||||
|
|
|
|||
|
|
@ -164,7 +164,6 @@ var (
|
|||
utils.BeaconGenesisRootFlag,
|
||||
utils.BeaconGenesisTimeFlag,
|
||||
utils.BeaconCheckpointFlag,
|
||||
utils.CollectWitnessFlag,
|
||||
}, utils.NetworkFlags, utils.DatabaseFlags)
|
||||
|
||||
rpcFlags = []cli.Flag{
|
||||
|
|
@ -299,9 +298,6 @@ func main() {
|
|||
func prepare(ctx *cli.Context) {
|
||||
// If we're running a known preset, log it for convenience.
|
||||
switch {
|
||||
case ctx.IsSet(utils.GoerliFlag.Name):
|
||||
log.Info("Starting Geth on Görli testnet...")
|
||||
|
||||
case ctx.IsSet(utils.SepoliaFlag.Name):
|
||||
log.Info("Starting Geth on Sepolia testnet...")
|
||||
|
||||
|
|
@ -339,8 +335,8 @@ func prepare(ctx *cli.Context) {
|
|||
if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
|
||||
// Make sure we're not on any supported preconfigured testnet either
|
||||
if !ctx.IsSet(utils.SepoliaFlag.Name) &&
|
||||
!ctx.IsSet(utils.GoerliFlag.Name) &&
|
||||
!ctx.IsSet(utils.MumbaiFlag.Name) &&
|
||||
!ctx.IsSet(utils.HoleskyFlag.Name) &&
|
||||
!ctx.IsSet(utils.AmoyFlag.Name) &&
|
||||
!ctx.IsSet(utils.DeveloperFlag.Name) {
|
||||
// Nope, we're really on mainnet. Bump that cache up!
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ var (
|
|||
}
|
||||
NetworkIdFlag = &cli.Uint64Flag{
|
||||
Name: "networkid",
|
||||
Usage: "Explicitly set network id (integer)(For testnets: use --goerli, --sepolia, --holesky instead)",
|
||||
Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky instead)",
|
||||
Value: ethconfig.Defaults.NetworkId,
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
|
|
@ -144,11 +144,6 @@ var (
|
|||
Usage: "Ethereum mainnet",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
GoerliFlag = &cli.BoolFlag{
|
||||
Name: "goerli",
|
||||
Usage: "Görli network: pre-configured proof-of-authority test network",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
SepoliaFlag = &cli.BoolFlag{
|
||||
Name: "sepolia",
|
||||
Usage: "Sepolia network: pre-configured proof-of-work test network",
|
||||
|
|
@ -644,11 +639,6 @@ var (
|
|||
Usage: "Disables db compaction after import",
|
||||
Category: flags.LoggingCategory,
|
||||
}
|
||||
CollectWitnessFlag = &cli.BoolFlag{
|
||||
Name: "collectwitness",
|
||||
Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.",
|
||||
Category: flags.MiscCategory,
|
||||
}
|
||||
|
||||
// MISC settings
|
||||
SyncTargetFlag = &cli.StringFlag{
|
||||
|
|
@ -851,8 +841,9 @@ var (
|
|||
DiscoveryV5Flag = &cli.BoolFlag{
|
||||
Name: "discovery.v5",
|
||||
Aliases: []string{"discv5"},
|
||||
Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
|
||||
Usage: "Enables the V5 discovery mechanism",
|
||||
Category: flags.NetworkingCategory,
|
||||
Value: true,
|
||||
}
|
||||
NetrestrictFlag = &cli.StringFlag{
|
||||
Name: "netrestrict",
|
||||
|
|
@ -1004,7 +995,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
|||
var (
|
||||
// TestnetFlags is the flag group of all built-in supported testnets.
|
||||
TestnetFlags = []cli.Flag{
|
||||
GoerliFlag,
|
||||
SepoliaFlag,
|
||||
}
|
||||
// NetworkFlags is the flag group of all built-in supported networks.
|
||||
|
|
@ -1026,10 +1016,6 @@ var (
|
|||
// then a subdirectory of the specified datadir will be used.
|
||||
func MakeDataDir(ctx *cli.Context) string {
|
||||
if path := ctx.String(DataDirFlag.Name); path != "" {
|
||||
if ctx.Bool(GoerliFlag.Name) {
|
||||
return filepath.Join(path, "goerli")
|
||||
}
|
||||
|
||||
if ctx.Bool(SepoliaFlag.Name) {
|
||||
return filepath.Join(path, "sepolia")
|
||||
}
|
||||
|
|
@ -1083,7 +1069,7 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
|
|||
//
|
||||
// 1. --bootnodes flag
|
||||
// 2. Config file
|
||||
// 3. Network preset flags (e.g. --goerli)
|
||||
// 3. Network preset flags (e.g. --holesky)
|
||||
// 4. default to mainnet nodes
|
||||
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
|
||||
urls := params.MainnetBootnodes
|
||||
|
|
@ -1096,8 +1082,6 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
|
|||
switch {
|
||||
case ctx.Bool(SepoliaFlag.Name):
|
||||
urls = params.SepoliaBootnodes
|
||||
case ctx.Bool(GoerliFlag.Name):
|
||||
urls = params.GoerliBootnodes
|
||||
}
|
||||
}
|
||||
cfg.BootstrapNodes = mustParseBootnodes(urls)
|
||||
|
|
@ -1378,8 +1362,8 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error
|
|||
|
||||
// setEtherbase retrieves the etherbase from the directly specified command line flags.
|
||||
func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||
if !ctx.IsSet(MinerEtherbaseFlag.Name) {
|
||||
return
|
||||
if ctx.IsSet(MinerEtherbaseFlag.Name) {
|
||||
log.Warn("Option --miner.etherbase is deprecated as the etherbase is set by the consensus client post-merge")
|
||||
}
|
||||
|
||||
addr := ctx.String(MinerEtherbaseFlag.Name)
|
||||
|
|
@ -1556,8 +1540,6 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) {
|
|||
cfg.DataDir = ctx.String(DataDirFlag.Name)
|
||||
case ctx.Bool(DeveloperFlag.Name):
|
||||
cfg.DataDir = "" // unless explicitly requested, use memory databases
|
||||
case ctx.Bool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
|
||||
case ctx.Bool(SepoliaFlag.Name) && cfg.DataDir == node.DefaultDataDir():
|
||||
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia")
|
||||
}
|
||||
|
|
@ -1752,7 +1734,7 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) {
|
|||
// SetEthConfig applies eth-related command line flags to the config.
|
||||
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||
// Avoid conflicting network flags
|
||||
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, GoerliFlag, SepoliaFlag, HoleskyFlag)
|
||||
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag)
|
||||
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
|
||||
|
||||
// Set configurations from CLI flags
|
||||
|
|
@ -1889,9 +1871,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||
// TODO(fjl): force-enable this in --dev mode
|
||||
cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(CollectWitnessFlag.Name) {
|
||||
cfg.EnableWitnessCollection = ctx.Bool(CollectWitnessFlag.Name)
|
||||
}
|
||||
|
||||
if ctx.IsSet(RPCGlobalGasCapFlag.Name) {
|
||||
cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name)
|
||||
|
|
@ -1937,13 +1916,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||
|
||||
cfg.Genesis = core.DefaultSepoliaGenesisBlock()
|
||||
SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash)
|
||||
case ctx.Bool(GoerliFlag.Name):
|
||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||
cfg.NetworkId = 5
|
||||
}
|
||||
|
||||
cfg.Genesis = core.DefaultGoerliGenesisBlock()
|
||||
SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash)
|
||||
case ctx.Bool(DeveloperFlag.Name):
|
||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||
cfg.NetworkId = 1337
|
||||
|
|
@ -2290,8 +2262,6 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
|
|||
genesis = core.DefaultGenesisBlock()
|
||||
case ctx.Bool(SepoliaFlag.Name):
|
||||
genesis = core.DefaultSepoliaGenesisBlock()
|
||||
case ctx.Bool(GoerliFlag.Name):
|
||||
genesis = core.DefaultGoerliGenesisBlock()
|
||||
case ctx.Bool(DeveloperFlag.Name):
|
||||
Fatalf("Developer chains are ephemeral")
|
||||
}
|
||||
|
|
@ -2367,7 +2337,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
|||
}
|
||||
vmcfg := vm.Config{
|
||||
EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
|
||||
EnableWitnessCollection: ctx.Bool(CollectWitnessFlag.Name),
|
||||
}
|
||||
if ctx.IsSet(VMTraceFlag.Name) {
|
||||
if name := ctx.String(VMTraceFlag.Name); name != "" {
|
||||
|
|
|
|||
|
|
@ -92,25 +92,21 @@ var (
|
|||
LightServeFlag = &cli.IntFlag{
|
||||
Name: "light.serve",
|
||||
Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)",
|
||||
Value: ethconfig.Defaults.LightServ,
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
LightIngressFlag = &cli.IntFlag{
|
||||
Name: "light.ingress",
|
||||
Usage: "Incoming bandwidth limit for serving light clients (deprecated)",
|
||||
Value: ethconfig.Defaults.LightIngress,
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
LightEgressFlag = &cli.IntFlag{
|
||||
Name: "light.egress",
|
||||
Usage: "Outgoing bandwidth limit for serving light clients (deprecated)",
|
||||
Value: ethconfig.Defaults.LightEgress,
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
LightMaxPeersFlag = &cli.IntFlag{
|
||||
Name: "light.maxpeers",
|
||||
Usage: "Maximum number of light clients to serve, or light servers to attach to (deprecated)",
|
||||
Value: ethconfig.Defaults.LightPeers,
|
||||
Category: flags.DeprecatedCategory,
|
||||
}
|
||||
LightNoPruneFlag = &cli.BoolFlag{
|
||||
|
|
|
|||
0
common/prque/prque.go
Executable file → Normal file
0
common/prque/prque.go
Executable file → Normal file
0
common/prque/sstack.go
Executable file → Normal file
0
common/prque/sstack.go
Executable file → Normal file
|
|
@ -389,8 +389,39 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
|||
// Assign the final state root to header.
|
||||
header.Root = state.IntermediateRoot(true)
|
||||
|
||||
// Assemble and return the final block.
|
||||
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil
|
||||
// Assemble the final block.
|
||||
block := types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
||||
|
||||
// Create the block witness and attach to block.
|
||||
// This step needs to happen as late as possible to catch all access events.
|
||||
if chain.Config().IsVerkle(header.Number) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ func TestGenesisContractChange(t *testing.T) {
|
|||
|
||||
genesis := genspec.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults))
|
||||
|
||||
statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil)
|
||||
statedb, err := state.New(genesis.Root(), state.NewDatabase(triedb.NewDatabase(db, triedb.HashDefaults), nil))
|
||||
require.NoError(t, err)
|
||||
|
||||
chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, b, vm.Config{}, nil, nil, nil)
|
||||
|
|
@ -84,7 +84,7 @@ func TestGenesisContractChange(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, statedb.Database().TrieDB().Commit(root, true))
|
||||
|
||||
statedb, err := state.New(h.Root, state.NewDatabase(db), nil)
|
||||
statedb, err := state.New(h.Root, state.NewDatabase(triedb.NewDatabase(db, triedb.HashDefaults), nil))
|
||||
require.NoError(t, err)
|
||||
|
||||
return root, statedb
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ func ApplyMessage(
|
|||
msg.Data(),
|
||||
msg.Gas(),
|
||||
uint256.NewInt(msg.Value().Uint64()),
|
||||
nil,
|
||||
)
|
||||
|
||||
success := big.NewInt(5).SetBytes(ret)
|
||||
|
|
@ -100,6 +99,11 @@ func ApplyMessage(
|
|||
log.Error("message execution failed on contract", "msgData", msg.Data)
|
||||
}
|
||||
|
||||
// If there's error committing span, log it here. It won't be reported before because the return value is empty.
|
||||
if bytes.Equal(msg.To().Bytes(), validatorContract.Bytes()) && err != nil {
|
||||
log.Error("message execution failed on contract", "err", err)
|
||||
}
|
||||
|
||||
// Update the state with pending changes
|
||||
if err != nil {
|
||||
state.Finalise(true)
|
||||
|
|
@ -120,7 +124,6 @@ func ApplyBorMessage(vmenv *vm.EVM, msg Callmsg) (*core.ExecutionResult, error)
|
|||
msg.Data(),
|
||||
msg.Gas(),
|
||||
uint256.NewInt(msg.Value().Uint64()),
|
||||
nil,
|
||||
)
|
||||
// Update the state with pending changes
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ import (
|
|||
)
|
||||
|
||||
// This test case is a repro of an annoying bug that took us forever to catch.
|
||||
// In Clique PoA networks (Görli, etc), consecutive blocks might have
|
||||
// the same state root (no block subsidy, empty block). If a node crashes, the
|
||||
// chain ends up losing the recent state and needs to regenerate it from blocks
|
||||
// already in the database. The bug was that processing the block *prior* to an
|
||||
// empty one **also completes** the empty one, ending up in a known-block error.
|
||||
// In Clique PoA networks, consecutive blocks might have the same state root (no
|
||||
// block subsidy, empty block). If a node crashes, the chain ends up losing the
|
||||
// recent state and needs to regenerate it from blocks already in the database.
|
||||
// The bug was that processing the block *prior* to an empty one **also
|
||||
// completes** the empty one, ending up in a known-block error.
|
||||
func TestReimportMirroredState(t *testing.T) {
|
||||
// Initialize a Clique chain with a single signer
|
||||
var (
|
||||
|
|
@ -90,7 +90,6 @@ func TestReimportMirroredState(t *testing.T) {
|
|||
}
|
||||
// Insert the first two blocks and make sure the chain is valid
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
|
||||
chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil, nil)
|
||||
defer chain.Stop()
|
||||
|
||||
|
|
|
|||
|
|
@ -331,7 +331,6 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
|||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||
}
|
||||
|
||||
chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||
if err != nil {
|
||||
b.Fatalf("error creating chain: %v", err)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
|
|
@ -127,15 +125,17 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||
|
||||
// ValidateState validates the various changes that happen after a state transition,
|
||||
// such as amount of used gas, the receipt roots and the state root itself.
|
||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error {
|
||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
|
||||
if res == nil {
|
||||
return fmt.Errorf("nil ProcessResult value")
|
||||
}
|
||||
header := block.Header()
|
||||
|
||||
if block.GasUsed() != usedGas {
|
||||
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
|
||||
if block.GasUsed() != res.GasUsed {
|
||||
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), res.GasUsed)
|
||||
}
|
||||
// Validate the received block's bloom with the one derived from the generated receipts.
|
||||
// For valid blocks this should always validate to true.
|
||||
rbloom := types.CreateBloom(receipts)
|
||||
rbloom := types.CreateBloom(res.Receipts)
|
||||
if rbloom != header.Bloom {
|
||||
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
||||
}
|
||||
|
|
@ -145,10 +145,17 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||
return nil
|
||||
}
|
||||
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
|
||||
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
||||
receiptSha := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
|
||||
if receiptSha != header.ReceiptHash {
|
||||
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
|
||||
}
|
||||
// Validate the parsed requests match the expected header value.
|
||||
if header.RequestsHash != nil {
|
||||
depositSha := types.DeriveSha(res.Requests, trie.NewStackTrie(nil))
|
||||
if depositSha != *header.RequestsHash {
|
||||
return fmt.Errorf("invalid deposit root hash (remote: %x local: %x)", *header.RequestsHash, depositSha)
|
||||
}
|
||||
}
|
||||
// Validate the state root against the received state root and throw
|
||||
// an error if they don't match.
|
||||
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
||||
|
|
@ -158,28 +165,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||
return nil
|
||||
}
|
||||
|
||||
// ValidateWitness cross validates a block execution with stateless remote clients.
|
||||
//
|
||||
// Normally we'd distribute the block witness to remote cross validators, wait
|
||||
// for them to respond and then merge the results. For now, however, it's only
|
||||
// Geth, so do an internal stateless run.
|
||||
func (v *BlockValidator) ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error {
|
||||
// Run the cross client stateless execution
|
||||
// TODO(karalabe): Self-stateless for now, swap with other clients
|
||||
crossReceiptRoot, crossStateRoot, err := ExecuteStateless(v.config, witness)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stateless execution failed: %v", err)
|
||||
}
|
||||
// Stateless cross execution suceeeded, validate the withheld computed fields
|
||||
if crossReceiptRoot != receiptRoot {
|
||||
return fmt.Errorf("cross validator receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, receiptRoot)
|
||||
}
|
||||
if crossStateRoot != stateRoot {
|
||||
return fmt.Errorf("cross validator state root mismatch (cross: %x local: %x)", crossStateRoot, stateRoot)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CalcGasLimit computes the gas limit of the next block after parent. It aims
|
||||
// to keep the baseline gas close to the provided target, and increase it towards
|
||||
// the target if the baseline gas is lower.
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
|
|||
t.Fatalf("post-block %d: unexpected result returned: %v", i, result)
|
||||
case <-time.After(25 * time.Millisecond):
|
||||
}
|
||||
chain.InsertBlockWithoutSetHead(postBlocks[i])
|
||||
chain.InsertBlockWithoutSetHead(postBlocks[i], false)
|
||||
}
|
||||
|
||||
// Verify the blocks with pre-merge blocks and post-merge blocks
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package core
|
|||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -42,6 +41,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
|
|
@ -78,17 +78,21 @@ var (
|
|||
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
||||
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
||||
|
||||
accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil) //nolint:golint,unused
|
||||
storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil) //nolint:golint,unused
|
||||
|
||||
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
|
||||
triedbCommitTimer = metrics.NewRegisteredResettingTimer("chain/triedb/commits", nil)
|
||||
snapshotAccountReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/account/reads", nil)
|
||||
snapshotStorageReadTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/storage/reads", nil)
|
||||
snapshotCommitTimer = metrics.NewRegisteredResettingTimer("chain/snapshot/commits", nil)
|
||||
|
||||
borConsensusTime = metrics.NewRegisteredTimer("chain/bor/consensus", nil)
|
||||
|
||||
blockImportTimer = metrics.NewRegisteredMeter("chain/imports", nil)
|
||||
triedbCommitTimer = metrics.NewRegisteredTimer("chain/triedb/commits", nil)
|
||||
|
||||
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
|
||||
blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil)
|
||||
blockCrossValidationTimer = metrics.NewRegisteredResettingTimer("chain/crossvalidation", nil) //nolint:golint,unused
|
||||
blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil)
|
||||
blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil)
|
||||
blockExecutionParallelCounter = metrics.NewRegisteredCounter("chain/execution/parallel", nil)
|
||||
|
|
@ -237,7 +241,7 @@ type BlockChain struct {
|
|||
lastWrite uint64 // Last block when the state was flushed
|
||||
flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state
|
||||
triedb *triedb.Database // The database handler for maintaining trie nodes.
|
||||
stateCache state.Database // State database to reuse between imports (contains state cache)
|
||||
statedb *state.CachingDB // State database to reuse between imports (contains state cache)
|
||||
txIndexer *txIndexer // Transaction indexer, might be nil if not enabled
|
||||
|
||||
hc *HeaderChain
|
||||
|
|
@ -356,7 +360,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||
|
||||
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
||||
bc.forker = NewForkChoice(bc, shouldPreserve, checker)
|
||||
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
||||
bc.statedb = state.NewDatabase(bc.triedb, nil)
|
||||
bc.validator = NewBlockValidator(chainConfig, bc)
|
||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
||||
bc.processor = NewStateProcessor(chainConfig, bc, bc.hc)
|
||||
|
|
@ -524,11 +528,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||
AsyncBuild: !bc.cacheConfig.SnapshotWait,
|
||||
}
|
||||
bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root)
|
||||
}
|
||||
|
||||
// Start future block processor.
|
||||
// bc.wg.Add(1)
|
||||
// go bc.updateFutureBlocks()
|
||||
// Re-initialize the state database with snapshot
|
||||
bc.statedb = state.NewDatabase(bc.triedb, bc.snaps)
|
||||
}
|
||||
|
||||
// Rewind the chain in case of an incompatible config upgrade.
|
||||
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
||||
|
|
@ -575,8 +578,6 @@ func NewParallelBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis
|
|||
|
||||
func (bc *BlockChain) ProcessBlock(block *types.Block, parent *types.Header) (_ types.Receipts, _ []*types.Log, _ uint64, _ *state.StateDB, vtime time.Duration, blockEndErr error) {
|
||||
// Process the block using processor and parallelProcessor at the same time, take the one which finishes first, cancel the other, and return the result
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
if bc.logger != nil && bc.logger.OnBlockStart != nil {
|
||||
td := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
|
||||
|
|
@ -609,7 +610,7 @@ func (bc *BlockChain) ProcessBlock(block *types.Block, parent *types.Header) (_
|
|||
processorCount := 0
|
||||
|
||||
if bc.parallelProcessor != nil {
|
||||
parallelStatedb, err := state.New(parent.Root, bc.stateCache, bc.snaps)
|
||||
parallelStatedb, err := state.New(parent.Root, bc.statedb)
|
||||
if err != nil {
|
||||
return nil, nil, 0, nil, 0, err
|
||||
}
|
||||
|
|
@ -620,19 +621,22 @@ func (bc *BlockChain) ProcessBlock(block *types.Block, parent *types.Header) (_
|
|||
go func() {
|
||||
parallelStatedb.StartPrefetcher("chain", nil)
|
||||
pstart := time.Now()
|
||||
receipts, logs, usedGas, err := bc.parallelProcessor.Process(block, parallelStatedb, bc.vmConfig, ctx)
|
||||
res, err := bc.parallelProcessor.Process(block, parallelStatedb, bc.vmConfig)
|
||||
blockExecutionParallelTimer.UpdateSince(pstart)
|
||||
if err == nil {
|
||||
vstart := time.Now()
|
||||
err = bc.validator.ValidateState(block, parallelStatedb, receipts, usedGas, false)
|
||||
err = bc.validator.ValidateState(block, parallelStatedb, res, false)
|
||||
vtime = time.Since(vstart)
|
||||
}
|
||||
resultChan <- Result{receipts, logs, usedGas, err, parallelStatedb, blockExecutionParallelCounter, true}
|
||||
if res == nil {
|
||||
res = &ProcessResult{}
|
||||
}
|
||||
resultChan <- Result{res.Receipts, res.Logs, res.GasUsed, err, parallelStatedb, blockExecutionParallelCounter, true}
|
||||
}()
|
||||
}
|
||||
|
||||
if bc.processor != nil {
|
||||
statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps)
|
||||
statedb, err := state.New(parent.Root, bc.statedb)
|
||||
if err != nil {
|
||||
return nil, nil, 0, nil, 0, err
|
||||
}
|
||||
|
|
@ -643,14 +647,17 @@ func (bc *BlockChain) ProcessBlock(block *types.Block, parent *types.Header) (_
|
|||
go func() {
|
||||
statedb.StartPrefetcher("chain", nil)
|
||||
pstart := time.Now()
|
||||
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig, ctx)
|
||||
res, err := bc.processor.Process(block, statedb, bc.vmConfig)
|
||||
blockExecutionSerialTimer.UpdateSince(pstart)
|
||||
if err == nil {
|
||||
vstart := time.Now()
|
||||
err = bc.validator.ValidateState(block, statedb, receipts, usedGas, false)
|
||||
err = bc.validator.ValidateState(block, statedb, res, false)
|
||||
vtime = time.Since(vstart)
|
||||
}
|
||||
resultChan <- Result{receipts, logs, usedGas, err, statedb, blockExecutionSerialCounter, false}
|
||||
if res == nil {
|
||||
res = &ProcessResult{}
|
||||
}
|
||||
resultChan <- Result{res.Receipts, res.Logs, res.GasUsed, err, statedb, blockExecutionSerialCounter, false}
|
||||
}()
|
||||
}
|
||||
|
||||
|
|
@ -1922,18 +1929,18 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
|||
|
||||
// WriteBlockAndSetHead writes the given block and all associated state to the database,
|
||||
// and applies the block as the new chain head.
|
||||
func (bc *BlockChain) WriteBlockAndSetHead(ctx context.Context, block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
|
||||
func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
|
||||
if !bc.chainmu.TryLock() {
|
||||
return NonStatTy, errChainStopped
|
||||
}
|
||||
defer bc.chainmu.Unlock()
|
||||
|
||||
return bc.writeBlockAndSetHead(ctx, block, receipts, logs, state, emitHeadEvent)
|
||||
return bc.writeBlockAndSetHead(block, receipts, logs, state, emitHeadEvent)
|
||||
}
|
||||
|
||||
// writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
|
||||
// This function expects the chain mutex to be held.
|
||||
func (bc *BlockChain) writeBlockAndSetHead(ctx context.Context, block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
|
||||
func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
|
||||
stateSyncLogs, err := bc.writeBlockWithState(block, receipts, logs, state)
|
||||
if err != nil {
|
||||
return NonStatTy, err
|
||||
|
|
@ -2056,7 +2063,9 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
|||
return 0, errChainStopped
|
||||
}
|
||||
defer bc.chainmu.Unlock()
|
||||
return bc.insertChain(chain, true)
|
||||
|
||||
_, n, err := bc.insertChain(chain, true, false) // No witness collection for mass inserts (would get super large)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// insertChain is the internal implementation of InsertChain, which assumes that
|
||||
|
|
@ -2067,10 +2076,10 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
|||
// racey behaviour. If a sidechain import is in progress, and the historic state
|
||||
// is imported, but then new canon-head is added before the actual sidechain
|
||||
// completes, then the historic state could be pruned again
|
||||
func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) {
|
||||
func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness bool) (*stateless.Witness, int, error) {
|
||||
// If the chain is terminating, don't even bother starting up.
|
||||
if bc.insertStopped() {
|
||||
return 0, nil
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
|
||||
|
|
@ -2106,13 +2115,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// Check the validity of incoming chain
|
||||
isValid, err1 := bc.forker.ValidateReorg(bc.CurrentBlock(), headers)
|
||||
if err1 != nil {
|
||||
return it.index, err1
|
||||
return nil, it.index, err1
|
||||
}
|
||||
|
||||
if !isValid {
|
||||
// The chain to be imported is invalid as the blocks doesn't match with
|
||||
// the whitelisted block number.
|
||||
return it.index, whitelist.ErrMismatch
|
||||
return nil, it.index, whitelist.ErrMismatch
|
||||
}
|
||||
|
||||
// Left-trim all the known blocks that don't need to build snapshot
|
||||
|
|
@ -2130,7 +2139,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
for block != nil && bc.skipBlock(err, it) {
|
||||
reorg, err = bc.forker.ReorgNeeded(current, block.Header())
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
if reorg {
|
||||
|
|
@ -2162,7 +2171,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
log.Debug("Writing previously known block", "number", block.Number(), "hash", block.Hash())
|
||||
|
||||
if err := bc.writeKnownBlock(block); err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
lastCanon = block
|
||||
|
|
@ -2178,13 +2187,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
if setHead {
|
||||
// First block is pruned, insert as sidechain and reorg only if TD grows enough
|
||||
log.Debug("Pruned ancestor, inserting as sidechain", "number", block.Number(), "hash", block.Hash())
|
||||
return bc.insertSideChain(block, it)
|
||||
return bc.insertSideChain(block, it, makeWitness)
|
||||
} else {
|
||||
// We're post-merge and the parent is pruned, try to recover the parent state
|
||||
log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash())
|
||||
_, err := bc.recoverAncestors(block)
|
||||
|
||||
return it.index, err
|
||||
_, err := bc.recoverAncestors(block, makeWitness)
|
||||
return nil, it.index, err
|
||||
}
|
||||
// First block is future, shove it (and all children) to the future queue (unknown ancestor)
|
||||
case errors.Is(err, consensus.ErrFutureBlock) || (errors.Is(err, consensus.ErrUnknownAncestor) && bc.futureBlocks.Contains(it.first().ParentHash())):
|
||||
|
|
@ -2192,7 +2200,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
log.Debug("Future block, postponing import", "number", block.Number(), "hash", block.Hash())
|
||||
|
||||
if err := bc.addFutureBlock(block); err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
block, err = it.next()
|
||||
|
|
@ -2202,7 +2210,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
stats.ignored += it.remaining()
|
||||
|
||||
// If there are any still remaining, mark as ignored
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
|
||||
// Some other error(except ErrKnownBlock) occurred, abort.
|
||||
// ErrKnownBlock is allowed here since some known blocks
|
||||
|
|
@ -2211,8 +2219,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
stats.ignored += len(it.chain)
|
||||
|
||||
bc.reportBlock(block, nil, err)
|
||||
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
// No validation errors for the first block (or chain prefix skipped)
|
||||
var activeState *state.StateDB
|
||||
|
|
@ -2226,6 +2233,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
}
|
||||
}()
|
||||
|
||||
// Track the singleton witness from this chain insertion (if any)
|
||||
var witness *stateless.Witness
|
||||
|
||||
// accumulator for canonical blocks
|
||||
var canonAccum []*types.Block
|
||||
|
||||
|
|
@ -2254,7 +2264,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// If the header is a banned one, straight out abort
|
||||
if BadHashes[block.Hash()] {
|
||||
bc.reportBlock(block, nil, ErrBannedHash)
|
||||
return it.index, ErrBannedHash
|
||||
return nil, it.index, ErrBannedHash
|
||||
}
|
||||
|
||||
// If the block is known (in the middle of the chain), it's a special case for
|
||||
|
|
@ -2289,7 +2299,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
}
|
||||
|
||||
if err := bc.writeKnownBlock(block); err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
stats.processed++
|
||||
|
|
@ -2301,14 +2311,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
Safe: bc.CurrentSafeBlock(),
|
||||
})
|
||||
}
|
||||
|
||||
// We can assume that logs are empty here, since the only way for consecutive
|
||||
// Clique blocks to have the same state is if there are no transactions.
|
||||
lastCanon = block
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Retrieve the parent block and it's state to execute on top
|
||||
start := time.Now()
|
||||
|
||||
|
|
@ -2316,6 +2324,28 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
if parent == nil {
|
||||
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||
}
|
||||
statedb, err := state.New(parent.Root, bc.statedb)
|
||||
if err != nil {
|
||||
return nil, it.index, err
|
||||
}
|
||||
statedb.SetLogger(bc.logger)
|
||||
|
||||
// If we are past Byzantium, enable prefetching to pull in trie node paths
|
||||
// while processing transactions. Before Byzantium the prefetcher is mostly
|
||||
// useless due to the intermediate root hashing after each transaction.
|
||||
if bc.chainConfig.IsByzantium(block.Number()) {
|
||||
// Generate witnesses either if we're self-testing, or if it's the
|
||||
// only block being inserted. A bit crude, but witnesses are huge,
|
||||
// so we refuse to make an entire chain of them.
|
||||
if bc.vmConfig.StatelessSelfValidation || (makeWitness && len(chain) == 1) {
|
||||
witness, err = stateless.NewWitness(block.Header(), bc)
|
||||
if err != nil {
|
||||
return nil, it.index, err
|
||||
}
|
||||
}
|
||||
statedb.StartPrefetcher("chain", witness)
|
||||
}
|
||||
activeState = statedb
|
||||
|
||||
// If we have a followup block, run that against the current state to pre-cache
|
||||
// transactions and probabilistically some of the account/storage trie nodes.
|
||||
|
|
@ -2323,7 +2353,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
|
||||
if !bc.cacheConfig.TrieCleanNoPrefetch {
|
||||
if followup, err := it.peek(); followup != nil && err == nil {
|
||||
throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps)
|
||||
throwaway, _ := state.New(parent.Root, bc.statedb)
|
||||
|
||||
go func(start time.Time, followup *types.Block, throwaway *state.StateDB) {
|
||||
// Disable tracing for prefetcher executions.
|
||||
|
|
@ -2346,10 +2376,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
activeState = statedb
|
||||
|
||||
if err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
bc.reportBlock(block, &ProcessResult{Receipts: receipts}, err)
|
||||
followupInterrupt.Store(true)
|
||||
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
// BOR state sync feed related changes
|
||||
|
|
@ -2391,23 +2421,24 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// so that it's considered as a `past` chain and the validation doesn't get bypassed.
|
||||
isValid, err = bc.forker.ValidateReorg(block.Header(), []*types.Header{block.Header()})
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
if !isValid {
|
||||
return it.index, whitelist.ErrMismatch
|
||||
return nil, it.index, whitelist.ErrMismatch
|
||||
}
|
||||
|
||||
if !setHead {
|
||||
// Don't set the head, only insert the block
|
||||
_, err = bc.writeBlockWithState(block, receipts, logs, statedb)
|
||||
} else {
|
||||
status, err = bc.writeBlockAndSetHead(context.Background(), block, receipts, logs, statedb, false)
|
||||
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
|
||||
}
|
||||
|
||||
followupInterrupt.Store(true)
|
||||
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
// Update the metrics touched during block commit
|
||||
|
|
@ -2434,7 +2465,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// After merge we expect few side chains. Simply count
|
||||
// all blocks the CL gives us for GC processing time
|
||||
bc.gcproc += proctime
|
||||
return it.index, nil // Direct block insertion of a single block
|
||||
return witness, it.index, nil // Direct block insertion of a single block
|
||||
}
|
||||
|
||||
// BOR
|
||||
|
|
@ -2480,14 +2511,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// Any blocks remaining here? The only ones we care about are the future ones
|
||||
if block != nil && errors.Is(err, consensus.ErrFutureBlock) {
|
||||
if err := bc.addFutureBlock(block); err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
block, err = it.next()
|
||||
|
||||
for ; block != nil && errors.Is(err, consensus.ErrUnknownAncestor); block, err = it.next() {
|
||||
if err := bc.addFutureBlock(block); err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
stats.queued++
|
||||
|
|
@ -2495,7 +2526,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
}
|
||||
|
||||
stats.ignored += it.remaining()
|
||||
return it.index, err
|
||||
return witness, it.index, err
|
||||
}
|
||||
|
||||
// blockProcessingResult is a summary of block processing
|
||||
|
|
@ -2528,42 +2559,68 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
|
||||
// Process block using the parent state as reference point
|
||||
pstart := time.Now()
|
||||
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig, context.Background())
|
||||
res, err := bc.processor.Process(block, statedb, bc.vmConfig)
|
||||
if err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
bc.reportBlock(block, res, err)
|
||||
return nil, err
|
||||
}
|
||||
ptime := time.Since(pstart)
|
||||
|
||||
vstart := time.Now()
|
||||
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
if err := bc.validator.ValidateState(block, statedb, res, false); err != nil {
|
||||
bc.reportBlock(block, res, err)
|
||||
return nil, err
|
||||
}
|
||||
vtime := time.Since(vstart)
|
||||
|
||||
if witness := statedb.Witness(); witness != nil {
|
||||
if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
return nil, fmt.Errorf("cross verification failed: %v", err)
|
||||
// If witnesses was generated and stateless self-validation requested, do
|
||||
// that now. Self validation should *never* run in production, it's more of
|
||||
// a tight integration to enable running *all* consensus tests through the
|
||||
// witness builder/runner, which would otherwise be impossible due to the
|
||||
// various invalid chain states/behaviors being contained in those tests.
|
||||
xvstart := time.Now()
|
||||
if witness := statedb.Witness(); witness != nil && bc.vmConfig.StatelessSelfValidation {
|
||||
log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash())
|
||||
|
||||
// Remove critical computed fields from the block to force true recalculation
|
||||
context := block.Header()
|
||||
context.Root = common.Hash{}
|
||||
context.ReceiptHash = common.Hash{}
|
||||
|
||||
task := types.NewBlockWithHeader(context).WithBody(*block.Body())
|
||||
|
||||
// Run the stateless self-cross-validation
|
||||
crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, task, witness)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stateless self-validation failed: %v", err)
|
||||
}
|
||||
if crossStateRoot != block.Root() {
|
||||
return nil, fmt.Errorf("stateless self-validation root mismatch (cross: %x local: %x)", crossStateRoot, block.Root())
|
||||
}
|
||||
if crossReceiptRoot != block.ReceiptHash() {
|
||||
return nil, fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, block.ReceiptHash())
|
||||
}
|
||||
}
|
||||
proctime := time.Since(start) // processing + validation
|
||||
xvtime := time.Since(xvstart)
|
||||
proctime := time.Since(start) // processing + validation + cross validation
|
||||
|
||||
// Update the metrics touched during block processing and validation
|
||||
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
||||
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
|
||||
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
|
||||
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
|
||||
if statedb.AccountLoaded != 0 {
|
||||
accountReadSingleTimer.Update(statedb.AccountReads / time.Duration(statedb.AccountLoaded))
|
||||
}
|
||||
if statedb.StorageLoaded != 0 {
|
||||
storageReadSingleTimer.Update(statedb.StorageReads / time.Duration(statedb.StorageLoaded))
|
||||
}
|
||||
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
|
||||
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
|
||||
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
||||
triehash := statedb.AccountHashes // The time spent on tries hashing
|
||||
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
|
||||
trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
|
||||
trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
|
||||
blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing
|
||||
blockExecutionTimer.Update(ptime - (statedb.AccountReads + statedb.StorageReads)) // The time spent on EVM processing
|
||||
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
|
||||
blockCrossValidationTimer.Update(xvtime) // The time spent on stateless cross validation
|
||||
|
||||
// Write the block to the chain and get the status.
|
||||
var (
|
||||
|
|
@ -2572,9 +2629,9 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
)
|
||||
if !setHead {
|
||||
// Don't set the head, only insert the block
|
||||
_, err = bc.writeBlockWithState(block, receipts, logs, statedb)
|
||||
_, err = bc.writeBlockWithState(block, res.Receipts, res.Logs, statedb)
|
||||
} else {
|
||||
status, err = bc.writeBlockAndSetHead(context.Background(), block, receipts, logs, statedb, false)
|
||||
status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -2588,7 +2645,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
||||
blockInsertTimer.UpdateSince(start)
|
||||
|
||||
return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil
|
||||
return &blockProcessingResult{usedGas: res.GasUsed, procTime: proctime, status: status}, nil
|
||||
}
|
||||
|
||||
// insertSideChain is called when an import batch hits upon a pruned ancestor
|
||||
|
|
@ -2598,7 +2655,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
// The method writes all (header-and-body-valid) blocks to disk, then tries to
|
||||
// switch over to the new chain if the TD exceeded the current chain.
|
||||
// insertSideChain is only used pre-merge.
|
||||
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, error) {
|
||||
func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, makeWitness bool) (*stateless.Witness, int, error) {
|
||||
var (
|
||||
externTd *big.Int
|
||||
lastBlock = block
|
||||
|
|
@ -2637,7 +2694,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
// If someone legitimately side-mines blocks, they would still be imported as usual. However,
|
||||
// we cannot risk writing unverified blocks to disk when they obviously target the pruning
|
||||
// mechanism.
|
||||
return it.index, errors.New("sidechain ghost-state attack")
|
||||
return nil, it.index, errors.New("sidechain ghost-state attack")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2651,7 +2708,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
start := time.Now()
|
||||
|
||||
if err := bc.writeBlockWithoutState(block, externTd); err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(),
|
||||
|
|
@ -2670,19 +2727,19 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
// blocks to regenerate the required state
|
||||
reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header())
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
isValid, err := bc.forker.ValidateReorg(current, headers)
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
if !reorg || !isValid {
|
||||
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
|
||||
return nil, it.index, err
|
||||
}
|
||||
// Gather all the sidechain hashes (full blocks may be memory heavy)
|
||||
var (
|
||||
|
|
@ -2694,7 +2751,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
for parent != nil && !bc.HasState(parent.Root) {
|
||||
if bc.stateRecoverable(parent.Root) {
|
||||
if err := bc.triedb.Recover(parent.Root); err != nil {
|
||||
return 0, err
|
||||
return nil, 0, err
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
@ -2705,7 +2762,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
}
|
||||
|
||||
if parent == nil {
|
||||
return it.index, errors.New("missing parent")
|
||||
return nil, it.index, errors.New("missing parent")
|
||||
}
|
||||
// Import all the pruned blocks to make the state available
|
||||
var (
|
||||
|
|
@ -2725,8 +2782,8 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
// memory here.
|
||||
if len(blocks) >= 2048 || memory > 64*1024*1024 {
|
||||
log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64())
|
||||
if _, err := bc.insertChain(blocks, true); err != nil {
|
||||
return 0, err
|
||||
if _, _, err := bc.insertChain(blocks, true, false); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
blocks, memory = blocks[:0], 0
|
||||
|
|
@ -2734,24 +2791,23 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||
// If the chain is terminating, stop processing blocks
|
||||
if bc.insertStopped() {
|
||||
log.Debug("Abort during blocks processing")
|
||||
return 0, nil
|
||||
return nil, 0, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(blocks) > 0 {
|
||||
log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64())
|
||||
return bc.insertChain(blocks, true)
|
||||
return bc.insertChain(blocks, true, makeWitness)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
// recoverAncestors finds the closest ancestor with available state and re-execute
|
||||
// all the ancestor blocks since that.
|
||||
// recoverAncestors is only used post-merge.
|
||||
// We return the hash of the latest block that we could correctly validate.
|
||||
func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) {
|
||||
func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (common.Hash, error) {
|
||||
// Gather all the sidechain hashes (full blocks may be memory heavy)
|
||||
var (
|
||||
hashes []common.Hash
|
||||
|
|
@ -2794,7 +2850,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error)
|
|||
} else {
|
||||
b = bc.GetBlock(hashes[i], numbers[i])
|
||||
}
|
||||
if _, err := bc.insertChain(types.Blocks{b}, false); err != nil {
|
||||
if _, _, err := bc.insertChain(types.Blocks{b}, false, makeWitness && i == 0); err != nil {
|
||||
return b.ParentHash(), err
|
||||
}
|
||||
}
|
||||
|
|
@ -3115,14 +3171,14 @@ func ExportN(w io.Writer, blocks []*types.Block) error {
|
|||
// The key difference between the InsertChain is it won't do the canonical chain
|
||||
// updating. It relies on the additional SetCanonical call to finalize the entire
|
||||
// procedure.
|
||||
func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block) error {
|
||||
func (bc *BlockChain) InsertBlockWithoutSetHead(block *types.Block, makeWitness bool) (*stateless.Witness, error) {
|
||||
if !bc.chainmu.TryLock() {
|
||||
return errChainStopped
|
||||
return nil, errChainStopped
|
||||
}
|
||||
defer bc.chainmu.Unlock()
|
||||
|
||||
_, err := bc.insertChain(types.Blocks{block}, false)
|
||||
return err
|
||||
witness, _, err := bc.insertChain(types.Blocks{block}, false, makeWitness)
|
||||
return witness, err
|
||||
}
|
||||
|
||||
// SetCanonical rewinds the chain to set the new head block as the specified
|
||||
|
|
@ -3136,7 +3192,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
|
|||
|
||||
// Re-execute the reorged chain in case the head state is missing.
|
||||
if !bc.HasState(head.Root()) {
|
||||
if latestValidHash, err := bc.recoverAncestors(head); err != nil {
|
||||
if latestValidHash, err := bc.recoverAncestors(head, false); err != nil {
|
||||
return latestValidHash, err
|
||||
}
|
||||
|
||||
|
|
@ -3223,7 +3279,11 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool {
|
|||
}
|
||||
|
||||
// reportBlock logs a bad block error.
|
||||
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
|
||||
func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err error) {
|
||||
var receipts types.Receipts
|
||||
if res != nil {
|
||||
receipts = res.Receipts
|
||||
}
|
||||
rawdb.WriteBadBlock(bc.db, block)
|
||||
log.Error(summarizeBadBlock(block, receipts, bc.Config(), err))
|
||||
}
|
||||
|
|
@ -3274,7 +3334,6 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header) (int, error) {
|
|||
}
|
||||
defer bc.chainmu.Unlock()
|
||||
_, err := bc.hc.InsertHeaderChain(chain, start, bc.forker)
|
||||
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
|||
|
||||
// HasState checks if state trie is fully present in the database or not.
|
||||
func (bc *BlockChain) HasState(hash common.Hash) bool {
|
||||
_, err := bc.stateCache.OpenTrie(hash)
|
||||
_, err := bc.statedb.OpenTrie(hash)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
|
|
@ -377,12 +377,9 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool {
|
|||
// If the code doesn't exist in the in-memory cache, check the storage with
|
||||
// new code scheme.
|
||||
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
|
||||
type codeReader interface {
|
||||
ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error)
|
||||
}
|
||||
// TODO(rjl493456442) The associated account address is also required
|
||||
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
|
||||
return bc.stateCache.(codeReader).ContractCodeWithPrefix(common.Address{}, hash)
|
||||
return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)
|
||||
}
|
||||
|
||||
// State returns a new mutable state based on the current HEAD block.
|
||||
|
|
@ -392,7 +389,7 @@ func (bc *BlockChain) State() (*state.StateDB, error) {
|
|||
|
||||
// StateAt returns a new mutable state based on a particular point in time.
|
||||
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
|
||||
return state.New(root, bc.stateCache, bc.snaps)
|
||||
return state.New(root, bc.statedb)
|
||||
}
|
||||
|
||||
// Config retrieves the chain's fork configuration.
|
||||
|
|
@ -418,7 +415,7 @@ func (bc *BlockChain) Processor() Processor {
|
|||
|
||||
// StateCache returns the caching database underpinning the blockchain instance.
|
||||
func (bc *BlockChain) StateCache() state.Database {
|
||||
return bc.stateCache
|
||||
return bc.statedb
|
||||
}
|
||||
|
||||
// GasLimit returns the gas limit of the current HEAD block.
|
||||
|
|
|
|||
|
|
@ -1797,8 +1797,8 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
|
||||
func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// fmt.Println(tt.dump(true))
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(tt.dump(false))
|
||||
|
||||
// Create a temporary persistent database
|
||||
datadir := t.TempDir()
|
||||
|
|
@ -1952,7 +1952,7 @@ func TestIssue23496(t *testing.T) {
|
|||
|
||||
func testIssue23496(t *testing.T, scheme string) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
|
||||
// Create a temporary persistent database
|
||||
datadir := t.TempDir()
|
||||
|
|
|
|||
|
|
@ -1961,7 +1961,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||
|
||||
func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(tt.dump(false))
|
||||
|
||||
// Create a temporary persistent database
|
||||
|
|
@ -2042,7 +2042,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
|
|||
dbconfig.HashDB = hashdb.Defaults
|
||||
}
|
||||
chain.triedb = triedb.NewDatabase(chain.db, dbconfig)
|
||||
chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb)
|
||||
chain.statedb = state.NewDatabase(chain.triedb, chain.snaps)
|
||||
|
||||
// Force run a freeze cycle
|
||||
type freezer interface {
|
||||
|
|
|
|||
|
|
@ -226,8 +226,8 @@ type snapshotTest struct {
|
|||
|
||||
func (snaptest *snapshotTest) test(t *testing.T) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// fmt.Println(tt.dump())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Restart the chain normally
|
||||
|
|
@ -249,8 +249,8 @@ type crashSnapshotTest struct {
|
|||
|
||||
func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// fmt.Println(tt.dump())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Pull the plug on the database, simulating a hard crash
|
||||
|
|
@ -303,8 +303,8 @@ type gappedSnapshotTest struct {
|
|||
|
||||
func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// fmt.Println(tt.dump())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Insert blocks without enabling snapshot if gapping is required.
|
||||
|
|
@ -347,8 +347,8 @@ type setHeadSnapshotTest struct {
|
|||
|
||||
func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// fmt.Println(tt.dump())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Rewind the chain if setHead operation is required.
|
||||
|
|
@ -376,8 +376,8 @@ type wipeCrashSnapshotTest struct {
|
|||
|
||||
func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||
// It's hard to follow the test case, visualize the input
|
||||
// log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// fmt.Println(tt.dump())
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
// fmt.Println(snaptest.dump())
|
||||
chain, blocks := snaptest.prepare(t)
|
||||
|
||||
// Firstly, stop the chain properly, with all snapshot journal
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -170,15 +170,18 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
|||
|
||||
return err
|
||||
}
|
||||
|
||||
receipts, _, usedGas, statedb, _, err := blockchain.ProcessBlock(block, blockchain.GetBlockByHash(block.ParentHash()).Header())
|
||||
|
||||
statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.statedb)
|
||||
if err != nil {
|
||||
blockchain.reportBlock(block, receipts, err)
|
||||
return err
|
||||
}
|
||||
if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
||||
blockchain.reportBlock(block, receipts, err)
|
||||
res, err := blockchain.processor.Process(block, statedb, vm.Config{})
|
||||
if err != nil {
|
||||
blockchain.reportBlock(block, res, err)
|
||||
return err
|
||||
}
|
||||
err = blockchain.validator.ValidateState(block, statedb, res, false)
|
||||
if err != nil {
|
||||
blockchain.reportBlock(block, res, err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -220,8 +223,8 @@ func testParallelBlockChainImport(t *testing.T, scheme string) {
|
|||
type AlwaysFailParallelStateProcessor struct {
|
||||
}
|
||||
|
||||
func (p *AlwaysFailParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (types.Receipts, []*types.Log, uint64, error) {
|
||||
return nil, nil, 0, errors.New("always fail")
|
||||
func (p *AlwaysFailParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
|
||||
return nil, errors.New("always fail")
|
||||
}
|
||||
|
||||
type SlowSerialStateProcessor struct {
|
||||
|
|
@ -232,9 +235,9 @@ func NewSlowSerialStateProcessor(s Processor) *SlowSerialStateProcessor {
|
|||
return &SlowSerialStateProcessor{s: s}
|
||||
}
|
||||
|
||||
func (p *SlowSerialStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (types.Receipts, []*types.Log, uint64, error) {
|
||||
func (p *SlowSerialStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return p.s.Process(block, statedb, cfg, interruptCtx)
|
||||
return p.s.Process(block, statedb, cfg)
|
||||
}
|
||||
|
||||
func TestSuccessfulBlockImportParallelFailed(t *testing.T) {
|
||||
|
|
@ -1437,7 +1440,6 @@ func testSideLogRebirth(t *testing.T, scheme string) {
|
|||
if _, err := blockchain.InsertChain(sideChain); err != nil {
|
||||
t.Fatalf("failed to insert forked chain: %v", err)
|
||||
}
|
||||
|
||||
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
|
||||
|
||||
// Generate a new block based on side chain.
|
||||
|
|
@ -1445,7 +1447,6 @@ func testSideLogRebirth(t *testing.T, scheme string) {
|
|||
if _, err := blockchain.InsertChain(newBlocks); err != nil {
|
||||
t.Fatalf("failed to insert forked chain: %v", err)
|
||||
}
|
||||
|
||||
checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
|
||||
}
|
||||
|
||||
|
|
@ -2000,7 +2001,6 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
|
|||
if _, err := chain.InsertChain(competitor[:len(competitor)-2]); err != nil {
|
||||
t.Fatalf("failed to insert competitor chain: %v", err)
|
||||
}
|
||||
|
||||
for i, block := range competitor[:len(competitor)-2] {
|
||||
if chain.HasState(block.Root()) {
|
||||
t.Fatalf("competitor %d: low TD chain became processed", i)
|
||||
|
|
@ -2371,9 +2371,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
|||
// [ Cn, Cn+1, Cc, Sn+3 ... Sm]
|
||||
// ^ ^ ^ pruned
|
||||
func TestPrunedImportSide(t *testing.T) {
|
||||
//glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false)))
|
||||
// glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
|
||||
// glogger.Verbosity(3)
|
||||
//log.Root().SetHandler(log.Handler(glogger))
|
||||
// log.SetDefault(log.NewLogger(glogger))
|
||||
testSideImport(t, 3, 3, -1)
|
||||
testSideImport(t, 3, -3, -1)
|
||||
testSideImport(t, 10, 0, -1)
|
||||
|
|
@ -2382,9 +2382,9 @@ func TestPrunedImportSide(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPrunedImportSideWithMerging(t *testing.T) {
|
||||
//glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false)))
|
||||
// glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
|
||||
// glogger.Verbosity(3)
|
||||
//log.Root().SetHandler(log.Handler(glogger))
|
||||
// log.SetDefault(log.NewLogger(glogger))
|
||||
testSideImport(t, 3, 3, 0)
|
||||
testSideImport(t, 3, -3, 0)
|
||||
testSideImport(t, 10, 0, 0)
|
||||
|
|
@ -3044,7 +3044,21 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
|
|||
// Generate and import the canonical chain
|
||||
_, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil)
|
||||
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil, 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, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -3967,7 +3981,7 @@ func TestSetCanonical(t *testing.T) {
|
|||
}
|
||||
|
||||
func testSetCanonical(t *testing.T, scheme string) {
|
||||
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||
|
||||
var (
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
|
|
@ -4019,7 +4033,7 @@ func testSetCanonical(t *testing.T, scheme string) {
|
|||
})
|
||||
|
||||
for _, block := range side {
|
||||
err := chain.InsertBlockWithoutSetHead(block)
|
||||
_, err := chain.InsertBlockWithoutSetHead(block, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to insert into chain: %v", err)
|
||||
}
|
||||
|
|
@ -4578,7 +4592,6 @@ func TestEIP3651(t *testing.T) {
|
|||
b.AddTx(tx)
|
||||
})
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil, nil)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tester chain: %v", err)
|
||||
}
|
||||
|
|
@ -4615,3 +4628,90 @@ func TestEIP3651(t *testing.T) {
|
|||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEIP6110(t *testing.T) {
|
||||
var (
|
||||
engine = beacon.NewFaker()
|
||||
|
||||
// A sender who makes transactions, has some funds
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
config = *params.AllEthashProtocolChanges
|
||||
gspec = &Genesis{
|
||||
Config: &config,
|
||||
Alloc: types.GenesisAlloc{
|
||||
addr: {Balance: funds},
|
||||
config.DepositContractAddress: {
|
||||
// Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7
|
||||
Code: common.Hex2Bytes("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033"),
|
||||
Nonce: 0,
|
||||
Balance: big.NewInt(0),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
gspec.Config.BerlinBlock = common.Big0
|
||||
gspec.Config.LondonBlock = common.Big0
|
||||
gspec.Config.TerminalTotalDifficulty = common.Big0
|
||||
gspec.Config.TerminalTotalDifficultyPassed = true
|
||||
gspec.Config.ShanghaiBlock = big.NewInt(0)
|
||||
gspec.Config.CancunBlock = big.NewInt(0)
|
||||
gspec.Config.PragueBlock = big.NewInt(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, nil, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,7 +359,18 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
gen(i, b)
|
||||
}
|
||||
|
||||
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals}
|
||||
var requests types.Requests
|
||||
if config.IsPrague(b.header.Number) {
|
||||
for _, r := range b.receipts {
|
||||
d, err := ParseDepositLogs(r.Logs, config)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
|
||||
}
|
||||
requests = append(requests, d...)
|
||||
}
|
||||
}
|
||||
|
||||
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: requests}
|
||||
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -381,7 +392,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
defer triedb.Close()
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabase(triedb, nil))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -482,15 +493,14 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
|
|||
panic(fmt.Sprintf("trie write error: %v", err))
|
||||
}
|
||||
|
||||
// TODO uncomment when proof generation is merged
|
||||
// proofs = append(proofs, block.ExecutionWitness().VerkleProof)
|
||||
// keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
|
||||
proofs = append(proofs, block.ExecutionWitness().VerkleProof)
|
||||
keyvals = append(keyvals, block.ExecutionWitness().StateDiff)
|
||||
|
||||
return block, b.receipts
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, trdb), nil)
|
||||
statedb, err := state.New(parent.Root(), state.NewDatabase(trdb, nil))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Config: &proConf,
|
||||
}
|
||||
|
||||
proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||
defer proBc.Stop()
|
||||
|
||||
|
|
@ -63,7 +62,6 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
|||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Config: &conConf,
|
||||
}
|
||||
|
||||
conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||
defer conBc.Stop()
|
||||
|
||||
|
|
|
|||
|
|
@ -81,25 +81,6 @@ func TestCreation(t *testing.T) {
|
|||
// {50000000, 2000000000, ID{Hash: checksumToBytes(0x9f3d2254), Next: 0}}, // Future Cancun block
|
||||
},
|
||||
},
|
||||
// Goerli test cases
|
||||
{
|
||||
params.GoerliChainConfig,
|
||||
core.DefaultGoerliGenesisBlock().ToBlock(),
|
||||
[]testcase{
|
||||
{0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
|
||||
{1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block
|
||||
{1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block
|
||||
{4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block
|
||||
{4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block
|
||||
{5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block
|
||||
// {5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // First London block
|
||||
// {6000000, 1678832735, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // Last London block
|
||||
// {6000001, 1678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // First Shanghai block
|
||||
// {6500002, 1705473119, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // Last Shanghai block
|
||||
// {6500003, 1705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // First Cancun block
|
||||
// {6500003, 2705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // Future Cancun block
|
||||
},
|
||||
},
|
||||
// Sepolia test cases
|
||||
{
|
||||
params.SepoliaChainConfig,
|
||||
|
|
|
|||
101
core/genesis.go
101
core/genesis.go
|
|
@ -141,8 +141,8 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
|
|||
}
|
||||
// Create an ephemeral in-memory database for computing hash,
|
||||
// all the derived states will be discarded to not pollute disk.
|
||||
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config)
|
||||
statedb, err := state.New(types.EmptyRootHash, db, nil)
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb.NewDatabase(db, config), nil))
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
|
@ -161,13 +161,12 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
|
|||
return statedb.Commit(0, false)
|
||||
}
|
||||
|
||||
// flushAlloc is very similar with hash, but the main difference is all the generated
|
||||
// states will be persisted into the given database. Also, the genesis state
|
||||
// specification will be flushed as well.
|
||||
func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database, blockhash common.Hash) error {
|
||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
// flushAlloc is very similar with hash, but the main difference is all the
|
||||
// generated states will be persisted into the given database.
|
||||
func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) {
|
||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb, nil))
|
||||
if err != nil {
|
||||
return err
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
for addr, account := range *ga {
|
||||
|
|
@ -185,23 +184,15 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
|
|||
}
|
||||
root, err := statedb.Commit(0, false)
|
||||
if err != nil {
|
||||
return err
|
||||
return common.Hash{}, err
|
||||
}
|
||||
// Commit newly generated states into disk if it's not empty.
|
||||
if root != types.EmptyRootHash {
|
||||
if err := triedb.Commit(root, true); err != nil {
|
||||
return err
|
||||
return common.Hash{}, err
|
||||
}
|
||||
}
|
||||
// Marshal the genesis state specification and persist.
|
||||
blob, err := json.Marshal(ga)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawdb.WriteGenesisStateSpec(db, blockhash, blob)
|
||||
|
||||
return nil
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) {
|
||||
|
|
@ -223,8 +214,6 @@ func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.Gene
|
|||
switch blockhash {
|
||||
case params.MainnetGenesisHash:
|
||||
genesis = DefaultGenesisBlock()
|
||||
case params.GoerliGenesisHash:
|
||||
genesis = DefaultGoerliGenesisBlock()
|
||||
case params.SepoliaGenesisHash:
|
||||
genesis = DefaultSepoliaGenesisBlock()
|
||||
case params.HoleskyGenesisHash:
|
||||
|
|
@ -464,7 +453,11 @@ func (g *Genesis) ToBlock() *types.Block {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return g.toBlockWithRoot(root)
|
||||
}
|
||||
|
||||
// toBlockWithRoot constructs the genesis block with the given genesis state root.
|
||||
func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
|
||||
head := &types.Header{
|
||||
Number: new(big.Int).SetUint64(g.Number),
|
||||
Nonce: types.EncodeNonce(g.Nonce),
|
||||
|
|
@ -494,28 +487,43 @@ func (g *Genesis) ToBlock() *types.Block {
|
|||
head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee)
|
||||
}
|
||||
}
|
||||
|
||||
var withdrawals []*types.Withdrawal
|
||||
var (
|
||||
withdrawals []*types.Withdrawal
|
||||
requests types.Requests
|
||||
)
|
||||
if conf := g.Config; conf != nil {
|
||||
num := big.NewInt(int64(g.Number))
|
||||
if conf.IsShanghai(num) {
|
||||
head.WithdrawalsHash = nil
|
||||
withdrawals = nil
|
||||
head.WithdrawalsHash = &types.EmptyWithdrawalsHash
|
||||
withdrawals = make([]*types.Withdrawal, 0)
|
||||
}
|
||||
if conf.IsCancun(num) {
|
||||
head.ParentBeaconRoot = nil
|
||||
head.ExcessBlobGas = nil
|
||||
head.BlobGasUsed = nil
|
||||
// EIP-4788: The parentBeaconBlockRoot of the genesis block is always
|
||||
// the zero hash. This is because the genesis block does not have a parent
|
||||
// by definition.
|
||||
head.ParentBeaconRoot = new(common.Hash)
|
||||
// EIP-4844 fields
|
||||
head.ExcessBlobGas = g.ExcessBlobGas
|
||||
head.BlobGasUsed = g.BlobGasUsed
|
||||
if head.ExcessBlobGas == nil {
|
||||
head.ExcessBlobGas = new(uint64)
|
||||
}
|
||||
if head.BlobGasUsed == nil {
|
||||
head.BlobGasUsed = new(uint64)
|
||||
}
|
||||
}
|
||||
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil))
|
||||
if conf.IsPrague(num) {
|
||||
head.RequestsHash = &types.EmptyRequestsHash
|
||||
requests = make(types.Requests, 0)
|
||||
}
|
||||
}
|
||||
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals, Requests: requests}, nil, trie.NewStackTrie(nil))
|
||||
}
|
||||
|
||||
// Commit writes the block and state of a genesis specification to the database.
|
||||
// The block is committed as the canonical head block.
|
||||
func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) {
|
||||
block := g.ToBlock()
|
||||
if block.Number().Sign() != 0 {
|
||||
if g.Number != 0 {
|
||||
return nil, errors.New("can't commit genesis block with number > 0")
|
||||
}
|
||||
config := g.Config
|
||||
|
|
@ -525,15 +533,22 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
|
|||
if err := config.CheckConfigForkOrder(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength {
|
||||
if config.Clique != nil && len(g.ExtraData) < 32+crypto.SignatureLength {
|
||||
return nil, errors.New("can't start clique chain without signers")
|
||||
}
|
||||
// All the checks has passed, flushAlloc the states derived from the genesis
|
||||
// specification as well as the specification itself into the provided
|
||||
// database.
|
||||
if err := flushAlloc(&g.Alloc, db, triedb, block.Hash()); err != nil {
|
||||
// flush the data to disk and compute the state root
|
||||
root, err := flushAlloc(&g.Alloc, triedb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block := g.toBlockWithRoot(root)
|
||||
|
||||
// Marshal the genesis state specification and persist.
|
||||
blob, err := json.Marshal(g.Alloc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawdb.WriteGenesisStateSpec(db, block.Hash(), blob)
|
||||
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
|
||||
rawdb.WriteBlock(db, block)
|
||||
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
|
||||
|
|
@ -577,18 +592,6 @@ func DefaultGenesisBlock() *Genesis {
|
|||
}
|
||||
}
|
||||
|
||||
// DefaultGoerliGenesisBlock returns the Görli network genesis block.
|
||||
func DefaultGoerliGenesisBlock() *Genesis {
|
||||
return &Genesis{
|
||||
Config: params.GoerliChainConfig,
|
||||
Timestamp: 1548854791,
|
||||
ExtraData: hexutil.MustDecode("0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
|
||||
GasLimit: 10485760,
|
||||
Difficulty: big.NewInt(1),
|
||||
Alloc: decodePrealloc(goerliAllocData),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultSepoliaGenesisBlock returns the Sepolia network genesis block.
|
||||
func DefaultSepoliaGenesisBlock() *Genesis {
|
||||
return &Genesis{
|
||||
|
|
@ -679,6 +682,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
|||
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
||||
// Pre-deploy EIP-4788 system contract
|
||||
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
||||
// Pre-deploy EIP-2935 history contract.
|
||||
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
|
||||
},
|
||||
}
|
||||
if faucet != nil {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -35,15 +35,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/triedb/pathdb"
|
||||
)
|
||||
|
||||
func TestInvalidCliqueConfig(t *testing.T) {
|
||||
block := DefaultGoerliGenesisBlock()
|
||||
block.ExtraData = []byte{}
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
if _, err := block.Commit(db, triedb.NewDatabase(db, nil)); err == nil {
|
||||
t.Fatal("Expected error on invalid clique config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupGenesis(t *testing.T) {
|
||||
testSetupGenesis(t, rawdb.HashScheme)
|
||||
testSetupGenesis(t, rawdb.PathScheme)
|
||||
|
|
@ -106,15 +97,15 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
|||
wantConfig: customg.Config,
|
||||
},
|
||||
{
|
||||
name: "custom block in DB, genesis == goerli",
|
||||
name: "custom block in DB, genesis == sepolia",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||
customg.Commit(db, tdb)
|
||||
return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock())
|
||||
return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock())
|
||||
},
|
||||
wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash},
|
||||
wantHash: params.GoerliGenesisHash,
|
||||
wantConfig: params.GoerliChainConfig,
|
||||
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
|
||||
wantHash: params.SepoliaGenesisHash,
|
||||
wantConfig: params.SepoliaChainConfig,
|
||||
},
|
||||
{
|
||||
name: "compatible config in DB",
|
||||
|
|
@ -187,7 +178,6 @@ func TestGenesisHashes(t *testing.T) {
|
|||
want common.Hash
|
||||
}{
|
||||
{DefaultGenesisBlock(), params.MainnetGenesisHash},
|
||||
{DefaultGoerliGenesisBlock(), params.GoerliGenesisHash},
|
||||
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
|
||||
} {
|
||||
// Test via MustCommit
|
||||
|
|
@ -313,7 +303,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
expected := common.FromHex("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b")
|
||||
expected := common.FromHex("4a83dc39eb688dbcfaf581d60e82de18f875e38786ebce5833342011d6fef37b")
|
||||
got := genesis.ToBlock().Root().Bytes()
|
||||
if !bytes.Equal(got, expected) {
|
||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ func (task *ExecutionTask) Execute(mvh *blockstm.MVHashMap, incarnation int) (er
|
|||
|
||||
// Apply the transaction to the current state (included in the env).
|
||||
if *task.shouldDelayFeeCal {
|
||||
task.result, err = ApplyMessageNoFeeBurnOrTip(evm, task.msg, new(GasPool).AddGas(task.gasLimit), nil)
|
||||
task.result, err = ApplyMessageNoFeeBurnOrTip(evm, task.msg, new(GasPool).AddGas(task.gasLimit))
|
||||
|
||||
if task.result == nil || err != nil {
|
||||
return blockstm.ErrExecAbortError{Dependency: task.statedb.DepTxIndex(), OriginError: err}
|
||||
|
|
@ -138,7 +138,7 @@ func (task *ExecutionTask) Execute(mvh *blockstm.MVHashMap, incarnation int) (er
|
|||
task.shouldRerunWithoutFeeDelay = true
|
||||
}
|
||||
} else {
|
||||
task.result, err = ApplyMessage(evm, &task.msg, new(GasPool).AddGas(task.gasLimit), nil)
|
||||
task.result, err = ApplyMessage(evm, &task.msg, new(GasPool).AddGas(task.gasLimit))
|
||||
}
|
||||
|
||||
if task.statedb.HadInvalidRead() || err != nil {
|
||||
|
|
@ -264,7 +264,7 @@ var parallelizabilityTimer = metrics.NewRegisteredTimer("block/parallelizability
|
|||
// 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.
|
||||
// nolint:gocognit
|
||||
func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config, interruptCtx context.Context) (types.Receipts, []*types.Log, uint64, error) {
|
||||
func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
|
||||
var (
|
||||
receipts types.Receipts
|
||||
header = block.Header()
|
||||
|
|
@ -306,7 +306,7 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
|
|||
msg, err := TransactionToMessage(tx, types.MakeSigner(p.config, header.Number, header.Time), header.BaseFee)
|
||||
if err != nil {
|
||||
log.Error("error creating message", "err", err)
|
||||
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)
|
||||
}
|
||||
|
||||
cleansdb := statedb.Copy()
|
||||
|
|
@ -343,8 +343,9 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
|
|||
|
||||
backupStateDB := statedb.Copy()
|
||||
|
||||
ctx := context.Background()
|
||||
profile := false
|
||||
result, err := blockstm.ExecuteParallel(tasks, profile, metadata, p.bc.parallelSpeculativeProcesses, interruptCtx)
|
||||
result, err := blockstm.ExecuteParallel(tasks, profile, metadata, p.bc.parallelSpeculativeProcesses, ctx)
|
||||
|
||||
if err == nil && profile && result.Deps != nil {
|
||||
_, weight := result.Deps.LongestPath(*result.Stats)
|
||||
|
|
@ -378,20 +379,34 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
|
|||
t.totalUsedGas = usedGas
|
||||
}
|
||||
|
||||
_, err = blockstm.ExecuteParallel(tasks, false, metadata, p.bc.parallelSpeculativeProcesses, interruptCtx)
|
||||
_, err = blockstm.ExecuteParallel(tasks, false, metadata, p.bc.parallelSpeculativeProcesses, ctx)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read requests if Prague is enabled.
|
||||
var requests types.Requests
|
||||
if p.config.IsPrague(block.Number()) {
|
||||
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)
|
||||
p.engine.Finalize(p.bc, header, statedb, block.Body())
|
||||
|
||||
return receipts, allLogs, *usedGas, nil
|
||||
return &ProcessResult{
|
||||
Receipts: receipts,
|
||||
Requests: requests,
|
||||
Logs: allLogs,
|
||||
GasUsed: *usedGas,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetDeps(txDependency [][]uint64) map[int][]int {
|
||||
|
|
|
|||
|
|
@ -303,6 +303,10 @@ func ParseStateScheme(provided string, disk ethdb.Database) (string, error) {
|
|||
log.Info("State scheme set to already existing", "scheme", stored)
|
||||
return stored, nil // reuse scheme of persistent scheme
|
||||
}
|
||||
// If state scheme is specified, ensure it's valid.
|
||||
if provided != HashScheme && provided != PathScheme {
|
||||
return "", fmt.Errorf("invalid state scheme %s", provided)
|
||||
}
|
||||
// If state scheme is specified, ensure it's compatible with
|
||||
// persistent state.
|
||||
if stored == "" || provided == stored {
|
||||
|
|
|
|||
|
|
@ -92,6 +92,16 @@ func InitDatabaseFromFreezer(db ethdb.Database) {
|
|||
log.Info("Initialized database from freezer", "blocks", frozen, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
}
|
||||
|
||||
// adjustRangeForBor updates the range to index transactions if the ancient data was pruned before. This is
|
||||
// to avoid indexing/unindexing data which is already pruned (i.e. before the `offset` block number).
|
||||
func adjustRangeForBor(db ethdb.Database, from uint64) uint64 {
|
||||
if offset := db.AncientOffSet(); offset > from {
|
||||
from = offset
|
||||
}
|
||||
|
||||
return from
|
||||
}
|
||||
|
||||
type blockTxHashes struct {
|
||||
number uint64
|
||||
hashes []common.Hash
|
||||
|
|
@ -108,10 +118,6 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool
|
|||
rlp rlp.RawValue
|
||||
}
|
||||
|
||||
if offset := db.AncientOffSet(); offset > from {
|
||||
from = offset
|
||||
}
|
||||
|
||||
if to <= from {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -206,6 +212,9 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool
|
|||
// There is a passed channel, the whole procedure will be interrupted if any
|
||||
// signal received.
|
||||
func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool, report bool) {
|
||||
// Adjust range if needed
|
||||
from = adjustRangeForBor(db, from)
|
||||
|
||||
// short circuit for invalid range
|
||||
if from >= to {
|
||||
return
|
||||
|
|
@ -309,6 +318,9 @@ func indexTransactionsForTesting(db ethdb.Database, from uint64, to uint64, inte
|
|||
// There is a passed channel, the whole procedure will be interrupted if any
|
||||
// signal received.
|
||||
func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool, report bool) {
|
||||
// Adjust range if needed
|
||||
from = adjustRangeForBor(db, from)
|
||||
|
||||
// short circuit for invalid range
|
||||
if from >= to {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -164,12 +164,6 @@ func (db *nofreezedb) ReadAncients(fn func(reader ethdb.AncientReaderOp) error)
|
|||
return fn(db)
|
||||
}
|
||||
|
||||
// MigrateTable processes the entries in a given table in sequence
|
||||
// converting them to a new format if they're of an old format.
|
||||
func (db *nofreezedb) MigrateTable(kind string, convert convertLegacyFn) error {
|
||||
return errNotSupported
|
||||
}
|
||||
|
||||
// AncientDatadir returns an error as we don't have a backing chain freezer.
|
||||
func (db *nofreezedb) AncientDatadir() (string, error) {
|
||||
return "", errNotSupported
|
||||
|
|
|
|||
|
|
@ -54,13 +54,11 @@ var (
|
|||
// freezerTableSize defines the maximum size of freezer data files.
|
||||
const freezerTableSize = 2 * 1000 * 1000 * 1000
|
||||
|
||||
// Freezer is a memory mapped append-only database to store immutable ordered
|
||||
// data into flat files:
|
||||
// Freezer is an append-only database to store immutable ordered data into
|
||||
// flat files:
|
||||
//
|
||||
// - The append-only nature ensures that disk writes are minimized.
|
||||
// - The memory mapping ensures we can max out system memory for caching without
|
||||
// reserving it for go-ethereum. This would also reduce the memory requirements
|
||||
// of Geth, and thus also GC overhead.
|
||||
// - The in-order data ensures that disk reads are always optimized.
|
||||
type Freezer struct {
|
||||
frozen atomic.Uint64 // Number of items already frozen
|
||||
tail atomic.Uint64 // Number of the first stored item in the freezer
|
||||
|
|
@ -162,7 +160,7 @@ func NewFreezer(datadir string, namespace string, readonly bool, offset uint64,
|
|||
return freezer, nil
|
||||
}
|
||||
|
||||
// Close terminates the chain freezer, unmapping all the data files.
|
||||
// Close terminates the chain freezer, closing all the data files.
|
||||
func (f *Freezer) Close() error {
|
||||
f.writeLock.Lock()
|
||||
defer f.writeLock.Unlock()
|
||||
|
|
|
|||
|
|
@ -413,13 +413,6 @@ func (f *MemoryFreezer) Sync() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// MigrateTable processes and migrates entries of a given table to a new format.
|
||||
// The second argument is a function that takes a raw entry and returns it
|
||||
// in the newest format.
|
||||
func (f *MemoryFreezer) MigrateTable(string, func([]byte) ([]byte, error)) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
// Close releases all the sources held by the memory freezer. It will panic if
|
||||
// any following invocation is made to a closed freezer.
|
||||
func (f *MemoryFreezer) Close() error {
|
||||
|
|
|
|||
|
|
@ -219,15 +219,6 @@ func (f *resettableFreezer) Sync() error {
|
|||
return f.freezer.Sync()
|
||||
}
|
||||
|
||||
// MigrateTable processes the entries in a given table in sequence
|
||||
// converting them to a new format if they're of an old format.
|
||||
func (f *resettableFreezer) MigrateTable(kind string, convert convertLegacyFn) error {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
return f.freezer.MigrateTable(kind, convert)
|
||||
}
|
||||
|
||||
// cleanup removes the directory located in the specified path
|
||||
// has the name with deletion marker suffix.
|
||||
func cleanup(path string) error {
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
|
|
@ -418,99 +416,6 @@ func checkAncientCount(t *testing.T, f *Freezer, kind string, n uint64) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRenameWindows(t *testing.T) {
|
||||
var (
|
||||
fname = "file.bin"
|
||||
fname2 = "file2.bin"
|
||||
data = []byte{1, 2, 3, 4}
|
||||
data2 = []byte{2, 3, 4, 5}
|
||||
data3 = []byte{3, 5, 6, 7}
|
||||
dataLen = 4
|
||||
)
|
||||
|
||||
// Create 2 temp dirs
|
||||
dir1 := t.TempDir()
|
||||
dir2 := t.TempDir()
|
||||
|
||||
// Create file in dir1 and fill with data
|
||||
f, err := os.Create(filepath.Join(dir1, fname))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f2, err := os.Create(filepath.Join(dir1, fname2))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f3, err := os.Create(filepath.Join(dir2, fname2))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := f.Write(data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := f2.Write(data2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := f3.Write(data3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := f.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := f2.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := f3.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Rename(f.Name(), filepath.Join(dir2, fname)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Rename(f2.Name(), filepath.Join(dir2, fname2)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Check file contents
|
||||
f, err = os.Open(filepath.Join(dir2, fname))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
buf := make([]byte, dataLen)
|
||||
if _, err := f.Read(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(buf, data) {
|
||||
t.Errorf("unexpected file contents. Got %v\n", buf)
|
||||
}
|
||||
|
||||
f, err = os.Open(filepath.Join(dir2, fname2))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
if _, err := f.Read(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(buf, data2) {
|
||||
t.Errorf("unexpected file contents. Got %v\n", buf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFreezerCloseSync(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
|||
|
|
@ -123,12 +123,6 @@ func (t *table) Sync() error {
|
|||
return t.db.Sync()
|
||||
}
|
||||
|
||||
// MigrateTable processes the entries in a given table in sequence
|
||||
// converting them to a new format if they're of an old format.
|
||||
func (t *table) MigrateTable(kind string, convert convertLegacyFn) error {
|
||||
return t.db.MigrateTable(kind, convert)
|
||||
}
|
||||
|
||||
// AncientDatadir returns the ancient datadir of the underlying database.
|
||||
func (t *table) AncientDatadir() (string, error) {
|
||||
return t.db.AncientDatadir()
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import (
|
|||
|
||||
// mode specifies how a tree location has been accessed
|
||||
// for the byte value:
|
||||
// * the first bit is set if the branch has been edited
|
||||
// * the second bit is set if the branch has been read
|
||||
// * the first bit is set if the branch has been read
|
||||
// * the second bit is set if the branch has been edited
|
||||
type mode byte
|
||||
|
||||
const (
|
||||
|
|
@ -94,11 +94,8 @@ func (ae *AccessEvents) Copy() *AccessEvents {
|
|||
// member fields of an account.
|
||||
func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite)
|
||||
return gas
|
||||
}
|
||||
|
||||
|
|
@ -107,8 +104,7 @@ func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
|||
// call to that account.
|
||||
func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.BasicDataLeafKey, false)
|
||||
return gas
|
||||
}
|
||||
|
||||
|
|
@ -116,41 +112,43 @@ func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
|||
// cold balance member fields of the caller and the callee accounts.
|
||||
func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
return gas
|
||||
}
|
||||
|
||||
// ContractCreateCPreheck charges access costs before
|
||||
// a contract creation is initiated. It is just reads, because the
|
||||
// address collision is done before the transfer, and so no write
|
||||
// are guaranteed to happen at this point.
|
||||
func (ae *AccessEvents) ContractCreatePreCheckGas(addr common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||
return gas
|
||||
}
|
||||
|
||||
// ContractCreateInitGas returns the access gas costs for the initialization of
|
||||
// a contract creation.
|
||||
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 {
|
||||
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true)
|
||||
if createSendsValue {
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
}
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, true)
|
||||
return gas
|
||||
}
|
||||
|
||||
// AddTxOrigin adds the member fields of the sender account to the access event list,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) {
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey, true)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||
}
|
||||
|
||||
// AddTxDestination adds the member fields of the sender account to the access event list,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) {
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, sendsValue)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, sendsValue)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||
}
|
||||
|
||||
// SlotGas returns the amount of gas to be charged for a cold storage access.
|
||||
|
|
@ -275,39 +273,12 @@ func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC,
|
|||
return statelessGasCharged
|
||||
}
|
||||
|
||||
// VersionGas adds the account's version to the accessed data, and returns the
|
||||
// BasicDataGas adds the account's basic data to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an
|
||||
// access in read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// BalanceGas adds the account's balance to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) BalanceGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// NonceGas adds the account's nonce to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) NonceGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// CodeSizeGas adds the account's code size to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
||||
func (ae *AccessEvents) BasicDataGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// CodeHashGas adds the account's code hash to the accessed data, and returns the
|
||||
|
|
@ -316,5 +287,5 @@ func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
|
|||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, isWrite)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,55 +40,43 @@ func TestAccountHeaderGas(t *testing.T) {
|
|||
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||
|
||||
// Check cold read cost
|
||||
gas := ae.VersionGas(testAddr, false)
|
||||
gas := ae.BasicDataGas(testAddr, false)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.VersionGas(testAddr, false)
|
||||
gas = ae.BasicDataGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check cold read costs in the same group no longer incur the branch read cost
|
||||
gas = ae.BalanceGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.NonceGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.CodeSizeGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.CodeHashGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
|
||||
// Check cold write cost
|
||||
gas = ae.VersionGas(testAddr, true)
|
||||
gas = ae.BasicDataGas(testAddr, true)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm write cost
|
||||
gas = ae.VersionGas(testAddr, true)
|
||||
gas = ae.BasicDataGas(testAddr, true)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check a write without a read charges both read and write costs
|
||||
gas = ae.BalanceGas(testAddr2, true)
|
||||
gas = ae.BasicDataGas(testAddr2, true)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check that a write followed by a read charges nothing
|
||||
gas = ae.BalanceGas(testAddr2, false)
|
||||
gas = ae.BasicDataGas(testAddr2, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
|
@ -112,13 +100,13 @@ func TestContractCreateInitGas(t *testing.T) {
|
|||
}
|
||||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.ContractCreateInitGas(testAddr, false)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*2; gas != want {
|
||||
gas := ae.ContractCreateInitGas(testAddr)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + 2*params.WitnessChunkWriteCost + 2*params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.ContractCreateInitGas(testAddr, false)
|
||||
gas = ae.ContractCreateInitGas(testAddr)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
|
@ -131,17 +119,17 @@ func TestMessageCallGas(t *testing.T) {
|
|||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.MessageCallGas(testAddr)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost*2; gas != want {
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check that reading the version and code size of the same account does not incur the branch read cost
|
||||
gas = ae.VersionGas(testAddr, false)
|
||||
// Check that reading the basic data and code hash of the same account does not incur the branch read cost
|
||||
gas = ae.BasicDataGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
gas = ae.CodeSizeGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
gas = ae.CodeHashGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
|
|
@ -45,29 +46,29 @@ const (
|
|||
|
||||
// Database wraps access to tries and contract code.
|
||||
type Database interface {
|
||||
// Reader returns a state reader associated with the specified state root.
|
||||
Reader(root common.Hash) (Reader, error)
|
||||
|
||||
// OpenTrie opens the main account trie.
|
||||
OpenTrie(root common.Hash) (Trie, error)
|
||||
|
||||
// OpenStorageTrie opens the storage trie of an account.
|
||||
OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error)
|
||||
|
||||
// CopyTrie returns an independent copy of the given trie.
|
||||
CopyTrie(Trie) Trie
|
||||
|
||||
// ContractCode retrieves a particular contract's code.
|
||||
ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error)
|
||||
|
||||
// ContractCodeSize retrieves a particular contracts code's size.
|
||||
ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error)
|
||||
|
||||
// DiskDB returns the underlying key-value disk database.
|
||||
DiskDB() ethdb.KeyValueStore
|
||||
|
||||
// PointCache returns the cache holding points used in verkle tree key computation
|
||||
PointCache() *utils.PointCache
|
||||
|
||||
// TrieDB returns the underlying trie database for managing trie nodes.
|
||||
TrieDB() *triedb.Database
|
||||
|
||||
// Snapshot returns the underlying state snapshot.
|
||||
Snapshot() *snapshot.Tree
|
||||
}
|
||||
|
||||
// Trie is a Ethereum Merkle Patricia trie.
|
||||
|
|
@ -94,7 +95,7 @@ type Trie interface {
|
|||
// UpdateAccount abstracts an account write to the trie. It encodes the
|
||||
// provided account object with associated algorithm and then updates it
|
||||
// in the trie with provided address.
|
||||
UpdateAccount(address common.Address, account *types.StateAccount) error
|
||||
UpdateAccount(address common.Address, account *types.StateAccount, codeLen int) error
|
||||
|
||||
// UpdateStorage associates key with value in the trie. If value has length zero,
|
||||
// any existing value is deleted from the trie. The value bytes must not be modified
|
||||
|
|
@ -147,47 +148,62 @@ type Trie interface {
|
|||
IsVerkle() bool
|
||||
}
|
||||
|
||||
// NewDatabase creates a backing store for state. The returned database is safe for
|
||||
// concurrent use, but does not retain any recent trie nodes in memory. To keep some
|
||||
// historical state in memory, use the NewDatabaseWithConfig constructor.
|
||||
func NewDatabase(db ethdb.Database) Database {
|
||||
return NewDatabaseWithConfig(db, nil)
|
||||
}
|
||||
|
||||
// NewDatabaseWithConfig creates a backing store for state. The returned database
|
||||
// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a
|
||||
// large memory cache.
|
||||
func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database {
|
||||
return &cachingDB{
|
||||
disk: db,
|
||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
||||
triedb: triedb.NewDatabase(db, config),
|
||||
pointCache: utils.NewPointCache(pointCacheSize),
|
||||
}
|
||||
}
|
||||
|
||||
// NewDatabaseWithNodeDB creates a state database with an already initialized node database.
|
||||
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database {
|
||||
return &cachingDB{
|
||||
disk: db,
|
||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
||||
triedb: triedb,
|
||||
pointCache: utils.NewPointCache(pointCacheSize),
|
||||
}
|
||||
}
|
||||
|
||||
type cachingDB struct {
|
||||
// CachingDB is an implementation of Database interface. It leverages both trie and
|
||||
// state snapshot to provide functionalities for state access. It's meant to be a
|
||||
// long-live object and has a few caches inside for sharing between blocks.
|
||||
type CachingDB struct {
|
||||
disk ethdb.KeyValueStore
|
||||
codeSizeCache *lru.Cache[common.Hash, int]
|
||||
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
||||
triedb *triedb.Database
|
||||
snap *snapshot.Tree
|
||||
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
||||
codeSizeCache *lru.Cache[common.Hash, int]
|
||||
pointCache *utils.PointCache
|
||||
}
|
||||
|
||||
// NewDatabase creates a state database with the provided data sources.
|
||||
func NewDatabase(triedb *triedb.Database, snap *snapshot.Tree) *CachingDB {
|
||||
return &CachingDB{
|
||||
disk: triedb.Disk(),
|
||||
triedb: triedb,
|
||||
snap: snap,
|
||||
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||
pointCache: utils.NewPointCache(pointCacheSize),
|
||||
}
|
||||
}
|
||||
|
||||
// NewDatabaseForTesting is similar to NewDatabase, but it initializes the caching
|
||||
// db by using an ephemeral memory db with default config for testing.
|
||||
func NewDatabaseForTesting() *CachingDB {
|
||||
return NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil)
|
||||
}
|
||||
|
||||
// Reader returns a state reader associated with the specified state root.
|
||||
func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||
var readers []Reader
|
||||
|
||||
// Set up the state snapshot reader if available. This feature
|
||||
// is optional and may be partially useful if it's not fully
|
||||
// generated.
|
||||
if db.snap != nil {
|
||||
sr, err := newStateReader(stateRoot, db.snap)
|
||||
if err == nil {
|
||||
readers = append(readers, sr) // snap reader is optional
|
||||
}
|
||||
}
|
||||
// Set up the trie reader, which is expected to always be available
|
||||
// as the gatekeeper unless the state is corrupted.
|
||||
tr, err := newTrieReader(stateRoot, db.triedb, db.pointCache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
readers = append(readers, tr)
|
||||
|
||||
return newMultiReader(readers...)
|
||||
}
|
||||
|
||||
// OpenTrie opens the main account trie at a specific root hash.
|
||||
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
||||
func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
||||
if db.triedb.IsVerkle() {
|
||||
return trie.NewVerkleTrie(root, db.triedb, db.pointCache)
|
||||
}
|
||||
|
|
@ -200,7 +216,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
|||
}
|
||||
|
||||
// OpenStorageTrie opens the storage trie of an account.
|
||||
func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) {
|
||||
func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) {
|
||||
// In the verkle case, there is only one tree. But the two-tree structure
|
||||
// is hardcoded in the codebase. So we need to return the same trie in this
|
||||
// case.
|
||||
|
|
@ -215,20 +231,8 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
|
|||
return tr, nil
|
||||
}
|
||||
|
||||
// CopyTrie returns an independent copy of the given trie.
|
||||
func (db *cachingDB) CopyTrie(t Trie) Trie {
|
||||
switch t := t.(type) {
|
||||
case *trie.StateTrie:
|
||||
return t.Copy()
|
||||
case *trie.VerkleTrie:
|
||||
return t.Copy()
|
||||
default:
|
||||
panic(fmt.Errorf("unknown trie type %T", t))
|
||||
}
|
||||
}
|
||||
|
||||
// ContractCode retrieves a particular contract's code.
|
||||
func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
|
||||
func (db *CachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
|
||||
code, _ := db.codeCache.Get(codeHash)
|
||||
if len(code) > 0 {
|
||||
return code, nil
|
||||
|
|
@ -249,7 +253,7 @@ func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash)
|
|||
// ContractCodeWithPrefix retrieves a particular contract's code. If the
|
||||
// code can't be found in the cache, then check the existence with **new**
|
||||
// db scheme.
|
||||
func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
|
||||
func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
|
||||
code, _ := db.codeCache.Get(codeHash)
|
||||
if len(code) > 0 {
|
||||
return code, nil
|
||||
|
|
@ -268,7 +272,7 @@ func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash com
|
|||
}
|
||||
|
||||
// ContractCodeSize retrieves a particular contracts code's size.
|
||||
func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
||||
func (db *CachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
||||
if cached, ok := db.codeSizeCache.Get(codeHash); ok {
|
||||
return cached, nil
|
||||
}
|
||||
|
|
@ -276,17 +280,29 @@ func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash)
|
|||
return len(code), err
|
||||
}
|
||||
|
||||
// DiskDB returns the underlying key-value disk database.
|
||||
func (db *cachingDB) DiskDB() ethdb.KeyValueStore {
|
||||
return db.disk
|
||||
}
|
||||
|
||||
// TrieDB retrieves any intermediate trie-node caching layer.
|
||||
func (db *cachingDB) TrieDB() *triedb.Database {
|
||||
func (db *CachingDB) TrieDB() *triedb.Database {
|
||||
return db.triedb
|
||||
}
|
||||
|
||||
// PointCache returns the cache of evaluated curve points.
|
||||
func (db *cachingDB) PointCache() *utils.PointCache {
|
||||
func (db *CachingDB) PointCache() *utils.PointCache {
|
||||
return db.pointCache
|
||||
}
|
||||
|
||||
// Snapshot returns the underlying state snapshot.
|
||||
func (db *CachingDB) Snapshot() *snapshot.Tree {
|
||||
return db.snap
|
||||
}
|
||||
|
||||
// mustCopyTrie returns a deep-copied trie.
|
||||
func mustCopyTrie(t Trie) Trie {
|
||||
switch t := t.(type) {
|
||||
case *trie.StateTrie:
|
||||
return t.Copy()
|
||||
case *trie.VerkleTrie:
|
||||
return t.Copy()
|
||||
default:
|
||||
panic(fmt.Errorf("unknown trie type %T", t))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func testNodeIteratorCoverage(t *testing.T, scheme string) {
|
|||
db, sdb, ndb, root, _ := makeTestState(scheme)
|
||||
ndb.Commit(root, false)
|
||||
|
||||
state, err := New(root, sdb, nil)
|
||||
state, err := New(root, sdb)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create state trie at %x: %v", root, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,21 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/blockstm"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type revision struct {
|
||||
id int
|
||||
journalIndex int
|
||||
}
|
||||
|
||||
// journalEntry is a modification entry in the state change journal that can be
|
||||
// reverted on demand.
|
||||
type journalEntry interface {
|
||||
|
|
@ -43,6 +51,9 @@ type journalEntry interface {
|
|||
type journal struct {
|
||||
entries []journalEntry // Current changes tracked by the journal
|
||||
dirties map[common.Address]int // Dirty accounts and the number of changes
|
||||
|
||||
validRevisions []revision
|
||||
nextRevisionId int
|
||||
}
|
||||
|
||||
// newJournal creates a new initialized journal.
|
||||
|
|
@ -52,6 +63,40 @@ func newJournal() *journal {
|
|||
}
|
||||
}
|
||||
|
||||
// reset clears the journal, after this operation the journal can be used anew.
|
||||
// It is semantically similar to calling 'newJournal', but the underlying slices
|
||||
// can be reused.
|
||||
func (j *journal) reset() {
|
||||
j.entries = j.entries[:0]
|
||||
j.validRevisions = j.validRevisions[:0]
|
||||
clear(j.dirties)
|
||||
j.nextRevisionId = 0
|
||||
}
|
||||
|
||||
// snapshot returns an identifier for the current revision of the state.
|
||||
func (j *journal) snapshot() int {
|
||||
id := j.nextRevisionId
|
||||
j.nextRevisionId++
|
||||
j.validRevisions = append(j.validRevisions, revision{id, j.length()})
|
||||
return id
|
||||
}
|
||||
|
||||
// revertToSnapshot reverts all state changes made since the given revision.
|
||||
func (j *journal) revertToSnapshot(revid int, s *StateDB) {
|
||||
// Find the snapshot in the stack of valid snapshots.
|
||||
idx := sort.Search(len(j.validRevisions), func(i int) bool {
|
||||
return j.validRevisions[i].id >= revid
|
||||
})
|
||||
if idx == len(j.validRevisions) || j.validRevisions[idx].id != revid {
|
||||
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
|
||||
}
|
||||
snapshot := j.validRevisions[idx].journalIndex
|
||||
|
||||
// Replay the journal to undo changes and remove invalidated snapshots
|
||||
j.revert(s, snapshot)
|
||||
j.validRevisions = j.validRevisions[:idx]
|
||||
}
|
||||
|
||||
// append inserts a new modification entry to the end of the change journal.
|
||||
func (j *journal) append(entry journalEntry) {
|
||||
j.entries = append(j.entries, entry)
|
||||
|
|
@ -99,46 +144,120 @@ func (j *journal) copy() *journal {
|
|||
return &journal{
|
||||
entries: entries,
|
||||
dirties: maps.Clone(j.dirties),
|
||||
validRevisions: slices.Clone(j.validRevisions),
|
||||
nextRevisionId: j.nextRevisionId,
|
||||
}
|
||||
}
|
||||
|
||||
func (j *journal) logChange(txHash common.Hash) {
|
||||
j.append(addLogChange{txhash: txHash})
|
||||
}
|
||||
|
||||
func (j *journal) createObject(addr common.Address) {
|
||||
j.append(createObjectChange{account: addr})
|
||||
}
|
||||
|
||||
func (j *journal) createContract(addr common.Address) {
|
||||
j.append(createContractChange{account: addr})
|
||||
}
|
||||
|
||||
func (j *journal) destruct(addr common.Address) {
|
||||
j.append(selfDestructChange{account: addr})
|
||||
}
|
||||
|
||||
func (j *journal) storageChange(addr common.Address, key, prev, origin common.Hash) {
|
||||
j.append(storageChange{
|
||||
account: addr,
|
||||
key: key,
|
||||
prevvalue: prev,
|
||||
origvalue: origin,
|
||||
})
|
||||
}
|
||||
|
||||
func (j *journal) transientStateChange(addr common.Address, key, prev common.Hash) {
|
||||
j.append(transientStorageChange{
|
||||
account: addr,
|
||||
key: key,
|
||||
prevalue: prev,
|
||||
})
|
||||
}
|
||||
|
||||
func (j *journal) refundChange(previous uint64) {
|
||||
j.append(refundChange{prev: previous})
|
||||
}
|
||||
|
||||
func (j *journal) balanceChange(addr common.Address, previous *uint256.Int) {
|
||||
j.append(balanceChange{
|
||||
account: addr,
|
||||
prev: previous.Clone(),
|
||||
})
|
||||
}
|
||||
|
||||
func (j *journal) setCode(address common.Address) {
|
||||
j.append(codeChange{account: address})
|
||||
}
|
||||
|
||||
func (j *journal) nonceChange(address common.Address, prev uint64) {
|
||||
j.append(nonceChange{
|
||||
account: address,
|
||||
prev: prev,
|
||||
})
|
||||
}
|
||||
|
||||
func (j *journal) touchChange(address common.Address) {
|
||||
j.append(touchChange{
|
||||
account: address,
|
||||
})
|
||||
if address == ripemd {
|
||||
// Explicitly put it in the dirty-cache, which is otherwise generated from
|
||||
// flattened journals.
|
||||
j.dirty(address)
|
||||
}
|
||||
}
|
||||
|
||||
func (j *journal) accessListAddAccount(addr common.Address) {
|
||||
j.append(accessListAddAccountChange{addr})
|
||||
}
|
||||
|
||||
func (j *journal) accessListAddSlot(addr common.Address, slot common.Hash) {
|
||||
j.append(accessListAddSlotChange{
|
||||
address: addr,
|
||||
slot: slot,
|
||||
})
|
||||
}
|
||||
|
||||
type (
|
||||
// Changes to the account trie.
|
||||
createObjectChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
}
|
||||
|
||||
// createContractChange represents an account becoming a contract-account.
|
||||
// This event happens prior to executing initcode. The journal-event simply
|
||||
// manages the created-flag, in order to allow same-tx destruction.
|
||||
createContractChange struct {
|
||||
account common.Address
|
||||
}
|
||||
|
||||
selfDestructChange struct {
|
||||
account *common.Address
|
||||
prev bool // whether account had already self-destructed
|
||||
prevbalance *uint256.Int
|
||||
account common.Address
|
||||
}
|
||||
|
||||
// Changes to individual accounts.
|
||||
balanceChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
prev *uint256.Int
|
||||
}
|
||||
nonceChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
prev uint64
|
||||
}
|
||||
storageChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
key common.Hash
|
||||
prevvalue common.Hash
|
||||
origvalue common.Hash
|
||||
}
|
||||
codeChange struct {
|
||||
account *common.Address
|
||||
prevcode, prevhash []byte
|
||||
account common.Address
|
||||
}
|
||||
|
||||
// Changes to other state values.
|
||||
|
|
@ -148,36 +267,32 @@ type (
|
|||
addLogChange struct {
|
||||
txhash common.Hash
|
||||
}
|
||||
addPreimageChange struct {
|
||||
hash common.Hash
|
||||
}
|
||||
touchChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
}
|
||||
|
||||
// Changes to the access list
|
||||
accessListAddAccountChange struct {
|
||||
address *common.Address
|
||||
address common.Address
|
||||
}
|
||||
accessListAddSlotChange struct {
|
||||
address *common.Address
|
||||
slot *common.Hash
|
||||
address common.Address
|
||||
slot common.Hash
|
||||
}
|
||||
|
||||
// Changes to transient storage
|
||||
transientStorageChange struct {
|
||||
account *common.Address
|
||||
account common.Address
|
||||
key, prevalue common.Hash
|
||||
}
|
||||
)
|
||||
|
||||
func (ch createObjectChange) revert(s *StateDB) {
|
||||
delete(s.stateObjects, *ch.account)
|
||||
RevertWrite(s, blockstm.NewAddressKey(*ch.account))
|
||||
delete(s.stateObjects, ch.account)
|
||||
}
|
||||
|
||||
func (ch createObjectChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch createObjectChange) copy() journalEntry {
|
||||
|
|
@ -201,23 +316,19 @@ func (ch createContractChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch selfDestructChange) revert(s *StateDB) {
|
||||
obj := s.getStateObject(*ch.account)
|
||||
obj := s.getStateObject(ch.account)
|
||||
if obj != nil {
|
||||
obj.selfDestructed = ch.prev
|
||||
obj.setBalance(ch.prevbalance)
|
||||
RevertWrite(s, blockstm.NewSubpathKey(*ch.account, SuicidePath))
|
||||
obj.selfDestructed = false
|
||||
}
|
||||
}
|
||||
|
||||
func (ch selfDestructChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch selfDestructChange) copy() journalEntry {
|
||||
return selfDestructChange{
|
||||
account: ch.account,
|
||||
prev: ch.prev,
|
||||
prevbalance: new(uint256.Int).Set(ch.prevbalance),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -227,7 +338,7 @@ func (ch touchChange) revert(s *StateDB) {
|
|||
}
|
||||
|
||||
func (ch touchChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch touchChange) copy() journalEntry {
|
||||
|
|
@ -237,11 +348,11 @@ func (ch touchChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch balanceChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setBalance(ch.prev)
|
||||
s.getStateObject(ch.account).setBalance(ch.prev)
|
||||
}
|
||||
|
||||
func (ch balanceChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch balanceChange) copy() journalEntry {
|
||||
|
|
@ -252,11 +363,11 @@ func (ch balanceChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch nonceChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setNonce(ch.prev)
|
||||
s.getStateObject(ch.account).setNonce(ch.prev)
|
||||
}
|
||||
|
||||
func (ch nonceChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch nonceChange) copy() journalEntry {
|
||||
|
|
@ -267,29 +378,23 @@ func (ch nonceChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch codeChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
|
||||
RevertWrite(s, blockstm.NewSubpathKey(*ch.account, CodePath))
|
||||
s.getStateObject(ch.account).setCode(types.EmptyCodeHash, nil)
|
||||
}
|
||||
|
||||
func (ch codeChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch codeChange) copy() journalEntry {
|
||||
return codeChange{
|
||||
account: ch.account,
|
||||
prevhash: common.CopyBytes(ch.prevhash),
|
||||
prevcode: common.CopyBytes(ch.prevcode),
|
||||
}
|
||||
return codeChange{account: ch.account}
|
||||
}
|
||||
|
||||
func (ch storageChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue, ch.origvalue)
|
||||
RevertWrite(s, blockstm.NewStateKey(*ch.account, ch.key))
|
||||
s.getStateObject(ch.account).setState(ch.key, ch.prevvalue, ch.origvalue)
|
||||
}
|
||||
|
||||
func (ch storageChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
return &ch.account
|
||||
}
|
||||
|
||||
func (ch storageChange) copy() journalEntry {
|
||||
|
|
@ -301,7 +406,7 @@ func (ch storageChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch transientStorageChange) revert(s *StateDB) {
|
||||
s.setTransientState(*ch.account, ch.key, ch.prevalue)
|
||||
s.setTransientState(ch.account, ch.key, ch.prevalue)
|
||||
}
|
||||
|
||||
func (ch transientStorageChange) dirtied() *common.Address {
|
||||
|
|
@ -351,20 +456,6 @@ func (ch addLogChange) copy() journalEntry {
|
|||
}
|
||||
}
|
||||
|
||||
func (ch addPreimageChange) revert(s *StateDB) {
|
||||
delete(s.preimages, ch.hash)
|
||||
}
|
||||
|
||||
func (ch addPreimageChange) dirtied() *common.Address {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch addPreimageChange) copy() journalEntry {
|
||||
return addPreimageChange{
|
||||
hash: ch.hash,
|
||||
}
|
||||
}
|
||||
|
||||
func (ch accessListAddAccountChange) revert(s *StateDB) {
|
||||
/*
|
||||
One important invariant here, is that whenever a (addr, slot) is added, if the
|
||||
|
|
@ -375,7 +466,7 @@ func (ch accessListAddAccountChange) revert(s *StateDB) {
|
|||
(addr) at this point, since no storage adds can remain when come upon
|
||||
a single (addr) change.
|
||||
*/
|
||||
s.accessList.DeleteAddress(*ch.address)
|
||||
s.accessList.DeleteAddress(ch.address)
|
||||
}
|
||||
|
||||
func (ch accessListAddAccountChange) dirtied() *common.Address {
|
||||
|
|
@ -389,7 +480,7 @@ func (ch accessListAddAccountChange) copy() journalEntry {
|
|||
}
|
||||
|
||||
func (ch accessListAddSlotChange) revert(s *StateDB) {
|
||||
s.accessList.DeleteSlot(*ch.address, *ch.slot)
|
||||
s.accessList.DeleteSlot(ch.address, ch.slot)
|
||||
}
|
||||
|
||||
func (ch accessListAddSlotChange) dirtied() *common.Address {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package state
|
|||
import "github.com/ethereum/go-ethereum/metrics"
|
||||
|
||||
var (
|
||||
accountReadMeters = metrics.NewRegisteredMeter("state/read/accounts", nil)
|
||||
storageReadMeters = metrics.NewRegisteredMeter("state/read/storage", nil)
|
||||
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
|
||||
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
|
||||
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)
|
||||
|
|
|
|||
|
|
@ -274,11 +274,10 @@ func (p *Pruner) Prune(root common.Hash) error {
|
|||
// is the presence of root can indicate the presence of the
|
||||
// entire trie.
|
||||
if !rawdb.HasLegacyTrieNode(p.db, root) {
|
||||
// The special case is for clique based networks(goerli
|
||||
// and some other private networks), it's possible that two
|
||||
// consecutive blocks will have same root. In this case snapshot
|
||||
// difflayer won't be created. So HEAD-127 may not paired with
|
||||
// head-127 layer. Instead the paired layer is higher than the
|
||||
// The special case is for clique based networks, it's possible
|
||||
// that two consecutive blocks will have same root. In this case
|
||||
// snapshot difflayer won't be created. So HEAD-127 may not paired
|
||||
// with head-127 layer. Instead the paired layer is higher than the
|
||||
// bottom-most diff layer. Try to find the bottom-most snapshot
|
||||
// layer with state available.
|
||||
//
|
||||
|
|
|
|||
313
core/state/reader.go
Normal file
313
core/state/reader.go
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"maps"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/utils"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
)
|
||||
|
||||
// Reader defines the interface for accessing accounts and storage slots
|
||||
// associated with a specific state.
|
||||
type Reader interface {
|
||||
// Account retrieves the account associated with a particular address.
|
||||
//
|
||||
// - Returns a nil account if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned account is safe to modify after the call
|
||||
Account(addr common.Address) (*types.StateAccount, error)
|
||||
|
||||
// Storage retrieves the storage slot associated with a particular account
|
||||
// address and slot key.
|
||||
//
|
||||
// - Returns an empty slot if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned storage slot is safe to modify after the call
|
||||
Storage(addr common.Address, slot common.Hash) (common.Hash, error)
|
||||
|
||||
// Copy returns a deep-copied state reader.
|
||||
Copy() Reader
|
||||
}
|
||||
|
||||
// stateReader is a wrapper over the state snapshot and implements the Reader
|
||||
// interface. It provides an efficient way to access flat state.
|
||||
type stateReader struct {
|
||||
snap snapshot.Snapshot
|
||||
buff crypto.KeccakState
|
||||
}
|
||||
|
||||
// newStateReader constructs a flat state reader with on the specified state root.
|
||||
func newStateReader(root common.Hash, snaps *snapshot.Tree) (*stateReader, error) {
|
||||
snap := snaps.Snapshot(root)
|
||||
if snap == nil {
|
||||
return nil, errors.New("snapshot is not available")
|
||||
}
|
||||
return &stateReader{
|
||||
snap: snap,
|
||||
buff: crypto.NewKeccakState(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Account implements Reader, retrieving the account specified by the address.
|
||||
//
|
||||
// An error will be returned if the associated snapshot is already stale or
|
||||
// the requested account is not yet covered by the snapshot.
|
||||
//
|
||||
// The returned account might be nil if it's not existent.
|
||||
func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||
ret, err := r.snap.Account(crypto.HashData(r.buff, addr.Bytes()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret == nil {
|
||||
return nil, nil
|
||||
}
|
||||
acct := &types.StateAccount{
|
||||
Nonce: ret.Nonce,
|
||||
Balance: ret.Balance,
|
||||
CodeHash: ret.CodeHash,
|
||||
Root: common.BytesToHash(ret.Root),
|
||||
}
|
||||
if len(acct.CodeHash) == 0 {
|
||||
acct.CodeHash = types.EmptyCodeHash.Bytes()
|
||||
}
|
||||
if acct.Root == (common.Hash{}) {
|
||||
acct.Root = types.EmptyRootHash
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
// Storage implements Reader, retrieving the storage slot specified by the
|
||||
// address and slot key.
|
||||
//
|
||||
// An error will be returned if the associated snapshot is already stale or
|
||||
// the requested storage slot is not yet covered by the snapshot.
|
||||
//
|
||||
// The returned storage slot might be empty if it's not existent.
|
||||
func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
||||
addrHash := crypto.HashData(r.buff, addr.Bytes())
|
||||
slotHash := crypto.HashData(r.buff, key.Bytes())
|
||||
ret, err := r.snap.Storage(addrHash, slotHash)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
if len(ret) == 0 {
|
||||
return common.Hash{}, nil
|
||||
}
|
||||
// Perform the rlp-decode as the slot value is RLP-encoded in the state
|
||||
// snapshot.
|
||||
_, content, _, err := rlp.Split(ret)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
var value common.Hash
|
||||
value.SetBytes(content)
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// Copy implements Reader, returning a deep-copied snap reader.
|
||||
func (r *stateReader) Copy() Reader {
|
||||
return &stateReader{
|
||||
snap: r.snap,
|
||||
buff: crypto.NewKeccakState(),
|
||||
}
|
||||
}
|
||||
|
||||
// trieReader implements the Reader interface, providing functions to access
|
||||
// state from the referenced trie.
|
||||
type trieReader struct {
|
||||
root common.Hash // State root which uniquely represent a state
|
||||
db *triedb.Database // Database for loading trie
|
||||
buff crypto.KeccakState // Buffer for keccak256 hashing
|
||||
mainTrie Trie // Main trie, resolved in constructor
|
||||
subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved
|
||||
subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved
|
||||
}
|
||||
|
||||
// trieReader constructs a trie reader of the specific state. An error will be
|
||||
// returned if the associated trie specified by root is not existent.
|
||||
func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCache) (*trieReader, error) {
|
||||
var (
|
||||
tr Trie
|
||||
err error
|
||||
)
|
||||
if !db.IsVerkle() {
|
||||
tr, err = trie.NewStateTrie(trie.StateTrieID(root), db)
|
||||
} else {
|
||||
tr, err = trie.NewVerkleTrie(root, db, cache)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &trieReader{
|
||||
root: root,
|
||||
db: db,
|
||||
buff: crypto.NewKeccakState(),
|
||||
mainTrie: tr,
|
||||
subRoots: make(map[common.Address]common.Hash),
|
||||
subTries: make(map[common.Address]Trie),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Account implements Reader, retrieving the account specified by the address.
|
||||
//
|
||||
// An error will be returned if the trie state is corrupted. An nil account
|
||||
// will be returned if it's not existent in the trie.
|
||||
func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||
account, err := r.mainTrie.GetAccount(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if account == nil {
|
||||
r.subRoots[addr] = types.EmptyRootHash
|
||||
} else {
|
||||
r.subRoots[addr] = account.Root
|
||||
}
|
||||
return account, nil
|
||||
}
|
||||
|
||||
// Storage implements Reader, retrieving the storage slot specified by the
|
||||
// address and slot key.
|
||||
//
|
||||
// An error will be returned if the trie state is corrupted. An empty storage
|
||||
// slot will be returned if it's not existent in the trie.
|
||||
func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
||||
var (
|
||||
tr Trie
|
||||
found bool
|
||||
value common.Hash
|
||||
)
|
||||
if r.db.IsVerkle() {
|
||||
tr = r.mainTrie
|
||||
} else {
|
||||
tr, found = r.subTries[addr]
|
||||
if !found {
|
||||
root, ok := r.subRoots[addr]
|
||||
|
||||
// The storage slot is accessed without account caching. It's unexpected
|
||||
// behavior but try to resolve the account first anyway.
|
||||
if !ok {
|
||||
_, err := r.Account(addr)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
root = r.subRoots[addr]
|
||||
}
|
||||
var err error
|
||||
tr, err = trie.NewStateTrie(trie.StorageTrieID(r.root, crypto.HashData(r.buff, addr.Bytes()), root), r.db)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
r.subTries[addr] = tr
|
||||
}
|
||||
}
|
||||
ret, err := tr.GetStorage(addr, key.Bytes())
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
value.SetBytes(ret)
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// Copy implements Reader, returning a deep-copied trie reader.
|
||||
func (r *trieReader) Copy() Reader {
|
||||
tries := make(map[common.Address]Trie)
|
||||
for addr, tr := range r.subTries {
|
||||
tries[addr] = mustCopyTrie(tr)
|
||||
}
|
||||
return &trieReader{
|
||||
root: r.root,
|
||||
db: r.db,
|
||||
buff: crypto.NewKeccakState(),
|
||||
mainTrie: mustCopyTrie(r.mainTrie),
|
||||
subRoots: maps.Clone(r.subRoots),
|
||||
subTries: tries,
|
||||
}
|
||||
}
|
||||
|
||||
// multiReader is the aggregation of a list of Reader interface, providing state
|
||||
// access by leveraging all readers. The checking priority is determined by the
|
||||
// position in the reader list.
|
||||
type multiReader struct {
|
||||
readers []Reader // List of readers, sorted by checking priority
|
||||
}
|
||||
|
||||
// newMultiReader constructs a multiReader instance with the given readers. The
|
||||
// priority among readers is assumed to be sorted. Note, it must contain at least
|
||||
// one reader for constructing a multiReader.
|
||||
func newMultiReader(readers ...Reader) (*multiReader, error) {
|
||||
if len(readers) == 0 {
|
||||
return nil, errors.New("empty reader set")
|
||||
}
|
||||
return &multiReader{
|
||||
readers: readers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Account implementing Reader interface, retrieving the account associated with
|
||||
// a particular address.
|
||||
//
|
||||
// - Returns a nil account if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned account is safe to modify after the call
|
||||
func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||
var errs []error
|
||||
for _, reader := range r.readers {
|
||||
acct, err := reader.Account(addr)
|
||||
if err == nil {
|
||||
return acct, nil
|
||||
}
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return nil, errors.Join(errs...)
|
||||
}
|
||||
|
||||
// Storage implementing Reader interface, retrieving the storage slot associated
|
||||
// with a particular account address and slot key.
|
||||
//
|
||||
// - Returns an empty slot if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned storage slot is safe to modify after the call
|
||||
func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||
var errs []error
|
||||
for _, reader := range r.readers {
|
||||
slot, err := reader.Storage(addr, slot)
|
||||
if err == nil {
|
||||
return slot, nil
|
||||
}
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return common.Hash{}, errors.Join(errs...)
|
||||
}
|
||||
|
||||
// Copy implementing Reader interface, returning a deep-copied state reader.
|
||||
func (r *multiReader) Copy() Reader {
|
||||
var readers []Reader
|
||||
for _, reader := range r.readers {
|
||||
readers = append(readers, reader.Copy())
|
||||
}
|
||||
return &multiReader{readers: readers}
|
||||
}
|
||||
|
|
@ -74,6 +74,14 @@ func (dl *diskLayer) Stale() bool {
|
|||
return dl.stale
|
||||
}
|
||||
|
||||
// markStale sets the stale flag as true.
|
||||
func (dl *diskLayer) markStale() {
|
||||
dl.lock.Lock()
|
||||
defer dl.lock.Unlock()
|
||||
|
||||
dl.stale = true
|
||||
}
|
||||
|
||||
// Account directly retrieves the account associated with a particular hash in
|
||||
// the snapshot slim data format.
|
||||
func (dl *diskLayer) Account(hash common.Hash) (*types.SlimAccount, error) {
|
||||
|
|
@ -184,3 +192,18 @@ func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
|
|||
func (dl *diskLayer) Update(blockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer {
|
||||
return newDiffLayer(dl, blockHash, destructs, accounts, storage)
|
||||
}
|
||||
|
||||
// stopGeneration aborts the state snapshot generation if it is currently running.
|
||||
func (dl *diskLayer) stopGeneration() {
|
||||
dl.lock.RLock()
|
||||
generating := dl.genMarker != nil
|
||||
dl.lock.RUnlock()
|
||||
if !generating {
|
||||
return
|
||||
}
|
||||
if dl.genAbort != nil {
|
||||
abort := make(chan *generatorStats)
|
||||
dl.genAbort <- abort
|
||||
<-abort
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -698,18 +698,11 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
|
|||
|
||||
return nil
|
||||
}
|
||||
// Always reset the initial account range as 1 whenever recover from the
|
||||
// interruption. TODO(rjl493456442) can we remove it?
|
||||
var accountRange = accountCheckRange
|
||||
if len(accMarker) > 0 {
|
||||
accountRange = 1
|
||||
}
|
||||
|
||||
origin := common.CopyBytes(accMarker)
|
||||
|
||||
for {
|
||||
id := trie.StateTrieID(dl.root)
|
||||
exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, types.FullAccountRLP)
|
||||
exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountCheckRange, onAccount, types.FullAccountRLP)
|
||||
if err != nil {
|
||||
return err // The procedure it aborted, either by external signal or internal error.
|
||||
}
|
||||
|
|
@ -722,8 +715,6 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
|
|||
ctx.removeStorageLeft()
|
||||
break
|
||||
}
|
||||
|
||||
accountRange = accountCheckRange
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -262,24 +262,11 @@ func (t *Tree) Disable() {
|
|||
for _, layer := range t.layers {
|
||||
switch layer := layer.(type) {
|
||||
case *diskLayer:
|
||||
|
||||
layer.lock.RLock()
|
||||
generating := layer.genMarker != nil
|
||||
layer.lock.RUnlock()
|
||||
if !generating {
|
||||
// Generator is already aborted or finished
|
||||
break
|
||||
}
|
||||
// If the base layer is generating, abort it
|
||||
if layer.genAbort != nil {
|
||||
abort := make(chan *generatorStats)
|
||||
layer.genAbort <- abort
|
||||
<-abort
|
||||
}
|
||||
// Layer should be inactive now, mark it as stale
|
||||
layer.lock.Lock()
|
||||
layer.stale = true
|
||||
layer.lock.Unlock()
|
||||
// TODO this function will hang if it's called twice. Will
|
||||
// fix it in the following PRs.
|
||||
layer.stopGeneration()
|
||||
layer.markStale()
|
||||
layer.Release()
|
||||
|
||||
case *diffLayer:
|
||||
// If the layer is a simple diff, simply mark as stale
|
||||
|
|
@ -768,16 +755,11 @@ func (t *Tree) Rebuild(root common.Hash) {
|
|||
for _, layer := range t.layers {
|
||||
switch layer := layer.(type) {
|
||||
case *diskLayer:
|
||||
// If the base layer is generating, abort it and save
|
||||
if layer.genAbort != nil {
|
||||
abort := make(chan *generatorStats)
|
||||
layer.genAbort <- abort
|
||||
<-abort
|
||||
}
|
||||
// Layer should be inactive now, mark it as stale
|
||||
layer.lock.Lock()
|
||||
layer.stale = true
|
||||
layer.lock.Unlock()
|
||||
// TODO this function will hang if it's called twice. Will
|
||||
// fix it in the following PRs.
|
||||
layer.stopGeneration()
|
||||
layer.markStale()
|
||||
layer.Release()
|
||||
|
||||
case *diffLayer:
|
||||
// If the layer is a simple diff, simply mark as stale
|
||||
|
|
|
|||
|
|
@ -117,15 +117,7 @@ func (s *stateObject) markSelfdestructed() {
|
|||
}
|
||||
|
||||
func (s *stateObject) touch() {
|
||||
s.db.journal.append(touchChange{
|
||||
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)
|
||||
}
|
||||
s.db.journal.touchChange(s.address)
|
||||
}
|
||||
|
||||
// getTrie returns the associated storage trie. The trie will be opened if it's
|
||||
|
|
@ -155,7 +147,7 @@ func (s *stateObject) getTrie() (Trie, error) {
|
|||
func (s *stateObject) getPrefetchedTrie() Trie {
|
||||
// If there's nothing to meaningfully return, let the user figure it out by
|
||||
// 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
|
||||
}
|
||||
// Attempt to retrieve the trie from the prefetcher
|
||||
|
|
@ -203,46 +195,17 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
|
|||
s.originStorage[key] = common.Hash{} // track the empty slot as origin value
|
||||
return common.Hash{}
|
||||
}
|
||||
// If no live objects are available, attempt to use snapshots
|
||||
var (
|
||||
enc []byte
|
||||
err error
|
||||
value common.Hash
|
||||
)
|
||||
s.db.StorageLoaded++
|
||||
|
||||
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()
|
||||
tr, err := s.getTrie()
|
||||
value, err := s.db.reader.Storage(s.address, key)
|
||||
if err != nil {
|
||||
s.db.setError(err)
|
||||
return common.Hash{}
|
||||
}
|
||||
val, err := tr.GetStorage(s.address, key.Bytes())
|
||||
s.db.StorageReads += time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
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.
|
||||
// Schedule the resolved storage slots for prefetching if it's enabled.
|
||||
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 {
|
||||
log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err)
|
||||
|
|
@ -262,16 +225,11 @@ func (s *stateObject) SetState(key, value common.Hash) {
|
|||
return
|
||||
}
|
||||
// New value is different, update and journal the change
|
||||
s.db.journal.append(storageChange{
|
||||
account: &s.address,
|
||||
key: key,
|
||||
prevvalue: prev,
|
||||
origvalue: origin,
|
||||
})
|
||||
s.db.journal.storageChange(s.address, key, prev, origin)
|
||||
s.setState(key, value, origin)
|
||||
if s.db.logger != nil && s.db.logger.OnStorageChange != nil {
|
||||
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
|
||||
|
|
@ -525,10 +483,7 @@ func (s *stateObject) SubBalance(amount *uint256.Int, reason tracing.BalanceChan
|
|||
}
|
||||
|
||||
func (s *stateObject) SetBalance(amount *uint256.Int, reason tracing.BalanceChangeReason) {
|
||||
s.db.journal.append(balanceChange{
|
||||
account: &s.address,
|
||||
prev: new(uint256.Int).Set(s.data.Balance),
|
||||
})
|
||||
s.db.journal.balanceChange(s.address, s.data.Balance)
|
||||
if s.db.logger != nil && s.db.logger.OnBalanceChange != nil {
|
||||
s.db.logger.OnBalanceChange(s.address, s.Balance().ToBig(), amount.ToBig(), reason)
|
||||
}
|
||||
|
|
@ -556,7 +511,7 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
|
|||
newContract: s.newContract,
|
||||
}
|
||||
if s.trie != nil {
|
||||
obj.trie = db.db.CopyTrie(s.trie)
|
||||
obj.trie = mustCopyTrie(s.trie)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
|
@ -609,14 +564,10 @@ func (s *stateObject) CodeSize() int {
|
|||
}
|
||||
|
||||
func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
|
||||
prevcode := s.Code()
|
||||
s.db.journal.append(codeChange{
|
||||
account: &s.address,
|
||||
prevhash: s.CodeHash(),
|
||||
prevcode: prevcode,
|
||||
})
|
||||
s.db.journal.setCode(s.address)
|
||||
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)
|
||||
}
|
||||
|
|
@ -628,10 +579,7 @@ func (s *stateObject) setCode(codeHash common.Hash, code []byte) {
|
|||
}
|
||||
|
||||
func (s *stateObject) SetNonce(nonce uint64) {
|
||||
s.db.journal.append(nonceChange{
|
||||
account: &s.address,
|
||||
prev: s.data.Nonce,
|
||||
})
|
||||
s.db.journal.nonceChange(s.address, s.data.Nonce)
|
||||
if s.db.logger != nil && s.db.logger.OnNonceChange != nil {
|
||||
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/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type stateEnv struct {
|
||||
db ethdb.Database
|
||||
state *StateDB
|
||||
}
|
||||
|
||||
func newStateEnv() *stateEnv {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
sdb, _ := New(types.EmptyRootHash, NewDatabase(db), nil)
|
||||
return &stateEnv{db: db, state: sdb}
|
||||
sdb, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||
return &stateEnv{state: sdb}
|
||||
}
|
||||
|
||||
func TestDump(t *testing.T) {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
||||
sdb, _ := New(types.EmptyRootHash, tdb, nil)
|
||||
s := &stateEnv{db: db, state: sdb}
|
||||
triedb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
||||
tdb := NewDatabase(triedb, nil)
|
||||
sdb, _ := New(types.EmptyRootHash, tdb)
|
||||
s := &stateEnv{state: sdb}
|
||||
|
||||
// generate a few entries
|
||||
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
||||
|
|
@ -62,7 +60,7 @@ func TestDump(t *testing.T) {
|
|||
root, _ := s.state.Commit(0, false)
|
||||
|
||||
// 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))
|
||||
want := `{
|
||||
"root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2",
|
||||
|
|
@ -101,9 +99,10 @@ func TestDump(t *testing.T) {
|
|||
|
||||
func TestIterativeDump(t *testing.T) {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
||||
sdb, _ := New(types.EmptyRootHash, tdb, nil)
|
||||
s := &stateEnv{db: db, state: sdb}
|
||||
triedb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
||||
tdb := NewDatabase(triedb, nil)
|
||||
sdb, _ := New(types.EmptyRootHash, tdb)
|
||||
s := &stateEnv{state: sdb}
|
||||
|
||||
// generate a few entries
|
||||
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
||||
|
|
@ -119,7 +118,7 @@ func TestIterativeDump(t *testing.T) {
|
|||
s.state.updateStateObject(obj1)
|
||||
s.state.updateStateObject(obj2)
|
||||
root, _ := s.state.Commit(0, false)
|
||||
s.state, _ = New(root, tdb, nil)
|
||||
s.state, _ = New(root, tdb)
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
s.state.IterativeDump(nil, json.NewEncoder(b))
|
||||
|
|
@ -195,7 +194,7 @@ func TestSnapshotEmpty(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"))
|
||||
snap := state.Snapshot()
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import (
|
|||
"maps"
|
||||
"math/big"
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
|
@ -50,11 +49,6 @@ import (
|
|||
// TriesInMemory represents the number of layers that are kept in RAM.
|
||||
const TriesInMemory = 128
|
||||
|
||||
type revision struct {
|
||||
id int
|
||||
journalIndex int
|
||||
}
|
||||
|
||||
type mutationType int
|
||||
|
||||
const (
|
||||
|
|
@ -90,10 +84,8 @@ type StateDB struct {
|
|||
db Database
|
||||
prefetcher *triePrefetcher
|
||||
trie Trie
|
||||
hasher crypto.KeccakState
|
||||
logger *tracing.Hooks
|
||||
snaps *snapshot.Tree // Nil if snapshot is not available
|
||||
snap snapshot.Snapshot // Nil if snapshot is not available
|
||||
reader Reader
|
||||
|
||||
// originalRoot is the pre-state root, before any changes were made.
|
||||
// It will be updated when the Commit is called.
|
||||
|
|
@ -147,6 +139,7 @@ type StateDB struct {
|
|||
|
||||
// Per-transaction access list
|
||||
accessList *accessList
|
||||
accessEvents *AccessEvents
|
||||
|
||||
// Transient storage
|
||||
transientStorage transientStorage
|
||||
|
|
@ -154,13 +147,18 @@ type StateDB struct {
|
|||
// Journal of state modifications. This is the backbone of
|
||||
// Snapshot and RevertToSnapshot.
|
||||
journal *journal
|
||||
validRevisions []revision
|
||||
nextRevisionId int
|
||||
|
||||
// State witness if cross validation is needed
|
||||
witness *stateless.Witness
|
||||
|
||||
// Measurements gathered during execution for debugging purposes
|
||||
|
||||
AccountLoaded int // Number of accounts retrieved from the database during the state transition
|
||||
AccountUpdated int // Number of accounts updated during the state transition
|
||||
AccountDeleted int // Number of accounts deleted during the state transition
|
||||
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
|
||||
AccountReads time.Duration
|
||||
AccountHashes time.Duration
|
||||
AccountUpdates time.Duration
|
||||
|
|
@ -176,25 +174,24 @@ type StateDB struct {
|
|||
|
||||
// Bor metrics
|
||||
BorConsensusTime time.Duration
|
||||
|
||||
AccountUpdated int
|
||||
StorageUpdated atomic.Int64
|
||||
AccountDeleted int
|
||||
StorageDeleted atomic.Int64
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reader, err := db.Reader(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sdb := &StateDB{
|
||||
db: db,
|
||||
trie: tr,
|
||||
originalRoot: root,
|
||||
snaps: snaps,
|
||||
reader: reader,
|
||||
stateObjects: make(map[common.Address]*stateObject),
|
||||
revertedKeys: make(map[blockstm.Key]struct{}),
|
||||
stateObjectsDestruct: make(map[common.Address]*stateObject),
|
||||
|
|
@ -204,17 +201,16 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
|
|||
journal: newJournal(),
|
||||
accessList: newAccessList(),
|
||||
transientStorage: newTransientStorage(),
|
||||
hasher: crypto.NewKeccakState(),
|
||||
}
|
||||
if sdb.snaps != nil {
|
||||
sdb.snap = sdb.snaps.Snapshot(root)
|
||||
if db.TrieDB().IsVerkle() {
|
||||
sdb.accessEvents = NewAccessEvents(db.PointCache())
|
||||
}
|
||||
|
||||
return sdb, nil
|
||||
}
|
||||
|
||||
func NewWithMVHashmap(root common.Hash, db Database, snaps *snapshot.Tree, mvhm *blockstm.MVHashMap) (*StateDB, error) {
|
||||
if sdb, err := New(root, db, snaps); err != nil {
|
||||
if sdb, err := New(root, db); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
sdb.mvHashmap = mvhm
|
||||
|
|
@ -503,18 +499,11 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) {
|
|||
// commit phase, most of the needed data is already hot.
|
||||
func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) {
|
||||
// Terminate any previously running prefetcher
|
||||
if s.prefetcher != nil {
|
||||
s.prefetcher.terminate(false)
|
||||
s.prefetcher.report()
|
||||
s.prefetcher = nil
|
||||
}
|
||||
s.StopPrefetcher()
|
||||
|
||||
// Enable witness collection if requested
|
||||
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
|
||||
// rewards are now handled at the consensus layer. Consequently, a block may
|
||||
// have no state transitions if it contains no transactions and no withdrawals.
|
||||
|
|
@ -524,11 +513,11 @@ func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness)
|
|||
// To prevent this, the account trie is always scheduled for prefetching once
|
||||
// the prefetcher is constructed. For more details, see:
|
||||
// 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 {
|
||||
log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StopPrefetcher terminates a running prefetcher and reports any leftover stats
|
||||
// from the gathered metrics.
|
||||
|
|
@ -553,7 +542,7 @@ func (s *StateDB) Error() error {
|
|||
}
|
||||
|
||||
func (s *StateDB) AddLog(log *types.Log) {
|
||||
s.journal.append(addLogChange{txhash: s.thash})
|
||||
s.journal.logChange(s.thash)
|
||||
|
||||
log.TxHash = s.thash
|
||||
log.TxIndex = uint(s.txIndex)
|
||||
|
|
@ -589,7 +578,6 @@ func (s *StateDB) Logs() []*types.Log {
|
|||
// AddPreimage records a SHA3 preimage seen by the VM.
|
||||
func (s *StateDB) AddPreimage(hash common.Hash, preimage []byte) {
|
||||
if _, ok := s.preimages[hash]; !ok {
|
||||
s.journal.append(addPreimageChange{hash: hash})
|
||||
s.preimages[hash] = slices.Clone(preimage)
|
||||
}
|
||||
}
|
||||
|
|
@ -601,15 +589,14 @@ func (s *StateDB) Preimages() map[common.Hash][]byte {
|
|||
|
||||
// AddRefund adds gas to the refund counter
|
||||
func (s *StateDB) AddRefund(gas uint64) {
|
||||
s.journal.append(refundChange{prev: s.refund})
|
||||
s.journal.refundChange(s.refund)
|
||||
s.refund += gas
|
||||
}
|
||||
|
||||
// SubRefund removes gas from the refund counter.
|
||||
// This method will panic if the refund counter goes below zero
|
||||
func (s *StateDB) SubRefund(gas uint64) {
|
||||
s.journal.append(refundChange{prev: s.refund})
|
||||
|
||||
s.journal.refundChange(s.refund)
|
||||
if gas > s.refund {
|
||||
panic(fmt.Sprintf("Refund counter below zero (gas: %d > refund: %d)", gas, s.refund))
|
||||
}
|
||||
|
|
@ -892,24 +879,19 @@ func (s *StateDB) SelfDestruct(addr common.Address) {
|
|||
if stateObject == nil {
|
||||
return
|
||||
}
|
||||
|
||||
stateObject = s.mvRecordWritten(stateObject)
|
||||
var (
|
||||
prev = new(uint256.Int).Set(stateObject.Balance())
|
||||
n = new(uint256.Int)
|
||||
)
|
||||
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)
|
||||
|
||||
// Regardless of whether it is already destructed or not, we do have to
|
||||
// journal the balance-change, if we set it to zero here.
|
||||
if !stateObject.Balance().IsZero() {
|
||||
stateObject.SetBalance(new(uint256.Int), 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.data.Balance = n
|
||||
|
||||
}
|
||||
MVWrite(s, blockstm.NewSubpathKey(addr, SuicidePath))
|
||||
MVWrite(s, blockstm.NewSubpathKey(addr, BalancePath))
|
||||
}
|
||||
|
|
@ -932,12 +914,7 @@ func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash)
|
|||
if prev == value {
|
||||
return
|
||||
}
|
||||
|
||||
s.journal.append(transientStorageChange{
|
||||
account: &addr,
|
||||
key: key,
|
||||
prevalue: prev,
|
||||
})
|
||||
s.journal.transientStateChange(addr, key, prev)
|
||||
s.setTransientState(addr, key, value)
|
||||
}
|
||||
|
||||
|
|
@ -960,7 +937,7 @@ func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common
|
|||
func (s *StateDB) updateStateObject(obj *stateObject) {
|
||||
// Encode the account and update the account trie
|
||||
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))
|
||||
}
|
||||
if obj.dirtyCode {
|
||||
|
|
@ -993,45 +970,19 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
|||
if _, ok := s.stateObjectsDestruct[addr]; ok {
|
||||
return nil
|
||||
}
|
||||
// If no live objects are available, attempt to use snapshots
|
||||
var data *types.StateAccount
|
||||
if s.snap != nil {
|
||||
start := time.Now()
|
||||
acc, err := s.snap.Account(crypto.HashData(crypto.NewKeccakState(), addr.Bytes()))
|
||||
s.SnapshotAccountReads += time.Since(start)
|
||||
if err == nil {
|
||||
if acc == 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.AccountLoaded++
|
||||
|
||||
start := time.Now()
|
||||
acct, err := s.reader.Account(addr)
|
||||
if err != nil {
|
||||
s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %w", addr.Bytes(), err))
|
||||
s.setError(fmt.Errorf("getStateObject (%x) error: %w", addr.Bytes(), err))
|
||||
return nil
|
||||
}
|
||||
if data == nil {
|
||||
s.AccountReads += time.Since(start)
|
||||
// Short circuit if the account is not found
|
||||
if acct == nil {
|
||||
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.
|
||||
|
|
@ -1041,7 +992,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
|||
}
|
||||
}
|
||||
// Insert into the live set
|
||||
obj := newObject(s, addr, data)
|
||||
obj := newObject(s, addr, acct)
|
||||
s.setStateObject(obj)
|
||||
return obj
|
||||
})
|
||||
|
|
@ -1091,7 +1042,7 @@ func (s *StateDB) mvRecordWritten(object *stateObject) *stateObject {
|
|||
// existing account with the given address, otherwise it will be silently overwritten.
|
||||
func (s *StateDB) createObject(addr common.Address) *stateObject {
|
||||
obj := newObject(s, addr, nil)
|
||||
s.journal.append(createObjectChange{account: &addr})
|
||||
s.journal.createObject(addr)
|
||||
s.setStateObject(obj)
|
||||
MVWrite(s, blockstm.NewAddressKey(addr))
|
||||
return obj
|
||||
|
|
@ -1117,7 +1068,7 @@ func (s *StateDB) CreateContract(addr common.Address) {
|
|||
}
|
||||
if !obj.newContract {
|
||||
obj.newContract = true
|
||||
s.journal.append(createContractChange{account: addr})
|
||||
s.journal.createContract(addr)
|
||||
}
|
||||
|
||||
MVWrite(s, blockstm.NewAddressKey(addr))
|
||||
|
|
@ -1129,8 +1080,8 @@ func (s *StateDB) Copy() *StateDB {
|
|||
// Copy all the basic fields, initialize the memory ones
|
||||
state := &StateDB{
|
||||
db: s.db,
|
||||
trie: s.db.CopyTrie(s.trie),
|
||||
hasher: crypto.NewKeccakState(),
|
||||
trie: mustCopyTrie(s.trie),
|
||||
reader: s.reader.Copy(),
|
||||
originalRoot: s.originalRoot,
|
||||
stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)),
|
||||
stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)),
|
||||
|
|
@ -1143,20 +1094,23 @@ func (s *StateDB) Copy() *StateDB {
|
|||
logs: make(map[common.Hash][]*types.Log, len(s.logs)),
|
||||
logSize: s.logSize,
|
||||
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
|
||||
// to the snapshot tree, we need to copy that as well. Otherwise, any
|
||||
// block mined by ourselves will cause gaps in the tree, and force the
|
||||
// miner to operate trie-backed only.
|
||||
snaps: s.snaps,
|
||||
snap: s.snap,
|
||||
// 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.
|
||||
accessList: s.accessList.Copy(),
|
||||
transientStorage: s.transientStorage.Copy(),
|
||||
journal: s.journal.copy(),
|
||||
}
|
||||
if s.witness != nil {
|
||||
state.witness = s.witness.Copy()
|
||||
}
|
||||
if s.accessEvents != nil {
|
||||
state.accessEvents = s.accessEvents.Copy()
|
||||
}
|
||||
// Deep copy cached state objects.
|
||||
for addr, obj := range s.stateObjects {
|
||||
state.stateObjects[addr] = obj.deepCopy(state)
|
||||
|
|
@ -1201,28 +1155,12 @@ func (s *StateDB) Copy() *StateDB {
|
|||
|
||||
// Snapshot returns an identifier for the current revision of the state.
|
||||
func (s *StateDB) Snapshot() int {
|
||||
id := s.nextRevisionId
|
||||
s.nextRevisionId++
|
||||
s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()})
|
||||
|
||||
return id
|
||||
return s.journal.snapshot()
|
||||
}
|
||||
|
||||
// RevertToSnapshot reverts all state changes made since the given revision.
|
||||
func (s *StateDB) RevertToSnapshot(revid int) {
|
||||
// Find the snapshot in the stack of valid snapshots.
|
||||
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]
|
||||
s.journal.revertToSnapshot(revid, s)
|
||||
}
|
||||
|
||||
// GetRefund returns the current value of the refund counter.
|
||||
|
|
@ -1332,8 +1270,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
|||
return nil
|
||||
})
|
||||
}
|
||||
// If witness building is enabled, gather all the read-only accesses
|
||||
if s.witness != nil {
|
||||
// If witness building is enabled, gather all the read-only accesses.
|
||||
// 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
|
||||
for _, obj := range s.stateObjectsDestruct {
|
||||
// Skip any objects that haven't touched their storage
|
||||
|
|
@ -1374,7 +1314,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
|||
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
|
||||
// here could result in losing uncommitted changes from storage.
|
||||
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 {
|
||||
log.Error("Failed to retrieve account pre-fetcher trie")
|
||||
} else {
|
||||
|
|
@ -1440,20 +1380,16 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
|
|||
}
|
||||
|
||||
func (s *StateDB) clearJournalAndRefund() {
|
||||
if len(s.journal.entries) > 0 {
|
||||
s.journal = newJournal()
|
||||
s.journal.reset()
|
||||
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
|
||||
// of a specific account. It leverages the associated state snapshot for fast
|
||||
// storage iteration and constructs trie node deletion markers by creating
|
||||
// stack trie with iterated slots.
|
||||
func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||
iter, err := s.snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{})
|
||||
func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||
iter, err := snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -1531,10 +1467,11 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root
|
|||
// The fast approach can be failed if the snapshot is not fully
|
||||
// generated, or it's internally corrupted. Fallback to the slow
|
||||
// one just in case.
|
||||
if s.snap != nil {
|
||||
slots, nodes, err = s.fastDeleteStorage(addrHash, root)
|
||||
snaps := s.db.Snapshot()
|
||||
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)
|
||||
}
|
||||
if err != nil {
|
||||
|
|
@ -1738,6 +1675,8 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
|
|||
if err := workers.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accountReadMeters.Mark(int64(s.AccountLoaded))
|
||||
storageReadMeters.Mark(int64(s.StorageLoaded))
|
||||
accountUpdatedMeter.Mark(int64(s.AccountUpdated))
|
||||
storageUpdatedMeter.Mark(s.StorageUpdated.Load())
|
||||
accountDeletedMeter.Mark(int64(s.AccountDeleted))
|
||||
|
|
@ -1746,7 +1685,10 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
|
|||
accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted))
|
||||
storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated))
|
||||
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.StorageDeleted.Store(0)
|
||||
|
||||
|
|
@ -1767,7 +1709,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU
|
|||
return nil, err
|
||||
}
|
||||
// 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()
|
||||
for _, code := range ret.codes {
|
||||
rawdb.WriteCode(batch, code.hash, code.blob)
|
||||
|
|
@ -1778,18 +1720,16 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU
|
|||
}
|
||||
if !ret.empty() {
|
||||
// If snapshotting is enabled, update the snapshot tree with this new version
|
||||
if s.snap != nil {
|
||||
s.snap = nil
|
||||
|
||||
if snap := s.db.Snapshot(); snap != nil && snap.Snapshot(ret.originRoot) != nil {
|
||||
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)
|
||||
}
|
||||
// Keep 128 diff layers in the memory, persistent layer is 129th.
|
||||
// - head layer is paired with HEAD state
|
||||
// - head-1 layer is paired with HEAD-1 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)
|
||||
}
|
||||
s.SnapshotCommits += time.Since(start)
|
||||
|
|
@ -1804,6 +1744,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU
|
|||
s.TrieDBCommits += time.Since(start)
|
||||
}
|
||||
}
|
||||
s.reader, _ = s.db.Reader(s.originalRoot)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
|
|
@ -1875,7 +1816,7 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d
|
|||
// AddAddressToAccessList adds the given address to the access list
|
||||
func (s *StateDB) AddAddressToAccessList(addr common.Address) {
|
||||
if s.accessList.AddAddress(addr) {
|
||||
s.journal.append(accessListAddAccountChange{&addr})
|
||||
s.journal.accessListAddAccount(addr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1887,14 +1828,11 @@ func (s *StateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) {
|
|||
// scope of 'address' without having the 'address' become already added
|
||||
// to the access list (via call-variant, create, etc).
|
||||
// Better safe than sorry, though
|
||||
s.journal.append(accessListAddAccountChange{&addr})
|
||||
s.journal.accessListAddAccount(addr)
|
||||
}
|
||||
|
||||
if slotMod {
|
||||
s.journal.append(accessListAddSlotChange{
|
||||
address: &addr,
|
||||
slot: &slot,
|
||||
})
|
||||
s.journal.accessListAddSlot(addr, slot)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1960,6 +1898,7 @@ func (s *StateDB) markUpdate(addr common.Address) {
|
|||
s.mutations[addr].typ = update
|
||||
}
|
||||
|
||||
// PointCache returns the point cache used by verkle tree.
|
||||
func (s *StateDB) PointCache() *utils.PointCache {
|
||||
return s.db.PointCache()
|
||||
}
|
||||
|
|
@ -1968,3 +1907,7 @@ func (s *StateDB) PointCache() *utils.PointCache {
|
|||
func (s *StateDB) Witness() *stateless.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),
|
||||
},
|
||||
{
|
||||
name: "SetState",
|
||||
name: "SetStorage",
|
||||
fn: func(a testAction, s *StateDB) {
|
||||
var key, val common.Hash
|
||||
binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
|
||||
|
|
@ -197,7 +197,6 @@ func (test *stateTest) run() bool {
|
|||
}
|
||||
disk = rawdb.NewMemoryDatabase()
|
||||
tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults})
|
||||
sdb = NewDatabaseWithNodeDB(disk, tdb)
|
||||
byzantium = rand.Intn(2) == 0
|
||||
)
|
||||
defer disk.Close()
|
||||
|
|
@ -217,7 +216,7 @@ func (test *stateTest) run() bool {
|
|||
if i != 0 {
|
||||
root = roots[len(roots)-1]
|
||||
}
|
||||
state, err := New(root, sdb, snaps)
|
||||
state, err := New(root, NewDatabase(tdb, snaps))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package state
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math"
|
||||
|
|
@ -57,8 +56,9 @@ func TestUpdateLeaks(t *testing.T) {
|
|||
var (
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
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
|
||||
for i := byte(0); i < 255; i++ {
|
||||
|
|
@ -96,8 +96,8 @@ func TestIntermediateLeaks(t *testing.T) {
|
|||
finalDb := rawdb.NewMemoryDatabase()
|
||||
transNdb := triedb.NewDatabase(transDb, nil)
|
||||
finalNdb := triedb.NewDatabase(finalDb, nil)
|
||||
transState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(transDb, transNdb), nil)
|
||||
finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil)
|
||||
transState, _ := New(types.EmptyRootHash, NewDatabase(transNdb, nil))
|
||||
finalState, _ := New(types.EmptyRootHash, NewDatabase(finalNdb, nil))
|
||||
|
||||
modify := func(state *StateDB, addr common.Address, i, tweak byte) {
|
||||
state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak)), tracing.BalanceChangeUnspecified)
|
||||
|
|
@ -178,7 +178,7 @@ func TestIntermediateLeaks(t *testing.T) {
|
|||
// https://github.com/ethereum/go-ethereum/pull/15549.
|
||||
func TestCopy(t *testing.T) {
|
||||
// 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++ {
|
||||
obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
|
|
@ -246,8 +246,8 @@ func TestCopy(t *testing.T) {
|
|||
// TestCopyWithDirtyJournal tests if Copy can correct create a equal copied
|
||||
// stateDB with dirty journal present.
|
||||
func TestCopyWithDirtyJournal(t *testing.T) {
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
orig, _ := New(types.EmptyRootHash, db, nil)
|
||||
db := NewDatabaseForTesting()
|
||||
orig, _ := New(types.EmptyRootHash, db)
|
||||
|
||||
// Fill up the initial states
|
||||
for i := byte(0); i < 255; i++ {
|
||||
|
|
@ -257,7 +257,7 @@ func TestCopyWithDirtyJournal(t *testing.T) {
|
|||
orig.updateStateObject(obj)
|
||||
}
|
||||
root, _ := orig.Commit(0, true)
|
||||
orig, _ = New(root, db, nil)
|
||||
orig, _ = New(root, db)
|
||||
|
||||
// modify all in memory without finalizing
|
||||
for i := byte(0); i < 255; i++ {
|
||||
|
|
@ -290,8 +290,8 @@ func TestCopyWithDirtyJournal(t *testing.T) {
|
|||
// 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
|
||||
func TestCopyObjectState(t *testing.T) {
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
orig, _ := New(types.EmptyRootHash, db, nil)
|
||||
db := NewDatabaseForTesting()
|
||||
orig, _ := New(types.EmptyRootHash, db)
|
||||
|
||||
// Fill up the initial states
|
||||
for i := byte(0); i < 5; i++ {
|
||||
|
|
@ -377,7 +377,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
|||
args: make([]int64, 1),
|
||||
},
|
||||
{
|
||||
name: "SetState",
|
||||
name: "SetStorage",
|
||||
fn: func(a testAction, s *StateDB) {
|
||||
var key, val common.Hash
|
||||
binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
|
||||
|
|
@ -389,6 +389,12 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
|||
{
|
||||
name: "SetCode",
|
||||
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)
|
||||
binary.BigEndian.PutUint64(code, uint64(a.args[0]))
|
||||
binary.BigEndian.PutUint64(code[8:], uint64(a.args[1]))
|
||||
|
|
@ -551,7 +557,7 @@ func (test *snapshotTest) String() string {
|
|||
func (test *snapshotTest) run() bool {
|
||||
// Run all actions and create snapshots.
|
||||
var (
|
||||
state, _ = New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
state, _ = New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||
snapshotRevs = make([]int, len(test.snapshots))
|
||||
sindex = 0
|
||||
checkstates = make([]*StateDB, len(test.snapshots))
|
||||
|
|
@ -730,7 +736,7 @@ func TestTouchDelete(t *testing.T) {
|
|||
s := newStateEnv()
|
||||
s.state.getOrNewStateObject(common.Address{})
|
||||
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()
|
||||
s.state.AddBalance(common.Address{}, new(uint256.Int), tracing.BalanceChangeUnspecified)
|
||||
|
|
@ -749,7 +755,7 @@ func TestTouchDelete(t *testing.T) {
|
|||
func TestMVHashMapReadWriteDelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
db := NewDatabaseForTesting()
|
||||
mvhm := blockstm.MakeMVHashMap()
|
||||
s, _ := NewWithMVHashmap(common.Hash{}, db, nil, mvhm)
|
||||
|
||||
|
|
@ -816,7 +822,7 @@ func TestMVHashMapReadWriteDelete(t *testing.T) {
|
|||
func TestMVHashMapCreateContract(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
db := NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.HashDefaults), nil)
|
||||
mvhm := blockstm.MakeMVHashMap()
|
||||
s, _ := NewWithMVHashmap(common.Hash{}, db, nil, mvhm)
|
||||
|
||||
|
|
@ -843,7 +849,7 @@ func TestMVHashMapCreateContract(t *testing.T) {
|
|||
func TestMVHashMapRevert(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
db := NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.HashDefaults), nil)
|
||||
mvhm := blockstm.MakeMVHashMap()
|
||||
s, _ := NewWithMVHashmap(common.Hash{}, db, nil, mvhm)
|
||||
|
||||
|
|
@ -899,7 +905,7 @@ func TestMVHashMapRevert(t *testing.T) {
|
|||
func TestMVHashMapMarkEstimate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
db := NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.HashDefaults), nil)
|
||||
mvhm := blockstm.MakeMVHashMap()
|
||||
s, _ := NewWithMVHashmap(common.Hash{}, db, nil, mvhm)
|
||||
|
||||
|
|
@ -965,7 +971,7 @@ func TestMVHashMapMarkEstimate(t *testing.T) {
|
|||
func TestMVHashMapOverwrite(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
db := NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.HashDefaults), nil)
|
||||
mvhm := blockstm.MakeMVHashMap()
|
||||
s, _ := NewWithMVHashmap(common.Hash{}, db, nil, mvhm)
|
||||
|
||||
|
|
@ -1047,7 +1053,7 @@ func TestMVHashMapOverwrite(t *testing.T) {
|
|||
func TestMVHashMapWriteNoConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
db := NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.HashDefaults), nil)
|
||||
mvhm := blockstm.MakeMVHashMap()
|
||||
s, _ := NewWithMVHashmap(common.Hash{}, db, nil, mvhm)
|
||||
|
||||
|
|
@ -1132,7 +1138,7 @@ func TestMVHashMapWriteNoConflict(t *testing.T) {
|
|||
func TestApplyMVWriteSet(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
db := NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.HashDefaults), nil)
|
||||
mvhm := blockstm.MakeMVHashMap()
|
||||
s, _ := NewWithMVHashmap(common.Hash{}, db, nil, mvhm)
|
||||
|
||||
|
|
@ -1227,7 +1233,7 @@ func TestApplyMVWriteSet(t *testing.T) {
|
|||
func TestMVHashMapRevertConcurrent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
db := NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.HashDefaults), nil)
|
||||
mvhm := blockstm.MakeMVHashMap()
|
||||
s, _ := NewWithMVHashmap(common.Hash{}, db, nil, mvhm)
|
||||
|
||||
|
|
@ -1283,7 +1289,7 @@ func TestMVHashMapRevertConcurrent(t *testing.T) {
|
|||
// 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
|
||||
func TestCopyOfCopy(t *testing.T) {
|
||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
state, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
||||
addr := common.HexToAddress("aaaa")
|
||||
state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified)
|
||||
|
||||
|
|
@ -1301,8 +1307,8 @@ func TestCopyOfCopy(t *testing.T) {
|
|||
//
|
||||
// See https://github.com/ethereum/go-ethereum/issues/20106.
|
||||
func TestCopyCommitCopy(t *testing.T) {
|
||||
tdb := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
state, _ := New(types.EmptyRootHash, tdb, nil)
|
||||
tdb := NewDatabaseForTesting()
|
||||
state, _ := New(types.EmptyRootHash, tdb)
|
||||
|
||||
// Create an account and check if the retrieved balance is correct
|
||||
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
||||
|
|
@ -1363,7 +1369,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
|||
}
|
||||
// Commit state, ensure states can be loaded from disk
|
||||
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 {
|
||||
t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
|
|
@ -1383,7 +1389,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
|||
//
|
||||
// See https://github.com/ethereum/go-ethereum/issues/20106.
|
||||
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
|
||||
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
||||
|
|
@ -1463,8 +1469,8 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
|||
|
||||
// TestCommitCopy tests the copy from a committed state is not fully functional.
|
||||
func TestCommitCopy(t *testing.T) {
|
||||
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||
state, _ := New(types.EmptyRootHash, db, nil)
|
||||
db := NewDatabaseForTesting()
|
||||
state, _ := New(types.EmptyRootHash, db)
|
||||
|
||||
// Create an account and check if the retrieved balance is correct
|
||||
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
||||
|
|
@ -1489,7 +1495,7 @@ func TestCommitCopy(t *testing.T) {
|
|||
}
|
||||
root, _ := state.Commit(0, true)
|
||||
|
||||
state, _ = New(root, db, nil)
|
||||
state, _ = New(root, db)
|
||||
state.SetState(addr, skey2, sval2)
|
||||
state.Commit(1, true)
|
||||
|
||||
|
|
@ -1502,10 +1508,10 @@ func TestCommitCopy(t *testing.T) {
|
|||
t.Fatalf("unexpected code: have %x", code)
|
||||
}
|
||||
// Miss slots because of non-functional trie after commit
|
||||
if val := copied.GetState(addr, skey1); val != (common.Hash{}) {
|
||||
t.Fatalf("unexpected storage slot: have %x", sval1)
|
||||
if val := copied.GetState(addr, skey1); val != 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)
|
||||
}
|
||||
// Slots cached in the stateDB, available after commit
|
||||
|
|
@ -1515,9 +1521,6 @@ func TestCommitCopy(t *testing.T) {
|
|||
if val := copied.GetCommittedState(addr, skey2); val != sval2 {
|
||||
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
|
||||
|
|
@ -1530,13 +1533,13 @@ func TestCommitCopy(t *testing.T) {
|
|||
// first, but the journal wiped the entire state object on create-revert.
|
||||
func TestDeleteCreateRevert(t *testing.T) {
|
||||
// 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"))
|
||||
state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
|
||||
|
||||
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
|
||||
state.SelfDestruct(addr)
|
||||
|
|
@ -1548,7 +1551,7 @@ func TestDeleteCreateRevert(t *testing.T) {
|
|||
|
||||
// Commit the entire state and make sure we don't crash and have the correct state
|
||||
root, _ = state.Commit(0, true)
|
||||
state, _ = New(root, state.db, state.snaps)
|
||||
state, _ = New(root, state.db)
|
||||
|
||||
if state.getStateObject(addr) != nil {
|
||||
t.Fatalf("self-destructed contract came alive")
|
||||
|
|
@ -1579,10 +1582,10 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
|
|||
CleanCacheSize: 0,
|
||||
}}) // disable caching
|
||||
}
|
||||
db := NewDatabaseWithNodeDB(memDb, tdb)
|
||||
db := NewDatabase(tdb, nil)
|
||||
|
||||
var root common.Hash
|
||||
state, _ := New(types.EmptyRootHash, db, nil)
|
||||
state, _ := New(types.EmptyRootHash, db)
|
||||
addr := common.BytesToAddress([]byte("so"))
|
||||
{
|
||||
state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
|
||||
|
|
@ -1597,7 +1600,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
|
|||
tdb.Commit(root, false)
|
||||
}
|
||||
// Create a new state on the old root
|
||||
state, _ = New(root, db, nil)
|
||||
state, _ = New(root, db)
|
||||
// Now we clear out the memdb
|
||||
it := memDb.NewIterator(nil, nil)
|
||||
for it.Next() {
|
||||
|
|
@ -1631,9 +1634,8 @@ func TestStateDBAccessList(t *testing.T) {
|
|||
return common.HexToHash(a)
|
||||
}
|
||||
|
||||
memDb := rawdb.NewMemoryDatabase()
|
||||
db := NewDatabase(memDb)
|
||||
state, _ := New(types.EmptyRootHash, db, nil)
|
||||
db := NewDatabaseForTesting()
|
||||
state, _ := New(types.EmptyRootHash, db)
|
||||
state.accessList = newAccessList()
|
||||
|
||||
verifyAddrs := func(astrings ...string) {
|
||||
|
|
@ -1832,9 +1834,9 @@ func TestFlushOrderDataLoss(t *testing.T) {
|
|||
// Create a state trie with many accounts and slots
|
||||
var (
|
||||
memdb = rawdb.NewMemoryDatabase()
|
||||
triedb = triedb.NewDatabase(memdb, nil)
|
||||
statedb = NewDatabaseWithNodeDB(memdb, triedb)
|
||||
state, _ = New(types.EmptyRootHash, statedb, nil)
|
||||
tdb = triedb.NewDatabase(memdb, triedb.HashDefaults)
|
||||
statedb = NewDatabase(tdb, nil)
|
||||
state, _ = New(types.EmptyRootHash, statedb)
|
||||
)
|
||||
|
||||
for a := byte(0); a < 10; a++ {
|
||||
|
|
@ -1848,15 +1850,15 @@ func TestFlushOrderDataLoss(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to commit state trie: %v", err)
|
||||
}
|
||||
triedb.Reference(root, common.Hash{})
|
||||
if err := triedb.Cap(1024); err != nil {
|
||||
tdb.Reference(root, common.Hash{})
|
||||
if err := tdb.Cap(1024); err != nil {
|
||||
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)
|
||||
}
|
||||
// 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 {
|
||||
t.Fatalf("failed to reopen state trie: %v", err)
|
||||
}
|
||||
|
|
@ -1873,9 +1875,8 @@ func TestFlushOrderDataLoss(t *testing.T) {
|
|||
func TestStateDBTransientStorage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
memDb := rawdb.NewMemoryDatabase()
|
||||
db := NewDatabase(memDb)
|
||||
state, _ := New(types.EmptyRootHash, db, nil)
|
||||
db := NewDatabaseForTesting()
|
||||
state, _ := New(types.EmptyRootHash, db)
|
||||
|
||||
key := common.Hash{0x01}
|
||||
value := common.Hash{0x02}
|
||||
|
|
@ -1913,9 +1914,9 @@ func TestDeleteStorage(t *testing.T) {
|
|||
var (
|
||||
disk = rawdb.NewMemoryDatabase()
|
||||
tdb = triedb.NewDatabase(disk, nil)
|
||||
db = NewDatabaseWithNodeDB(disk, tdb)
|
||||
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")
|
||||
)
|
||||
// Initialize account and populate storage
|
||||
|
|
@ -1927,9 +1928,10 @@ func TestDeleteStorage(t *testing.T) {
|
|||
state.SetState(addr, slot, value)
|
||||
}
|
||||
root, _ := state.Commit(0, true)
|
||||
|
||||
// Init phase done, create two states, one with snap and one without
|
||||
fastState, _ := New(root, db, snaps)
|
||||
slowState, _ := New(root, db, nil)
|
||||
fastState, _ := New(root, NewDatabase(tdb, snaps))
|
||||
slowState, _ := New(root, NewDatabase(tdb, nil))
|
||||
|
||||
obj := fastState.getOrNewStateObject(addr)
|
||||
storageRoot := obj.data.Root
|
||||
|
|
@ -1967,8 +1969,8 @@ func TestStorageDirtiness(t *testing.T) {
|
|||
var (
|
||||
disk = rawdb.NewMemoryDatabase()
|
||||
tdb = triedb.NewDatabase(disk, nil)
|
||||
db = NewDatabaseWithNodeDB(disk, tdb)
|
||||
state, _ = New(types.EmptyRootHash, db, nil)
|
||||
db = NewDatabase(tdb, nil)
|
||||
state, _ = New(types.EmptyRootHash, db)
|
||||
addr = common.HexToAddress("0x1")
|
||||
checkDirty = func(key common.Hash, value common.Hash, dirty bool) {
|
||||
obj := state.getStateObject(addr)
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, c
|
|||
}
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
nodeDb := triedb.NewDatabase(db, config)
|
||||
sdb := NewDatabaseWithNodeDB(db, nodeDb)
|
||||
state, _ := New(types.EmptyRootHash, sdb, nil)
|
||||
sdb := NewDatabase(nodeDb, nil)
|
||||
state, _ := New(types.EmptyRootHash, sdb)
|
||||
|
||||
// Fill it with some arbitrary data
|
||||
var accounts []*testAccount
|
||||
|
|
@ -96,7 +96,7 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, scheme string, root com
|
|||
config.PathDB = pathdb.Defaults
|
||||
}
|
||||
// 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 {
|
||||
t.Fatalf("failed to create state trie at %x: %v", root, err)
|
||||
}
|
||||
|
|
@ -125,7 +125,7 @@ func checkStateConsistency(db ethdb.Database, scheme string, root common.Hash) e
|
|||
if scheme == rawdb.PathScheme {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ var (
|
|||
//
|
||||
// Note, the prefetcher's API is not thread safe.
|
||||
type triePrefetcher struct {
|
||||
verkle bool // Flag whether the prefetcher is in verkle mode
|
||||
db Database // Database to fetch trie nodes through
|
||||
root common.Hash // Root hash of the account trie for metrics
|
||||
fetchers map[string]*subfetcher // Subfetchers for each trie
|
||||
|
|
@ -68,6 +69,7 @@ type triePrefetcher struct {
|
|||
func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher {
|
||||
prefix := triePrefetchMetricsPrefix + namespace
|
||||
return &triePrefetcher{
|
||||
verkle: db.TrieDB().IsVerkle(),
|
||||
db: db,
|
||||
root: root,
|
||||
fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map
|
||||
|
|
@ -214,12 +216,18 @@ func (p *triePrefetcher) used(owner common.Hash, root common.Hash, used [][]byte
|
|||
|
||||
if fetcher := p.fetchers[p.trieID(owner, root)]; fetcher != nil {
|
||||
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.
|
||||
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)
|
||||
copy(trieID, owner.Bytes())
|
||||
copy(trieID[common.HashLength:], root.Bytes())
|
||||
|
|
@ -339,31 +347,47 @@ func (sf *subfetcher) terminate(async bool) {
|
|||
<-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
|
||||
// when requested.
|
||||
func (sf *subfetcher) loop() {
|
||||
// No matter how the loop stops, signal anyone waiting that it's terminated
|
||||
defer close(sf.term)
|
||||
|
||||
// Start by opening the trie and stop processing if it fails
|
||||
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)
|
||||
if err := sf.openTrie(); err != nil {
|
||||
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 {
|
||||
select {
|
||||
case <-sf.wake:
|
||||
|
|
|
|||
|
|
@ -24,11 +24,14 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"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"
|
||||
)
|
||||
|
||||
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
|
||||
addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
|
||||
|
|
@ -63,3 +66,47 @@ func TestUseAfterTerminate(t *testing.T) {
|
|||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
|
|
@ -90,7 +89,7 @@ func precacheTransaction(msg *Message, _ *params.ChainConfig, gaspool *GasPool,
|
|||
// Update the evm with the new transaction context.
|
||||
evm.Reset(NewEVMTxContext(msg), statedb)
|
||||
// Add addresses to access list if applicable
|
||||
_, err := ApplyMessage(evm, msg, gaspool, context.Background())
|
||||
_, err := ApplyMessage(evm, msg, gaspool)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, hc *HeaderCha
|
|||
// 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
|
||||
// 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, interruptCtx context.Context) (types.Receipts, []*types.Log, uint64, error) {
|
||||
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
|
||||
var (
|
||||
receipts types.Receipts
|
||||
usedGas = new(uint64)
|
||||
|
|
@ -76,57 +76,57 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
var (
|
||||
context vm.BlockContext
|
||||
signer = types.MakeSigner(p.config, header.Number, header.Time)
|
||||
err error
|
||||
)
|
||||
context = NewEVMBlockContext(header, p.hc, nil)
|
||||
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
|
||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
||||
}
|
||||
if p.config.IsPrague(block.Number()) {
|
||||
ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
|
||||
}
|
||||
// Iterate over and process the individual transactions
|
||||
for i, tx := range block.Transactions() {
|
||||
if interruptCtx != nil {
|
||||
select {
|
||||
case <-interruptCtx.Done():
|
||||
return nil, nil, 0, interruptCtx.Err()
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
||||
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)
|
||||
|
||||
receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, interruptCtx)
|
||||
receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
|
||||
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)
|
||||
allLogs = append(allLogs, receipt.Logs...)
|
||||
}
|
||||
// Fail if Shanghai not enabled and len(withdrawals) is non-zero.
|
||||
withdrawals := block.Withdrawals()
|
||||
if !p.config.IsShanghai(block.Number()) && withdrawals != nil {
|
||||
return nil, nil, 0, fmt.Errorf("withdrawals before shanghai")
|
||||
// Read requests if Prague is enabled.
|
||||
var requests types.Requests
|
||||
if p.config.IsPrague(block.Number()) {
|
||||
requests, err = ParseDepositLogs(allLogs, p.config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Bor does not support withdrawals
|
||||
// nolint
|
||||
if withdrawals != nil {
|
||||
withdrawals = nil
|
||||
}
|
||||
|
||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||
p.hc.engine.Finalize(p.bc, 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
|
||||
// and uses the input parameters for its environment similar to ApplyTransaction. However,
|
||||
// this method takes an already created EVM instance as input.
|
||||
func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, interruptCtx context.Context) (receipt *types.Receipt, err error) {
|
||||
func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil {
|
||||
evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||
if evm.Config.Tracer.OnTxEnd != nil {
|
||||
|
|
@ -151,7 +151,7 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
|||
// resume recording read and write
|
||||
statedb.SetMVHashmap(backupMVHashMap)
|
||||
|
||||
result, err = ApplyMessageNoFeeBurnOrTip(evm, *msg, gp, interruptCtx)
|
||||
result, err = ApplyMessageNoFeeBurnOrTip(evm, *msg, gp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -198,9 +198,14 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
|||
|
||||
*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
|
||||
// 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() {
|
||||
receipt.Status = types.ReceiptStatusFailed
|
||||
} else {
|
||||
|
|
@ -216,18 +221,23 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
|||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
|
||||
// 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.
|
||||
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash)
|
||||
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
||||
receipt.BlockHash = blockHash
|
||||
receipt.BlockNumber = blockNumber
|
||||
receipt.TransactionIndex = uint(statedb.TxIndex())
|
||||
|
||||
return receipt, err
|
||||
return receipt
|
||||
}
|
||||
|
||||
// ApplyTransaction attempts to apply a transaction to the given state database
|
||||
|
|
@ -243,17 +253,19 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
|||
blockContext := NewEVMBlockContext(header, bc, author)
|
||||
txContext := NewEVMTxContext(msg)
|
||||
vmenv := vm.NewEVM(blockContext, txContext, statedb, config, cfg)
|
||||
return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv, interruptCtx)
|
||||
return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
|
||||
}
|
||||
|
||||
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
||||
// contract. This method is exported to be used in tests.
|
||||
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
|
||||
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil {
|
||||
vmenv.Config.Tracer.OnSystemCallStart()
|
||||
if tracer := vmenv.Config.Tracer; tracer != nil {
|
||||
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
|
||||
|
|
@ -269,6 +281,49 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
|
|||
}
|
||||
vmenv.Reset(NewEVMTxContext(msg), statedb)
|
||||
statedb.AddAddressToAccessList(params.BeaconRootsAddress)
|
||||
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560, nil)
|
||||
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||
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 (
|
||||
"crypto/ecdsa"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
|
|
@ -31,11 +32,14 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/ethereum/go-verkle"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
|
|
@ -489,13 +493,40 @@ func TestProcessVerkle(t *testing.T) {
|
|||
|
||||
txCost1 := params.TxGas
|
||||
txCost2 := params.TxGas
|
||||
contractCreationCost := intrinsicContractCreationGas + uint64(2039 /* execution costs */)
|
||||
codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + uint64(57444 /* execution costs */)
|
||||
contractCreationCost := intrinsicContractCreationGas +
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* creation with value */
|
||||
739 /* execution costs */
|
||||
codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas +
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (tx) */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at pc=0x20) */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */
|
||||
params.WitnessChunkReadCost + /* SLOAD in constructor */
|
||||
params.WitnessChunkWriteCost + /* SSTORE in constructor */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at PC=0x121) */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */
|
||||
params.WitnessChunkReadCost + /* SLOAD in constructor */
|
||||
params.WitnessChunkWriteCost + /* SSTORE in constructor */
|
||||
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash for tx creation */
|
||||
15*(params.WitnessChunkReadCost+params.WitnessChunkWriteCost) + /* code chunks #0..#14 */
|
||||
4844 /* execution costs */
|
||||
blockGasUsagesExpected := []uint64{
|
||||
txCost1*2 + txCost2,
|
||||
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()
|
||||
|
||||
// TODO need to check that the tx cost provided is the exact amount used (no remaining left-over)
|
||||
|
|
@ -516,7 +547,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)
|
||||
if err != nil {
|
||||
|
|
@ -536,3 +577,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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
|
|
@ -158,10 +157,13 @@ type Message struct {
|
|||
BlobGasFeeCap *big.Int
|
||||
BlobHashes []common.Hash
|
||||
|
||||
// When SkipAccountChecks is true, the message nonce is not checked against the
|
||||
// account nonce in state. It also disables checking that the sender is an EOA.
|
||||
// When SkipNonceChecks is true, the message nonce is not checked against the
|
||||
// account nonce in state.
|
||||
// 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.
|
||||
|
|
@ -176,7 +178,8 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
|
|||
Value: tx.Value(),
|
||||
Data: tx.Data(),
|
||||
AccessList: tx.AccessList(),
|
||||
SkipAccountChecks: false,
|
||||
SkipNonceChecks: false,
|
||||
SkipFromEOACheck: false,
|
||||
BlobHashes: tx.BlobHashes(),
|
||||
BlobGasFeeCap: tx.BlobGasFeeCap(),
|
||||
}
|
||||
|
|
@ -198,15 +201,15 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
|
|||
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
||||
// indicates a core error meaning that the message would always fail for that particular
|
||||
// state and would never be accepted within a block.
|
||||
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool, interruptCtx context.Context) (*ExecutionResult, error) {
|
||||
return NewStateTransition(evm, msg, gp).TransitionDb(interruptCtx)
|
||||
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
||||
return NewStateTransition(evm, msg, gp).TransitionDb()
|
||||
}
|
||||
|
||||
func ApplyMessageNoFeeBurnOrTip(evm *vm.EVM, msg Message, gp *GasPool, interruptCtx context.Context) (*ExecutionResult, error) {
|
||||
func ApplyMessageNoFeeBurnOrTip(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
|
||||
st := NewStateTransition(evm, &msg, gp)
|
||||
st.noFeeBurnAndTip = true
|
||||
|
||||
return st.TransitionDb(interruptCtx)
|
||||
return st.TransitionDb()
|
||||
}
|
||||
|
||||
// StateTransition represents a state transition.
|
||||
|
|
@ -312,7 +315,7 @@ func (st *StateTransition) buyGas() error {
|
|||
func (st *StateTransition) preCheck() error {
|
||||
// Only check transactions that are not fake
|
||||
msg := st.msg
|
||||
if !msg.SkipAccountChecks {
|
||||
if !msg.SkipNonceChecks {
|
||||
// Make sure this transaction's nonce is correct.
|
||||
stNonce := st.state.GetNonce(msg.From)
|
||||
if msgNonce := msg.Nonce; stNonce < msgNonce {
|
||||
|
|
@ -325,6 +328,8 @@ func (st *StateTransition) preCheck() error {
|
|||
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
||||
msg.From.Hex(), stNonce)
|
||||
}
|
||||
}
|
||||
if !msg.SkipFromEOACheck {
|
||||
// Make sure the sender is an EOA
|
||||
codeHash := st.state.GetCodeHash(msg.From)
|
||||
if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash {
|
||||
|
|
@ -404,7 +409,7 @@ func (st *StateTransition) preCheck() error {
|
|||
//
|
||||
// However if any consensus issue encountered, return the error directly with
|
||||
// nil evm execution result.
|
||||
func (st *StateTransition) TransitionDb(interruptCtx context.Context) (*ExecutionResult, error) {
|
||||
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||
input1 := st.state.GetBalance(st.msg.From)
|
||||
|
||||
var input2 *uint256.Int
|
||||
|
|
@ -488,7 +493,7 @@ func (st *StateTransition) TransitionDb(interruptCtx context.Context) (*Executio
|
|||
} else {
|
||||
st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
|
||||
|
||||
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value, interruptCtx)
|
||||
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value)
|
||||
}
|
||||
|
||||
var gasRefund uint64
|
||||
|
|
@ -537,7 +542,7 @@ func (st *StateTransition) TransitionDb(interruptCtx context.Context) (*Executio
|
|||
|
||||
// add the coinbase to the witness iff the fee is greater than 0
|
||||
if rules.IsEIP4762 && amount.Sign() != 0 {
|
||||
st.evm.AccessEvents.BalanceGas(st.evm.Context.Coinbase, true)
|
||||
st.evm.AccessEvents.AddAccount(st.evm.Context.Coinbase, true)
|
||||
}
|
||||
|
||||
output1 := new(big.Int).SetBytes(input1.Bytes())
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
|
|
@ -27,25 +25,33 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
)
|
||||
|
||||
// ExecuteStateless runs a stateless execution based on a witness, verifies
|
||||
// everything it can locally and returns the two computed fields that need the
|
||||
// other side to explicitly check.
|
||||
// everything it can locally and returns the state root and receipt root, that
|
||||
// need the other side to explicitly check.
|
||||
//
|
||||
// This method is a bit of a sore thumb here, but:
|
||||
// - It cannot be placed in core/stateless, because state.New prodces a circular dep
|
||||
// - It cannot be placed outside of core, because it needs to construct a dud headerchain
|
||||
//
|
||||
// TODO(karalabe): Would be nice to resolve both issues above somehow and move it.
|
||||
func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (common.Hash, common.Hash, error) {
|
||||
func ExecuteStateless(config *params.ChainConfig, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, error) {
|
||||
// Sanity check if the supplied block accidentally contains a set root or
|
||||
// receipt hash. If so, be very loud, but still continue.
|
||||
if block.Root() != (common.Hash{}) {
|
||||
log.Error("stateless runner received state root it's expected to calculate (faulty consensus client)", "block", block.Number())
|
||||
}
|
||||
if block.ReceiptHash() != (common.Hash{}) {
|
||||
log.Error("stateless runner received receipt root it's expected to calculate (faulty consensus client)", "block", block.Number())
|
||||
}
|
||||
// Create and populate the state database to serve as the stateless backend
|
||||
memdb := witness.MakeHashDB()
|
||||
|
||||
db, err := state.New(witness.Root(), state.NewDatabaseWithConfig(memdb, triedb.HashDefaults), nil)
|
||||
db, err := state.New(witness.Root(), state.NewDatabase(triedb.NewDatabase(memdb, triedb.HashDefaults), nil))
|
||||
if err != nil {
|
||||
return common.Hash{}, common.Hash{}, err
|
||||
}
|
||||
|
|
@ -60,16 +66,15 @@ func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (c
|
|||
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
||||
|
||||
// Run the stateless blocks processing and self-validate certain fields
|
||||
receipts, _, usedGas, err := processor.Process(witness.Block, db, vm.Config{}, context.Background())
|
||||
res, err := processor.Process(block, db, vm.Config{})
|
||||
if err != nil {
|
||||
return common.Hash{}, common.Hash{}, err
|
||||
}
|
||||
if err = validator.ValidateState(witness.Block, db, receipts, usedGas, true); err != nil {
|
||||
if err = validator.ValidateState(block, db, res, true); err != nil {
|
||||
return common.Hash{}, common.Hash{}, err
|
||||
}
|
||||
// Almost everything validated, but receipt and state root needs to be returned
|
||||
receiptRoot := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
||||
stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number()))
|
||||
|
||||
return receiptRoot, stateRoot, nil
|
||||
receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil))
|
||||
stateRoot := db.IntermediateRoot(config.IsEIP158(block.Number()))
|
||||
return stateRoot, receiptRoot, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@ import (
|
|||
// MakeHashDB imports tries, codes and block hashes from a witness into a new
|
||||
// hash-based memory db. We could eventually rewrite this into a pathdb, but
|
||||
// simple is better for now.
|
||||
//
|
||||
// Note, this hashdb approach is quite strictly self-validating:
|
||||
// - Headers are persisted keyed by hash, so blockhash will error on junk
|
||||
// - Codes are persisted keyed by hash, so bytecode lookup will error on junk
|
||||
// - Trie nodes are persisted keyed by hash, so trie expansion will error on junk
|
||||
//
|
||||
// Acceleration structures built would need to explicitly validate the witness.
|
||||
func (w *Witness) MakeHashDB() ethdb.Database {
|
||||
var (
|
||||
memdb = rawdb.NewMemoryDatabase()
|
||||
|
|
|
|||
|
|
@ -17,42 +17,31 @@
|
|||
package stateless
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type extWitness -field-override extWitnessMarshalling -out gen_encoding_json.go
|
||||
|
||||
// toExtWitness converts our internal witness representation to the consensus one.
|
||||
func (w *Witness) toExtWitness() *extWitness {
|
||||
ext := &extWitness{
|
||||
Block: w.Block,
|
||||
Headers: w.Headers,
|
||||
}
|
||||
ext.Codes = make([][]byte, 0, len(w.Codes))
|
||||
for code := range w.Codes {
|
||||
ext.Codes = append(ext.Codes, []byte(code))
|
||||
}
|
||||
slices.SortFunc(ext.Codes, bytes.Compare)
|
||||
|
||||
ext.State = make([][]byte, 0, len(w.State))
|
||||
for node := range w.State {
|
||||
ext.State = append(ext.State, []byte(node))
|
||||
}
|
||||
slices.SortFunc(ext.State, bytes.Compare)
|
||||
return ext
|
||||
}
|
||||
|
||||
// fromExtWitness converts the consensus witness format into our internal one.
|
||||
func (w *Witness) fromExtWitness(ext *extWitness) error {
|
||||
w.Block, w.Headers = ext.Block, ext.Headers
|
||||
w.Headers = ext.Headers
|
||||
|
||||
w.Codes = make(map[string]struct{}, len(ext.Codes))
|
||||
for _, code := range ext.Codes {
|
||||
|
|
@ -62,12 +51,7 @@ func (w *Witness) fromExtWitness(ext *extWitness) error {
|
|||
for _, node := range ext.State {
|
||||
w.State[string(node)] = struct{}{}
|
||||
}
|
||||
return w.sanitize()
|
||||
}
|
||||
|
||||
// MarshalJSON marshals a witness as JSON.
|
||||
func (w *Witness) MarshalJSON() ([]byte, error) {
|
||||
return w.toExtWitness().MarshalJSON()
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeRLP serializes a witness as RLP.
|
||||
|
|
@ -75,15 +59,6 @@ func (w *Witness) EncodeRLP(wr io.Writer) error {
|
|||
return rlp.Encode(wr, w.toExtWitness())
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (w *Witness) UnmarshalJSON(input []byte) error {
|
||||
var ext extWitness
|
||||
if err := ext.UnmarshalJSON(input); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.fromExtWitness(&ext)
|
||||
}
|
||||
|
||||
// DecodeRLP decodes a witness from RLP.
|
||||
func (w *Witness) DecodeRLP(s *rlp.Stream) error {
|
||||
var ext extWitness
|
||||
|
|
@ -93,37 +68,9 @@ func (w *Witness) DecodeRLP(s *rlp.Stream) error {
|
|||
return w.fromExtWitness(&ext)
|
||||
}
|
||||
|
||||
// sanitize checks for some mandatory fields in the witness after decoding so
|
||||
// the rest of the code can assume invariants and doesn't have to deal with
|
||||
// corrupted data.
|
||||
func (w *Witness) sanitize() error {
|
||||
// Verify that the "parent" header (i.e. index 0) is available, and is the
|
||||
// true parent of the block-to-be executed, since we use that to link the
|
||||
// current block to the pre-state.
|
||||
if len(w.Headers) == 0 {
|
||||
return errors.New("parent header (for pre-root hash) missing")
|
||||
}
|
||||
for i, header := range w.Headers {
|
||||
if header == nil {
|
||||
return fmt.Errorf("witness header nil at position %d", i)
|
||||
}
|
||||
}
|
||||
if w.Headers[0].Hash() != w.Block.ParentHash() {
|
||||
return fmt.Errorf("parent hash different: witness %v, block parent %v", w.Headers[0].Hash(), w.Block.ParentHash())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// extWitness is a witness RLP encoding for transferring across clients.
|
||||
type extWitness struct {
|
||||
Block *types.Block `json:"block" gencodec:"required"`
|
||||
Headers []*types.Header `json:"headers" gencodec:"required"`
|
||||
Codes [][]byte `json:"codes"`
|
||||
State [][]byte `json:"state"`
|
||||
}
|
||||
|
||||
// extWitnessMarshalling defines the hex marshalling types for a witness.
|
||||
type extWitnessMarshalling struct {
|
||||
Codes []hexutil.Bytes
|
||||
State []hexutil.Bytes
|
||||
Headers []*types.Header
|
||||
Codes [][]byte
|
||||
State [][]byte
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package stateless
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
var _ = (*extWitnessMarshalling)(nil)
|
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (e extWitness) MarshalJSON() ([]byte, error) {
|
||||
type extWitness struct {
|
||||
Block *types.Block `json:"block" gencodec:"required"`
|
||||
Headers []*types.Header `json:"headers" gencodec:"required"`
|
||||
Codes []hexutil.Bytes `json:"codes"`
|
||||
State []hexutil.Bytes `json:"state"`
|
||||
}
|
||||
var enc extWitness
|
||||
enc.Block = e.Block
|
||||
enc.Headers = e.Headers
|
||||
if e.Codes != nil {
|
||||
enc.Codes = make([]hexutil.Bytes, len(e.Codes))
|
||||
for k, v := range e.Codes {
|
||||
enc.Codes[k] = v
|
||||
}
|
||||
}
|
||||
if e.State != nil {
|
||||
enc.State = make([]hexutil.Bytes, len(e.State))
|
||||
for k, v := range e.State {
|
||||
enc.State[k] = v
|
||||
}
|
||||
}
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (e *extWitness) UnmarshalJSON(input []byte) error {
|
||||
type extWitness struct {
|
||||
Block *types.Block `json:"block" gencodec:"required"`
|
||||
Headers []*types.Header `json:"headers" gencodec:"required"`
|
||||
Codes []hexutil.Bytes `json:"codes"`
|
||||
State []hexutil.Bytes `json:"state"`
|
||||
}
|
||||
var dec extWitness
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if dec.Block == nil {
|
||||
return errors.New("missing required field 'block' for extWitness")
|
||||
}
|
||||
e.Block = dec.Block
|
||||
if dec.Headers == nil {
|
||||
return errors.New("missing required field 'headers' for extWitness")
|
||||
}
|
||||
e.Headers = dec.Headers
|
||||
if dec.Codes != nil {
|
||||
e.Codes = make([][]byte, len(dec.Codes))
|
||||
for k, v := range dec.Codes {
|
||||
e.Codes[k] = v
|
||||
}
|
||||
}
|
||||
if dec.State != nil {
|
||||
e.State = make([][]byte, len(dec.State))
|
||||
for k, v := range dec.State {
|
||||
e.State[k] = v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -17,16 +17,13 @@
|
|||
package stateless
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// HeaderReader is an interface to pull in headers in place of block hashes for
|
||||
|
|
@ -36,10 +33,11 @@ type HeaderReader interface {
|
|||
GetHeader(hash common.Hash, number uint64) *types.Header
|
||||
}
|
||||
|
||||
// Witness encompasses a block, state and any other chain data required to apply
|
||||
// a set of transactions and derive a post state/receipt root.
|
||||
// Witness encompasses the state required to apply a set of transactions and
|
||||
// derive a post state/receipt root.
|
||||
type Witness struct {
|
||||
Block *types.Block // Current block with rootHash and receiptHash zeroed out
|
||||
context *types.Header // Header to which this witness belongs to, with rootHash and receiptHash zeroed out
|
||||
|
||||
Headers []*types.Header // Past headers in reverse order (0=parent, 1=parent's-parent, etc). First *must* be set.
|
||||
Codes map[string]struct{} // Set of bytecodes ran or accessed
|
||||
State map[string]struct{} // Set of MPT state trie nodes (account and storage together)
|
||||
|
|
@ -49,24 +47,23 @@ type Witness struct {
|
|||
}
|
||||
|
||||
// NewWitness creates an empty witness ready for population.
|
||||
func NewWitness(chain HeaderReader, block *types.Block) (*Witness, error) {
|
||||
// Zero out the result fields to avoid accidentally sending them to the verifier
|
||||
header := block.Header()
|
||||
header.Root = common.Hash{}
|
||||
header.ReceiptHash = common.Hash{}
|
||||
|
||||
// Retrieve the parent header, which will *always* be included to act as a
|
||||
// trustless pre-root hash container
|
||||
parent := chain.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||
func NewWitness(context *types.Header, chain HeaderReader) (*Witness, error) {
|
||||
// When building witnesses, retrieve the parent header, which will *always*
|
||||
// be included to act as a trustless pre-root hash container
|
||||
var headers []*types.Header
|
||||
if chain != nil {
|
||||
parent := chain.GetHeader(context.ParentHash, context.Number.Uint64()-1)
|
||||
if parent == nil {
|
||||
return nil, errors.New("failed to retrieve parent header")
|
||||
}
|
||||
headers = append(headers, parent)
|
||||
}
|
||||
// Create the wtness with a reconstructed gutted out block
|
||||
return &Witness{
|
||||
Block: types.NewBlockWithHeader(header).WithBody(*block.Body()),
|
||||
context: context,
|
||||
Headers: headers,
|
||||
Codes: make(map[string]struct{}),
|
||||
State: make(map[string]struct{}),
|
||||
Headers: []*types.Header{parent},
|
||||
chain: chain,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -76,11 +73,8 @@ func NewWitness(chain HeaderReader, block *types.Block) (*Witness, error) {
|
|||
// the chain to cover the block being added.
|
||||
func (w *Witness) AddBlockHash(number uint64) {
|
||||
// Keep pulling in headers until this hash is populated
|
||||
for int(w.Block.NumberU64()-number) > len(w.Headers) {
|
||||
tail := w.Block.Header()
|
||||
if len(w.Headers) > 0 {
|
||||
tail = w.Headers[len(w.Headers)-1]
|
||||
}
|
||||
for int(w.context.Number.Uint64()-number) > len(w.Headers) {
|
||||
tail := w.Headers[len(w.Headers)-1]
|
||||
w.Headers = append(w.Headers, w.chain.GetHeader(tail.ParentHash, tail.Number.Uint64()-1))
|
||||
}
|
||||
}
|
||||
|
|
@ -101,53 +95,22 @@ func (w *Witness) AddState(nodes map[string]struct{}) {
|
|||
w.lock.Lock()
|
||||
defer w.lock.Unlock()
|
||||
|
||||
for node := range nodes {
|
||||
w.State[node] = struct{}{}
|
||||
}
|
||||
maps.Copy(w.State, nodes)
|
||||
}
|
||||
|
||||
// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it
|
||||
// is never mutated by Witness
|
||||
func (w *Witness) Copy() *Witness {
|
||||
return &Witness{
|
||||
Block: w.Block,
|
||||
cpy := &Witness{
|
||||
Headers: slices.Clone(w.Headers),
|
||||
Codes: maps.Clone(w.Codes),
|
||||
State: maps.Clone(w.State),
|
||||
chain: w.chain,
|
||||
}
|
||||
if w.context != nil {
|
||||
cpy.context = types.CopyHeader(w.context)
|
||||
}
|
||||
|
||||
// String prints a human-readable summary containing the total size of the
|
||||
// witness and the sizes of the underlying components
|
||||
func (w *Witness) String() string {
|
||||
blob, _ := rlp.EncodeToBytes(w)
|
||||
bytesTotal := len(blob)
|
||||
|
||||
blob, _ = rlp.EncodeToBytes(w.Block)
|
||||
bytesBlock := len(blob)
|
||||
|
||||
bytesHeaders := 0
|
||||
for _, header := range w.Headers {
|
||||
blob, _ = rlp.EncodeToBytes(header)
|
||||
bytesHeaders += len(blob)
|
||||
}
|
||||
bytesCodes := 0
|
||||
for code := range w.Codes {
|
||||
bytesCodes += len(code)
|
||||
}
|
||||
bytesState := 0
|
||||
for node := range w.State {
|
||||
bytesState += len(node)
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
fmt.Fprintf(buf, "Witness #%d: %v\n", w.Block.Number(), common.StorageSize(bytesTotal))
|
||||
fmt.Fprintf(buf, " block (%4d txs): %10v\n", len(w.Block.Transactions()), common.StorageSize(bytesBlock))
|
||||
fmt.Fprintf(buf, "%4d headers: %10v\n", len(w.Headers), common.StorageSize(bytesHeaders))
|
||||
fmt.Fprintf(buf, "%4d trie nodes: %10v\n", len(w.State), common.StorageSize(bytesState))
|
||||
fmt.Fprintf(buf, "%4d codes: %10v\n", len(w.Codes), common.StorageSize(bytesCodes))
|
||||
|
||||
return buf.String()
|
||||
return cpy
|
||||
}
|
||||
|
||||
// Root returns the pre-state root from the first header.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,24 @@
|
|||
|
||||
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]
|
||||
|
||||
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.
|
||||
- `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.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
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue