1cb3b6aee4
This change addresses an issue in snap sync, specifically when the entire sync process can be halted due to an encountered empty storage range. Currently, on the snap sync client side, the response to an empty (partial) storage range is discarded as a non-delivery. However, this response can be a valid response, when the particular range requested does not contain any slots. For instance, consider a large contract where the entire key space is divided into 16 chunks, and there are no available slots in the last chunk [0xf] -> [end]. When the node receives a request for this particular range, the response includes: The proof with origin [0xf] A nil storage slot set If we simply discard this response, the finalization of the last range will be skipped, halting the entire sync process indefinitely. The test case TestSyncWithUnevenStorage can reproduce the scenario described above. In addition, this change also defines the common variables MaxAddress and MaxHash.
423 lines
18 KiB
Go
423 lines
18 KiB
Go
// Copyright 2020 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package core
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/math"
|
|
"github.com/ethereum/go-ethereum/consensus"
|
|
"github.com/ethereum/go-ethereum/consensus/beacon"
|
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
|
"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/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/holiman/uint256"
|
|
"golang.org/x/crypto/sha3"
|
|
)
|
|
|
|
func u64(val uint64) *uint64 { return &val }
|
|
|
|
// TestStateProcessorErrors tests the output from the 'core' errors
|
|
// as defined in core/error.go. These errors are generated when the
|
|
// blockchain imports bad blocks, meaning blocks which have valid headers but
|
|
// contain invalid transactions
|
|
func TestStateProcessorErrors(t *testing.T) {
|
|
var (
|
|
config = ¶ms.ChainConfig{
|
|
ChainID: big.NewInt(1),
|
|
HomesteadBlock: big.NewInt(0),
|
|
EIP150Block: big.NewInt(0),
|
|
EIP155Block: big.NewInt(0),
|
|
EIP158Block: big.NewInt(0),
|
|
ByzantiumBlock: big.NewInt(0),
|
|
ConstantinopleBlock: big.NewInt(0),
|
|
PetersburgBlock: big.NewInt(0),
|
|
IstanbulBlock: big.NewInt(0),
|
|
MuirGlacierBlock: big.NewInt(0),
|
|
BerlinBlock: big.NewInt(0),
|
|
LondonBlock: big.NewInt(0),
|
|
Ethash: new(params.EthashConfig),
|
|
TerminalTotalDifficulty: big.NewInt(0),
|
|
TerminalTotalDifficultyPassed: true,
|
|
ShanghaiTime: new(uint64),
|
|
CancunTime: new(uint64),
|
|
}
|
|
signer = types.LatestSigner(config)
|
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020")
|
|
)
|
|
var makeTx = func(key *ecdsa.PrivateKey, nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction {
|
|
tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, key)
|
|
return tx
|
|
}
|
|
var mkDynamicTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction {
|
|
tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{
|
|
Nonce: nonce,
|
|
GasTipCap: gasTipCap,
|
|
GasFeeCap: gasFeeCap,
|
|
Gas: gasLimit,
|
|
To: &to,
|
|
Value: big.NewInt(0),
|
|
}), signer, key1)
|
|
return tx
|
|
}
|
|
var mkDynamicCreationTx = func(nonce uint64, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, data []byte) *types.Transaction {
|
|
tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{
|
|
Nonce: nonce,
|
|
GasTipCap: gasTipCap,
|
|
GasFeeCap: gasFeeCap,
|
|
Gas: gasLimit,
|
|
Value: big.NewInt(0),
|
|
Data: data,
|
|
}), signer, key1)
|
|
return tx
|
|
}
|
|
var mkBlobTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, hashes []common.Hash) *types.Transaction {
|
|
tx, err := types.SignTx(types.NewTx(&types.BlobTx{
|
|
Nonce: nonce,
|
|
GasTipCap: uint256.MustFromBig(gasTipCap),
|
|
GasFeeCap: uint256.MustFromBig(gasFeeCap),
|
|
Gas: gasLimit,
|
|
To: to,
|
|
BlobHashes: hashes,
|
|
Value: new(uint256.Int),
|
|
}), signer, key1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return tx
|
|
}
|
|
|
|
{ // Tests against a 'recent' chain definition
|
|
var (
|
|
db = rawdb.NewMemoryDatabase()
|
|
gspec = &Genesis{
|
|
Config: config,
|
|
Alloc: GenesisAlloc{
|
|
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
|
|
Balance: big.NewInt(1000000000000000000), // 1 ether
|
|
Nonce: 0,
|
|
},
|
|
common.HexToAddress("0xfd0810DD14796680f72adf1a371963d0745BCc64"): GenesisAccount{
|
|
Balance: big.NewInt(1000000000000000000), // 1 ether
|
|
Nonce: math.MaxUint64,
|
|
},
|
|
},
|
|
}
|
|
blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil)
|
|
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
|
|
)
|
|
|
|
defer blockchain.Stop()
|
|
bigNumber := new(big.Int).SetBytes(common.MaxHash.Bytes())
|
|
tooBigNumber := new(big.Int).Set(bigNumber)
|
|
tooBigNumber.Add(tooBigNumber, common.Big1)
|
|
for i, tt := range []struct {
|
|
txs []*types.Transaction
|
|
want string
|
|
}{
|
|
{ // ErrNonceTooLow
|
|
txs: []*types.Transaction{
|
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
|
},
|
|
want: "could not apply tx 1 [0x0026256b3939ed97e2c4a6f3fce8ecf83bdcfa6d507c47838c308a1fb0436f62]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1",
|
|
},
|
|
{ // ErrNonceTooHigh
|
|
txs: []*types.Transaction{
|
|
makeTx(key1, 100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
|
},
|
|
want: "could not apply tx 0 [0xdebad714ca7f363bd0d8121c4518ad48fa469ca81b0a081be3d10c17460f751b]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0",
|
|
},
|
|
{ // ErrNonceMax
|
|
txs: []*types.Transaction{
|
|
makeTx(key2, math.MaxUint64, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
|
},
|
|
want: "could not apply tx 0 [0x84ea18d60eb2bb3b040e3add0eb72f757727122cc257dd858c67cb6591a85986]: nonce has max value: address 0xfd0810DD14796680f72adf1a371963d0745BCc64, nonce: 18446744073709551615",
|
|
},
|
|
{ // ErrGasLimitReached
|
|
txs: []*types.Transaction{
|
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil),
|
|
},
|
|
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
|
|
},
|
|
{ // ErrInsufficientFundsForTransfer
|
|
txs: []*types.Transaction{
|
|
makeTx(key1, 0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil),
|
|
},
|
|
want: "could not apply tx 0 [0x98c796b470f7fcab40aaef5c965a602b0238e1034cce6fb73823042dd0638d74]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 1000018375000000000",
|
|
},
|
|
{ // ErrInsufficientFunds
|
|
txs: []*types.Transaction{
|
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil),
|
|
},
|
|
want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 18900000000000000000000",
|
|
},
|
|
// ErrGasUintOverflow
|
|
// One missing 'core' error is ErrGasUintOverflow: "gas uint64 overflow",
|
|
// In order to trigger that one, we'd have to allocate a _huge_ chunk of data, such that the
|
|
// multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment
|
|
{ // ErrIntrinsicGas
|
|
txs: []*types.Transaction{
|
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(875000000), nil),
|
|
},
|
|
want: "could not apply tx 0 [0xcf3b049a0b516cb4f9274b3e2a264359e2ba53b2fb64b7bda2c634d5c9d01fca]: intrinsic gas too low: have 20000, want 21000",
|
|
},
|
|
{ // ErrGasLimitReached
|
|
txs: []*types.Transaction{
|
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(875000000), nil),
|
|
},
|
|
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
|
|
},
|
|
{ // ErrFeeCapTooLow
|
|
txs: []*types.Transaction{
|
|
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(0), big.NewInt(0)),
|
|
},
|
|
want: "could not apply tx 0 [0xc4ab868fef0c82ae0387b742aee87907f2d0fc528fc6ea0a021459fb0fc4a4a8]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 0 baseFee: 875000000",
|
|
},
|
|
{ // ErrTipVeryHigh
|
|
txs: []*types.Transaction{
|
|
mkDynamicTx(0, common.Address{}, params.TxGas, tooBigNumber, big.NewInt(1)),
|
|
},
|
|
want: "could not apply tx 0 [0x15b8391b9981f266b32f3ab7da564bbeb3d6c21628364ea9b32a21139f89f712]: max priority fee per gas higher than 2^256-1: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxPriorityFeePerGas bit length: 257",
|
|
},
|
|
{ // ErrFeeCapVeryHigh
|
|
txs: []*types.Transaction{
|
|
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(1), tooBigNumber),
|
|
},
|
|
want: "could not apply tx 0 [0x48bc299b83fdb345c57478f239e89814bb3063eb4e4b49f3b6057a69255c16bd]: max fee per gas higher than 2^256-1: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas bit length: 257",
|
|
},
|
|
{ // ErrTipAboveFeeCap
|
|
txs: []*types.Transaction{
|
|
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(2), big.NewInt(1)),
|
|
},
|
|
want: "could not apply tx 0 [0xf987a31ff0c71895780a7612f965a0c8b056deb54e020bb44fa478092f14c9b4]: max priority fee per gas higher than max fee per gas: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxPriorityFeePerGas: 2, maxFeePerGas: 1",
|
|
},
|
|
{ // ErrInsufficientFunds
|
|
// Available balance: 1000000000000000000
|
|
// Effective cost: 18375000021000
|
|
// FeeCap * gas: 1050000000000000000
|
|
// This test is designed to have the effective cost be covered by the balance, but
|
|
// the extended requirement on FeeCap*gas < balance to fail
|
|
txs: []*types.Transaction{
|
|
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(1), big.NewInt(50000000000000)),
|
|
},
|
|
want: "could not apply tx 0 [0x413603cd096a87f41b1660d3ed3e27d62e1da78eac138961c0a1314ed43bd129]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 1050000000000000000",
|
|
},
|
|
{ // Another ErrInsufficientFunds, this one to ensure that feecap/tip of max u256 is allowed
|
|
txs: []*types.Transaction{
|
|
mkDynamicTx(0, common.Address{}, params.TxGas, bigNumber, bigNumber),
|
|
},
|
|
want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000",
|
|
},
|
|
{ // ErrMaxInitCodeSizeExceeded
|
|
txs: []*types.Transaction{
|
|
mkDynamicCreationTx(0, 500000, common.Big0, big.NewInt(params.InitialBaseFee), tooBigInitCode[:]),
|
|
},
|
|
want: "could not apply tx 0 [0xd491405f06c92d118dd3208376fcee18a57c54bc52063ee4a26b1cf296857c25]: max initcode size exceeded: code size 49153 limit 49152",
|
|
},
|
|
{ // ErrIntrinsicGas: Not enough gas to cover init code
|
|
txs: []*types.Transaction{
|
|
mkDynamicCreationTx(0, 54299, common.Big0, big.NewInt(params.InitialBaseFee), make([]byte, 320)),
|
|
},
|
|
want: "could not apply tx 0 [0xfd49536a9b323769d8472fcb3ebb3689b707a349379baee3e2ee3fe7baae06a1]: intrinsic gas too low: have 54299, want 54300",
|
|
},
|
|
{ // ErrBlobFeeCapTooLow
|
|
txs: []*types.Transaction{
|
|
mkBlobTx(0, common.Address{}, params.TxGas, big.NewInt(1), big.NewInt(1), []common.Hash{(common.Hash{1})}),
|
|
},
|
|
want: "could not apply tx 0 [0x6c11015985ce82db691d7b2d017acda296db88b811c3c60dc71449c76256c716]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 1 baseFee: 875000000",
|
|
},
|
|
} {
|
|
block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config)
|
|
_, err := blockchain.InsertChain(types.Blocks{block})
|
|
if err == nil {
|
|
t.Fatal("block imported without errors")
|
|
}
|
|
if have, want := err.Error(), tt.want; have != want {
|
|
t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ErrTxTypeNotSupported, For this, we need an older chain
|
|
{
|
|
var (
|
|
db = rawdb.NewMemoryDatabase()
|
|
gspec = &Genesis{
|
|
Config: ¶ms.ChainConfig{
|
|
ChainID: big.NewInt(1),
|
|
HomesteadBlock: big.NewInt(0),
|
|
EIP150Block: big.NewInt(0),
|
|
EIP155Block: big.NewInt(0),
|
|
EIP158Block: big.NewInt(0),
|
|
ByzantiumBlock: big.NewInt(0),
|
|
ConstantinopleBlock: big.NewInt(0),
|
|
PetersburgBlock: big.NewInt(0),
|
|
IstanbulBlock: big.NewInt(0),
|
|
MuirGlacierBlock: big.NewInt(0),
|
|
},
|
|
Alloc: GenesisAlloc{
|
|
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
|
|
Balance: big.NewInt(1000000000000000000), // 1 ether
|
|
Nonce: 0,
|
|
},
|
|
},
|
|
}
|
|
blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
|
)
|
|
defer blockchain.Stop()
|
|
for i, tt := range []struct {
|
|
txs []*types.Transaction
|
|
want string
|
|
}{
|
|
{ // ErrTxTypeNotSupported
|
|
txs: []*types.Transaction{
|
|
mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)),
|
|
},
|
|
want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: transaction type not supported",
|
|
},
|
|
} {
|
|
block := GenerateBadBlock(gspec.ToBlock(), ethash.NewFaker(), tt.txs, gspec.Config)
|
|
_, err := blockchain.InsertChain(types.Blocks{block})
|
|
if err == nil {
|
|
t.Fatal("block imported without errors")
|
|
}
|
|
if have, want := err.Error(), tt.want; have != want {
|
|
t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ErrSenderNoEOA, for this we need the sender to have contract code
|
|
{
|
|
var (
|
|
db = rawdb.NewMemoryDatabase()
|
|
gspec = &Genesis{
|
|
Config: config,
|
|
Alloc: GenesisAlloc{
|
|
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
|
|
Balance: big.NewInt(1000000000000000000), // 1 ether
|
|
Nonce: 0,
|
|
Code: common.FromHex("0xB0B0FACE"),
|
|
},
|
|
},
|
|
}
|
|
blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil)
|
|
)
|
|
defer blockchain.Stop()
|
|
for i, tt := range []struct {
|
|
txs []*types.Transaction
|
|
want string
|
|
}{
|
|
{ // ErrSenderNoEOA
|
|
txs: []*types.Transaction{
|
|
mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)),
|
|
},
|
|
want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x9280914443471259d4570a8661015ae4a5b80186dbc619658fb494bebc3da3d1",
|
|
},
|
|
} {
|
|
block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), tt.txs, gspec.Config)
|
|
_, err := blockchain.InsertChain(types.Blocks{block})
|
|
if err == nil {
|
|
t.Fatal("block imported without errors")
|
|
}
|
|
if have, want := err.Error(), tt.want; have != want {
|
|
t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be
|
|
// valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently
|
|
// valid to be considered for import:
|
|
// - valid pow (fake), ancestry, difficulty, gaslimit etc
|
|
func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block {
|
|
difficulty := big.NewInt(0)
|
|
if !config.TerminalTotalDifficultyPassed {
|
|
difficulty = engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{
|
|
Number: parent.Number(),
|
|
Time: parent.Time(),
|
|
Difficulty: parent.Difficulty(),
|
|
UncleHash: parent.UncleHash(),
|
|
})
|
|
}
|
|
|
|
header := &types.Header{
|
|
ParentHash: parent.Hash(),
|
|
Coinbase: parent.Coinbase(),
|
|
Difficulty: difficulty,
|
|
GasLimit: parent.GasLimit(),
|
|
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
|
Time: parent.Time() + 10,
|
|
UncleHash: types.EmptyUncleHash,
|
|
}
|
|
if config.IsLondon(header.Number) {
|
|
header.BaseFee = eip1559.CalcBaseFee(config, parent.Header())
|
|
}
|
|
if config.IsShanghai(header.Number, header.Time) {
|
|
header.WithdrawalsHash = &types.EmptyWithdrawalsHash
|
|
}
|
|
var receipts []*types.Receipt
|
|
// The post-state result doesn't need to be correct (this is a bad block), but we do need something there
|
|
// Preferably something unique. So let's use a combo of blocknum + txhash
|
|
hasher := sha3.NewLegacyKeccak256()
|
|
hasher.Write(header.Number.Bytes())
|
|
var cumulativeGas uint64
|
|
var nBlobs int
|
|
for _, tx := range txs {
|
|
txh := tx.Hash()
|
|
hasher.Write(txh[:])
|
|
receipt := types.NewReceipt(nil, false, cumulativeGas+tx.Gas())
|
|
receipt.TxHash = tx.Hash()
|
|
receipt.GasUsed = tx.Gas()
|
|
receipts = append(receipts, receipt)
|
|
cumulativeGas += tx.Gas()
|
|
nBlobs += len(tx.BlobHashes())
|
|
}
|
|
header.Root = common.BytesToHash(hasher.Sum(nil))
|
|
if config.IsCancun(header.Number, header.Time) {
|
|
var pExcess, pUsed = uint64(0), uint64(0)
|
|
if parent.ExcessBlobGas() != nil {
|
|
pExcess = *parent.ExcessBlobGas()
|
|
pUsed = *parent.BlobGasUsed()
|
|
}
|
|
excess := eip4844.CalcExcessBlobGas(pExcess, pUsed)
|
|
used := uint64(nBlobs * params.BlobTxBlobGasPerBlob)
|
|
header.ExcessBlobGas = &excess
|
|
header.BlobGasUsed = &used
|
|
|
|
beaconRoot := common.HexToHash("0xbeac00")
|
|
header.ParentBeaconRoot = &beaconRoot
|
|
}
|
|
// Assemble and return the final block for sealing
|
|
if config.IsShanghai(header.Number, header.Time) {
|
|
return types.NewBlockWithWithdrawals(header, txs, nil, receipts, []*types.Withdrawal{}, trie.NewStackTrie(nil))
|
|
}
|
|
return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil))
|
|
}
|