bc42e88415
This change improves GenerateChain to support internal chain history access (ChainReader) for the consensus engine and EVM. GenerateChain takes a `parent` block and the number of blocks to create. With my changes, the consensus engine and EVM can now access blocks from `parent` up to the block currently being generated. This is required to make the BLOCKHASH instruction work, and also needed to create real clique chains. Clique uses chain history to figure out if the current signer is in-turn, for example. I've also added some more accessors to BlockGen. These are helpful when creating transactions: - g.Signer returns a signer instance for the current block - g.Difficulty returns the current block difficulty - g.Gas returns the remaining gas amount Another fix in this commit concerns the receipts returned by GenerateChain. The receipts now have properly derived fields (BlockHash, etc.) and should generally match what would be returned by the RPC API.
424 lines
18 KiB
Go
424 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 {
|
|
fakeChainReader := newChainMaker(nil, config, engine)
|
|
difficulty = engine.CalcDifficulty(fakeChainReader, 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))
|
|
}
|