core/types, params: add blob transaction type, RLP encoded for now (#27049)

* core/types, params: add blob transaction type, RLP encoded for now

* all: integrate Cancun (and timestamp based forks) into MakeSigner

* core/types: fix 2 back-and-forth type refactors

* core: fix review comment

* core/types: swap blob tx type id to 0x03
This commit is contained in:
Péter Szilágyi 2023-04-21 12:52:02 +03:00 committed by GitHub
parent 4ab4e4f3aa
commit bbc565ab05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 448 additions and 115 deletions

@ -684,7 +684,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
return fmt.Errorf("could not fetch parent") return fmt.Errorf("could not fetch parent")
} }
// Check transaction validity // Check transaction validity
signer := types.MakeSigner(b.blockchain.Config(), block.Number()) signer := types.MakeSigner(b.blockchain.Config(), block.Number(), block.Time())
sender, err := types.Sender(signer, tx) sender, err := types.Sender(signer, tx)
if err != nil { if err != nil {
return fmt.Errorf("invalid transaction: %v", err) return fmt.Errorf("invalid transaction: %v", err)
@ -884,7 +884,11 @@ func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (typ
if number == nil { if number == nil {
return nil, nil return nil, nil
} }
return rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config()), nil header := rawdb.ReadHeader(fb.db, hash, *number)
if header == nil {
return nil, nil
}
return rawdb.ReadReceipts(fb.db, hash, *number, header.Time, fb.bc.Config()), nil
} }
func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) {

@ -125,7 +125,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
} }
var ( var (
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre) statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre)
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number)) signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
gaspool = new(core.GasPool) gaspool = new(core.GasPool)
blockHash = common.Hash{0x13, 0x37} blockHash = common.Hash{0x13, 0x37}
rejectedTxs []*rejectedTx rejectedTxs []*rejectedTx

@ -112,7 +112,7 @@ func Transaction(ctx *cli.Context) error {
return NewError(ErrorIO, errors.New("only rlp supported")) return NewError(ErrorIO, errors.New("only rlp supported"))
} }
} }
signer := types.MakeSigner(chainConfig, new(big.Int)) signer := types.MakeSigner(chainConfig, new(big.Int), 0)
// We now have the transactions in 'body', which is supposed to be an // We now have the transactions in 'body', which is supposed to be an
// rlp list of transactions // rlp list of transactions
it, err := rlp.NewListIterator([]byte(body)) it, err := rlp.NewListIterator([]byte(body))

@ -240,7 +240,7 @@ func Transition(ctx *cli.Context) error {
} }
} }
// We may have to sign the transactions. // We may have to sign the transactions.
signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number))) signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp)
if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil { if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil {
return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err)) return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err))

@ -84,7 +84,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
toaddr := common.Address{} toaddr := common.Address{}
data := make([]byte, nbytes) data := make([]byte, nbytes)
gas, _ := IntrinsicGas(data, nil, false, false, false, false) gas, _ := IntrinsicGas(data, nil, false, false, false, false)
signer := types.MakeSigner(gen.config, big.NewInt(int64(i))) signer := types.MakeSigner(gen.config, big.NewInt(int64(i)), gen.header.Time)
gasPrice := big.NewInt(0) gasPrice := big.NewInt(0)
if gen.header.BaseFee != nil { if gen.header.BaseFee != nil {
gasPrice = gen.header.BaseFee gasPrice = gen.header.BaseFee
@ -128,7 +128,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
if gen.header.BaseFee != nil { if gen.header.BaseFee != nil {
gasPrice = gen.header.BaseFee gasPrice = gen.header.BaseFee
} }
signer := types.MakeSigner(gen.config, big.NewInt(int64(i))) signer := types.MakeSigner(gen.config, big.NewInt(int64(i)), gen.header.Time)
for { for {
gas -= params.TxGas gas -= params.TxGas
if gas < params.TxGas { if gas < params.TxGas {
@ -317,7 +317,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
if full { if full {
hash := header.Hash() hash := header.Hash()
rawdb.ReadBody(db, hash, n) rawdb.ReadBody(db, hash, n)
rawdb.ReadReceipts(db, hash, n, chain.Config()) rawdb.ReadReceipts(db, hash, n, header.Time, chain.Config())
} }
} }
chain.Stop() chain.Stop()

@ -1540,7 +1540,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
} }
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain) SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain)
var ( var (
stats = insertStats{startTime: mclock.Now()} stats = insertStats{startTime: mclock.Now()}
@ -2049,7 +2049,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error)
// the processing of a block. These logs are later announced as deleted or reborn. // the processing of a block. These logs are later announced as deleted or reborn.
func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64()) receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64())
receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.BaseFee(), b.Transactions()) receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Time(), b.BaseFee(), b.Transactions())
var logs []*types.Log var logs []*types.Log
for _, receipt := range receipts { for _, receipt := range receipts {

@ -217,7 +217,11 @@ func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts {
if number == nil { if number == nil {
return nil return nil
} }
receipts := rawdb.ReadReceipts(bc.db, hash, *number, bc.chainConfig) header := bc.GetHeader(hash, *number)
if header == nil {
return nil
}
receipts := rawdb.ReadReceipts(bc.db, hash, *number, header.Time, bc.chainConfig)
if receipts == nil { if receipts == nil {
return nil return nil
} }

@ -809,7 +809,7 @@ func TestFastVsFullChains(t *testing.T) {
// Iterate over all chain data components, and cross reference // Iterate over all chain data components, and cross reference
for i := 0; i < len(blocks); i++ { for i := 0; i < len(blocks); i++ {
num, hash := blocks[i].NumberU64(), blocks[i].Hash() num, hash, time := blocks[i].NumberU64(), blocks[i].Hash(), blocks[i].Time()
if ftd, atd := fast.GetTd(hash, num), archive.GetTd(hash, num); ftd.Cmp(atd) != 0 { if ftd, atd := fast.GetTd(hash, num), archive.GetTd(hash, num); ftd.Cmp(atd) != 0 {
t.Errorf("block #%d [%x]: td mismatch: fastdb %v, archivedb %v", num, hash, ftd, atd) t.Errorf("block #%d [%x]: td mismatch: fastdb %v, archivedb %v", num, hash, ftd, atd)
@ -832,9 +832,9 @@ func TestFastVsFullChains(t *testing.T) {
} }
// Check receipts. // Check receipts.
freceipts := rawdb.ReadReceipts(fastDb, hash, num, fast.Config()) freceipts := rawdb.ReadReceipts(fastDb, hash, num, time, fast.Config())
anreceipts := rawdb.ReadReceipts(ancientDb, hash, num, fast.Config()) anreceipts := rawdb.ReadReceipts(ancientDb, hash, num, time, fast.Config())
areceipts := rawdb.ReadReceipts(archiveDb, hash, num, fast.Config()) areceipts := rawdb.ReadReceipts(archiveDb, hash, num, time, fast.Config())
if types.DeriveSha(freceipts, trie.NewStackTrie(nil)) != types.DeriveSha(areceipts, trie.NewStackTrie(nil)) { if types.DeriveSha(freceipts, trie.NewStackTrie(nil)) != types.DeriveSha(areceipts, trie.NewStackTrie(nil)) {
t.Errorf("block #%d [%x]: receipts mismatch: fastdb %v, ancientdb %v, archivedb %v", num, hash, freceipts, anreceipts, areceipts) t.Errorf("block #%d [%x]: receipts mismatch: fastdb %v, ancientdb %v, archivedb %v", num, hash, freceipts, anreceipts, areceipts)
} }

@ -625,7 +625,7 @@ func ReadRawReceipts(db ethdb.Reader, hash common.Hash, number uint64) types.Rec
// The current implementation populates these metadata fields by reading the receipts' // The current implementation populates these metadata fields by reading the receipts'
// corresponding block body, so if the block body is not found it will return nil even // corresponding block body, so if the block body is not found it will return nil even
// if the receipt itself is stored. // if the receipt itself is stored.
func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) types.Receipts { func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, time uint64, config *params.ChainConfig) types.Receipts {
// We're deriving many fields from the block body, retrieve beside the receipt // We're deriving many fields from the block body, retrieve beside the receipt
receipts := ReadRawReceipts(db, hash, number) receipts := ReadRawReceipts(db, hash, number)
if receipts == nil { if receipts == nil {
@ -643,7 +643,7 @@ func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, config *para
} else { } else {
baseFee = header.BaseFee baseFee = header.BaseFee
} }
if err := receipts.DeriveFields(config, hash, number, baseFee, body.Transactions); err != nil { if err := receipts.DeriveFields(config, hash, number, time, baseFee, body.Transactions); err != nil {
log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err) log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err)
return nil return nil
} }

@ -379,7 +379,7 @@ func TestBlockReceiptStorage(t *testing.T) {
// Check that no receipt entries are in a pristine database // Check that no receipt entries are in a pristine database
hash := common.BytesToHash([]byte{0x03, 0x14}) hash := common.BytesToHash([]byte{0x03, 0x14})
if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 {
t.Fatalf("non existent receipts returned: %v", rs) t.Fatalf("non existent receipts returned: %v", rs)
} }
// Insert the body that corresponds to the receipts // Insert the body that corresponds to the receipts
@ -387,7 +387,7 @@ func TestBlockReceiptStorage(t *testing.T) {
// Insert the receipt slice into the database and check presence // Insert the receipt slice into the database and check presence
WriteReceipts(db, hash, 0, receipts) WriteReceipts(db, hash, 0, receipts)
if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) == 0 { if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) == 0 {
t.Fatalf("no receipts returned") t.Fatalf("no receipts returned")
} else { } else {
if err := checkReceiptsRLP(rs, receipts); err != nil { if err := checkReceiptsRLP(rs, receipts); err != nil {
@ -396,7 +396,7 @@ func TestBlockReceiptStorage(t *testing.T) {
} }
// Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed) // Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed)
DeleteBody(db, hash, 0) DeleteBody(db, hash, 0)
if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); rs != nil { if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); rs != nil {
t.Fatalf("receipts returned when body was deleted: %v", rs) t.Fatalf("receipts returned when body was deleted: %v", rs)
} }
// Ensure that receipts without metadata can be returned without the block body too // Ensure that receipts without metadata can be returned without the block body too
@ -407,7 +407,7 @@ func TestBlockReceiptStorage(t *testing.T) {
WriteBody(db, hash, 0, body) WriteBody(db, hash, 0, body)
DeleteReceipts(db, hash, 0) DeleteReceipts(db, hash, 0)
if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 {
t.Fatalf("deleted receipts returned: %v", rs) t.Fatalf("deleted receipts returned: %v", rs)
} }
} }
@ -727,7 +727,7 @@ func TestReadLogs(t *testing.T) {
hash := common.BytesToHash([]byte{0x03, 0x14}) hash := common.BytesToHash([]byte{0x03, 0x14})
// Check that no receipt entries are in a pristine database // Check that no receipt entries are in a pristine database
if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 {
t.Fatalf("non existent receipts returned: %v", rs) t.Fatalf("non existent receipts returned: %v", rs)
} }
// Insert the body that corresponds to the receipts // Insert the body that corresponds to the receipts

@ -130,8 +130,12 @@ func ReadReceipt(db ethdb.Reader, hash common.Hash, config *params.ChainConfig)
if blockHash == (common.Hash{}) { if blockHash == (common.Hash{}) {
return nil, common.Hash{}, 0, 0 return nil, common.Hash{}, 0, 0
} }
blockHeader := ReadHeader(db, blockHash, *blockNumber)
if blockHeader == nil {
return nil, common.Hash{}, 0, 0
}
// Read all the receipts from the block and return the one with the matching hash // Read all the receipts from the block and return the one with the matching hash
receipts := ReadReceipts(db, blockHash, *blockNumber, config) receipts := ReadReceipts(db, blockHash, *blockNumber, blockHeader.Time, config)
for receiptIndex, receipt := range receipts { for receiptIndex, receipt := range receipts {
if receipt.TxHash == hash { if receipt.TxHash == hash {
return receipt, blockHash, *blockNumber, uint64(receiptIndex) return receipt, blockHash, *blockNumber, uint64(receiptIndex)

@ -53,7 +53,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
gaspool = new(GasPool).AddGas(block.GasLimit()) gaspool = new(GasPool).AddGas(block.GasLimit())
blockContext = NewEVMBlockContext(header, p.bc, nil) blockContext = NewEVMBlockContext(header, p.bc, nil)
evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
signer = types.MakeSigner(p.config, header.Number) signer = types.MakeSigner(p.config, header.Number, header.Time)
) )
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
byzantium := p.config.IsByzantium(block.Number()) byzantium := p.config.IsByzantium(block.Number())

@ -70,11 +70,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
blockContext := NewEVMBlockContext(header, p.bc, nil) var (
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) context = NewEVMBlockContext(header, p.bc, nil)
vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
signer = types.MakeSigner(p.config, header.Number, header.Time)
)
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
msg, err := TransactionToMessage(tx, types.MakeSigner(p.config, header.Number), header.BaseFee) msg, err := TransactionToMessage(tx, signer, header.BaseFee)
if err != nil { if err != nil {
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
} }
@ -147,7 +150,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta
// for the transaction, gas used and an error if the transaction failed, // for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid. // indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee) msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -606,6 +606,10 @@ func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error {
if !pool.eip1559.Load() && tx.Type() == types.DynamicFeeTxType { if !pool.eip1559.Load() && tx.Type() == types.DynamicFeeTxType {
return core.ErrTxTypeNotSupported return core.ErrTxTypeNotSupported
} }
// Reject blob transactions forever, those will have their own pool.
if tx.Type() == types.BlobTxType {
return core.ErrTxTypeNotSupported
}
// Reject transactions over defined size to prevent DOS attacks // Reject transactions over defined size to prevent DOS attacks
if tx.Size() > txMaxSize { if tx.Size() > txMaxSize {
return ErrOversizedData return ErrOversizedData

@ -313,8 +313,8 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
// DeriveFields fills the receipts with their computed fields based on consensus // DeriveFields fills the receipts with their computed fields based on consensus
// data and contextual infos like containing block and transactions. // data and contextual infos like containing block and transactions.
func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, baseFee *big.Int, txs []*Transaction) error { func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, time uint64, baseFee *big.Int, txs []*Transaction) error {
signer := MakeSigner(config, new(big.Int).SetUint64(number)) signer := MakeSigner(config, new(big.Int).SetUint64(number), time)
logIndex := uint(0) logIndex := uint(0)
if len(txs) != len(rs) { if len(txs) != len(rs) {

@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
"github.com/kylelemons/godebug/diff" "github.com/kylelemons/godebug/diff"
) )
@ -99,6 +100,8 @@ func TestDeriveFields(t *testing.T) {
to3 := common.HexToAddress("0x3") to3 := common.HexToAddress("0x3")
to4 := common.HexToAddress("0x4") to4 := common.HexToAddress("0x4")
to5 := common.HexToAddress("0x5") to5 := common.HexToAddress("0x5")
to6 := common.HexToAddress("0x6")
to7 := common.HexToAddress("0x7")
txs := Transactions{ txs := Transactions{
NewTx(&LegacyTx{ NewTx(&LegacyTx{
Nonce: 1, Nonce: 1,
@ -127,19 +130,39 @@ func TestDeriveFields(t *testing.T) {
Value: big.NewInt(4), Value: big.NewInt(4),
Gas: 4, Gas: 4,
GasTipCap: big.NewInt(44), GasTipCap: big.NewInt(44),
GasFeeCap: big.NewInt(1045), GasFeeCap: big.NewInt(1044),
}), }),
NewTx(&DynamicFeeTx{ NewTx(&DynamicFeeTx{
To: &to5, To: &to5,
Nonce: 5, Nonce: 5,
Value: big.NewInt(5), Value: big.NewInt(5),
Gas: 5, Gas: 5,
GasTipCap: big.NewInt(56), GasTipCap: big.NewInt(55),
GasFeeCap: big.NewInt(1055), GasFeeCap: big.NewInt(1055),
}), }),
// EIP-4844 transactions.
NewTx(&BlobTx{
To: &to6,
Nonce: 6,
Value: uint256.NewInt(6),
Gas: 6,
GasTipCap: uint256.NewInt(66),
GasFeeCap: uint256.NewInt(1066),
BlobFeeCap: uint256.NewInt(100066),
}),
NewTx(&BlobTx{
To: &to7,
Nonce: 7,
Value: uint256.NewInt(7),
Gas: 7,
GasTipCap: uint256.NewInt(77),
GasFeeCap: uint256.NewInt(1077),
BlobFeeCap: uint256.NewInt(100077),
}),
} }
blockNumber := big.NewInt(1) blockNumber := big.NewInt(1)
blockTime := uint64(2)
blockHash := common.BytesToHash([]byte{0x03, 0x14}) blockHash := common.BytesToHash([]byte{0x03, 0x14})
// Create the corresponding receipts // Create the corresponding receipts
@ -246,12 +269,38 @@ func TestDeriveFields(t *testing.T) {
BlockNumber: blockNumber, BlockNumber: blockNumber,
TransactionIndex: 4, TransactionIndex: 4,
}, },
&Receipt{
Type: BlobTxType,
PostState: common.Hash{6}.Bytes(),
CumulativeGasUsed: 21,
Logs: []*Log{},
// derived fields:
TxHash: txs[5].Hash(),
GasUsed: 6,
EffectiveGasPrice: big.NewInt(1066),
BlockHash: blockHash,
BlockNumber: blockNumber,
TransactionIndex: 5,
},
&Receipt{
Type: BlobTxType,
PostState: common.Hash{7}.Bytes(),
CumulativeGasUsed: 28,
Logs: []*Log{},
// derived fields:
TxHash: txs[6].Hash(),
GasUsed: 7,
EffectiveGasPrice: big.NewInt(1077),
BlockHash: blockHash,
BlockNumber: blockNumber,
TransactionIndex: 6,
},
} }
// Re-derive receipts. // Re-derive receipts.
basefee := big.NewInt(1000) basefee := big.NewInt(1000)
derivedReceipts := clearComputedFieldsOnReceipts(receipts) derivedReceipts := clearComputedFieldsOnReceipts(receipts)
err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), basefee, txs) err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), blockTime, basefee, txs)
if err != nil { if err != nil {
t.Fatalf("DeriveFields(...) = %v, want <nil>", err) t.Fatalf("DeriveFields(...) = %v, want <nil>", err)
} }

@ -42,9 +42,10 @@ var (
// Transaction types. // Transaction types.
const ( const (
LegacyTxType = iota LegacyTxType = 0x00
AccessListTxType AccessListTxType = 0x01
DynamicFeeTxType DynamicFeeTxType = 0x02
BlobTxType = 0x03
) )
// Transaction is an Ethereum transaction. // Transaction is an Ethereum transaction.
@ -82,6 +83,9 @@ type TxData interface {
value() *big.Int value() *big.Int
nonce() uint64 nonce() uint64
to() *common.Address to() *common.Address
blobGas() uint64
blobGasFeeCap() *big.Int
blobHashes() []common.Hash
rawSignatureValues() (v, r, s *big.Int) rawSignatureValues() (v, r, s *big.Int)
setSignatureValues(chainID, v, r, s *big.Int) setSignatureValues(chainID, v, r, s *big.Int)
@ -192,6 +196,10 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
var inner DynamicFeeTx var inner DynamicFeeTx
err := rlp.DecodeBytes(b[1:], &inner) err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err return &inner, err
case BlobTxType:
var inner BlobTx
err := rlp.DecodeBytes(b[1:], &inner) // TODO(karalabe): This needs to be ssz
return &inner, err
default: default:
return nil, ErrTxTypeNotSupported return nil, ErrTxTypeNotSupported
} }
@ -281,6 +289,15 @@ func (tx *Transaction) GasTipCap() *big.Int { return new(big.Int).Set(tx.inner.g
// GasFeeCap returns the fee cap per gas of the transaction. // GasFeeCap returns the fee cap per gas of the transaction.
func (tx *Transaction) GasFeeCap() *big.Int { return new(big.Int).Set(tx.inner.gasFeeCap()) } func (tx *Transaction) GasFeeCap() *big.Int { return new(big.Int).Set(tx.inner.gasFeeCap()) }
// BlobGas returns the data gas limit of the transaction for blob transactions, 0 otherwise.
func (tx *Transaction) BlobGas() uint64 { return tx.inner.blobGas() }
// BlobGasFeeCap returns the data gas fee cap per data gas of the transaction for blob transactions, nil otherwise.
func (tx *Transaction) BlobGasFeeCap() *big.Int { return tx.inner.blobGasFeeCap() }
// BlobHashes returns the hases of the blob commitments for blob transactions, nil otherwise.
func (tx *Transaction) BlobHashes() []common.Hash { return tx.inner.blobHashes() }
// Value returns the ether amount of the transaction. // Value returns the ether amount of the transaction.
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) } func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) }
@ -293,9 +310,12 @@ func (tx *Transaction) To() *common.Address {
return copyAddressPtr(tx.inner.to()) return copyAddressPtr(tx.inner.to())
} }
// Cost returns gas * gasPrice + value. // Cost returns (gas * gasPrice) + (blobGas * blobGasPrice) + value.
func (tx *Transaction) Cost() *big.Int { func (tx *Transaction) Cost() *big.Int {
total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas())) total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))
if tx.Type() == BlobTxType {
total.Add(total, new(big.Int).Mul(tx.BlobGasFeeCap(), new(big.Int).SetUint64(tx.BlobGas())))
}
total.Add(total, tx.Value()) total.Add(total, tx.Value())
return total return total
} }
@ -364,6 +384,16 @@ func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) i
return tx.EffectiveGasTipValue(baseFee).Cmp(other) return tx.EffectiveGasTipValue(baseFee).Cmp(other)
} }
// BlobGasFeeCapCmp compares the blob fee cap of two transactions.
func (tx *Transaction) BlobGasFeeCapCmp(other *Transaction) int {
return tx.inner.blobGasFeeCap().Cmp(other.inner.blobGasFeeCap())
}
// BlobGasFeeCapIntCmp compares the blob fee cap of the transaction against the given blob fee cap.
func (tx *Transaction) BlobGasFeeCapIntCmp(other *big.Int) int {
return tx.inner.blobGasFeeCap().Cmp(other)
}
// Hash returns the transaction hash. // Hash returns the transaction hash.
func (tx *Transaction) Hash() common.Hash { func (tx *Transaction) Hash() common.Hash {
if hash := tx.hash.Load(); hash != nil { if hash := tx.hash.Load(); hash != nil {
@ -387,7 +417,11 @@ func (tx *Transaction) Size() uint64 {
return size.(uint64) return size.(uint64)
} }
c := writeCounter(0) c := writeCounter(0)
if tx.Type() == BlobTxType {
rlp.Encode(&c, &tx.inner) // TODO(karalabe): Replace with SSZ encoding
} else {
rlp.Encode(&c, &tx.inner) rlp.Encode(&c, &tx.inner)
}
size := uint64(c) size := uint64(c)
if tx.Type() != LegacyTxType { if tx.Type() != LegacyTxType {

@ -37,9 +37,11 @@ type sigCache struct {
} }
// MakeSigner returns a Signer based on the given chain config and block number. // MakeSigner returns a Signer based on the given chain config and block number.
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer {
var signer Signer var signer Signer
switch { switch {
case config.IsCancun(blockTime):
signer = NewCancunSigner(config.ChainID)
case config.IsLondon(blockNumber): case config.IsLondon(blockNumber):
signer = NewLondonSigner(config.ChainID) signer = NewLondonSigner(config.ChainID)
case config.IsBerlin(blockNumber): case config.IsBerlin(blockNumber):
@ -63,6 +65,9 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
// have the current block number available, use MakeSigner instead. // have the current block number available, use MakeSigner instead.
func LatestSigner(config *params.ChainConfig) Signer { func LatestSigner(config *params.ChainConfig) Signer {
if config.ChainID != nil { if config.ChainID != nil {
if config.CancunTime != nil {
return NewCancunSigner(config.ChainID)
}
if config.LondonBlock != nil { if config.LondonBlock != nil {
return NewLondonSigner(config.ChainID) return NewLondonSigner(config.ChainID)
} }
@ -87,7 +92,7 @@ func LatestSignerForChainID(chainID *big.Int) Signer {
if chainID == nil { if chainID == nil {
return HomesteadSigner{} return HomesteadSigner{}
} }
return NewLondonSigner(chainID) return NewCancunSigner(chainID)
} }
// SignTx signs the transaction using the given signer and private key. // SignTx signs the transaction using the given signer and private key.
@ -170,6 +175,75 @@ type Signer interface {
Equal(Signer) bool Equal(Signer) bool
} }
type cancunSigner struct{ londonSigner }
// NewCancunSigner returns a signer that accepts
// - EIP-4844 blob transactions
// - EIP-1559 dynamic fee transactions
// - EIP-2930 access list transactions,
// - EIP-155 replay protected transactions, and
// - legacy Homestead transactions.
func NewCancunSigner(chainId *big.Int) Signer {
return cancunSigner{londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}}
}
func (s cancunSigner) Sender(tx *Transaction) (common.Address, error) {
if tx.Type() != BlobTxType {
return s.londonSigner.Sender(tx)
}
V, R, S := tx.RawSignatureValues()
// Blob txs are defined to use 0 and 1 as their recovery
// id, add 27 to become equivalent to unprotected Homestead signatures.
V = new(big.Int).Add(V, big.NewInt(27))
if tx.ChainId().Cmp(s.chainId) != 0 {
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
}
return recoverPlain(s.Hash(tx), R, S, V, true)
}
func (s cancunSigner) Equal(s2 Signer) bool {
x, ok := s2.(cancunSigner)
return ok && x.chainId.Cmp(s.chainId) == 0
}
func (s cancunSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
txdata, ok := tx.inner.(*BlobTx)
if !ok {
return s.londonSigner.SignatureValues(tx, sig)
}
// Check that chain ID of tx matches the signer. We also accept ID zero here,
// because it indicates that the chain ID was not specified in the tx.
if txdata.ChainID.Sign() != 0 && txdata.ChainID.ToBig().Cmp(s.chainId) != 0 {
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
}
R, S, _ = decodeSignature(sig)
V = big.NewInt(int64(sig[64]))
return R, S, V, nil
}
// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (s cancunSigner) Hash(tx *Transaction) common.Hash {
if tx.Type() != BlobTxType {
return s.londonSigner.Hash(tx)
}
return prefixedRlpHash(
tx.Type(),
[]interface{}{
s.chainId,
tx.Nonce(),
tx.GasTipCap(),
tx.GasFeeCap(),
tx.Gas(),
tx.To(),
tx.Value(),
tx.Data(),
tx.AccessList(),
tx.BlobGasFeeCap(),
tx.BlobHashes(),
})
}
type londonSigner struct{ eip2930Signer } type londonSigner struct{ eip2930Signer }
// NewLondonSigner returns a signer that accepts // NewLondonSigner returns a signer that accepts

@ -105,6 +105,9 @@ func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice }
func (tx *AccessListTx) value() *big.Int { return tx.Value } func (tx *AccessListTx) value() *big.Int { return tx.Value }
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce } func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
func (tx *AccessListTx) to() *common.Address { return tx.To } func (tx *AccessListTx) to() *common.Address { return tx.To }
func (tx *AccessListTx) blobGas() uint64 { return 0 }
func (tx *AccessListTx) blobGasFeeCap() *big.Int { return nil }
func (tx *AccessListTx) blobHashes() []common.Hash { return nil }
func (tx *AccessListTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { func (tx *AccessListTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
return dst.Set(tx.GasPrice) return dst.Set(tx.GasPrice)

132
core/types/tx_blob.go Normal file

@ -0,0 +1,132 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
// BlobTx represents an EIP-4844 transaction.
type BlobTx struct {
ChainID *uint256.Int
Nonce uint64
GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas
GasFeeCap *uint256.Int // a.k.a. maxFeePerGas
Gas uint64
To *common.Address // `rlp:"nil"` // nil means contract creation
Value *uint256.Int
Data []byte
AccessList AccessList
BlobFeeCap *uint256.Int // a.k.a. maxFeePerDataGas
BlobHashes []common.Hash
// Signature values
V *uint256.Int `json:"v" gencodec:"required"`
R *uint256.Int `json:"r" gencodec:"required"`
S *uint256.Int `json:"s" gencodec:"required"`
}
// copy creates a deep copy of the transaction data and initializes all fields.
func (tx *BlobTx) copy() TxData {
cpy := &BlobTx{
Nonce: tx.Nonce,
To: copyAddressPtr(tx.To),
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
// These are copied below.
AccessList: make(AccessList, len(tx.AccessList)),
BlobHashes: make([]common.Hash, len(tx.BlobHashes)),
Value: new(uint256.Int),
ChainID: new(uint256.Int),
GasTipCap: new(uint256.Int),
GasFeeCap: new(uint256.Int),
BlobFeeCap: new(uint256.Int),
V: new(uint256.Int),
R: new(uint256.Int),
S: new(uint256.Int),
}
copy(cpy.AccessList, tx.AccessList)
copy(cpy.BlobHashes, tx.BlobHashes)
if tx.Value != nil {
cpy.Value.Set(tx.Value)
}
if tx.ChainID != nil {
cpy.ChainID.Set(tx.ChainID)
}
if tx.GasTipCap != nil {
cpy.GasTipCap.Set(tx.GasTipCap)
}
if tx.GasFeeCap != nil {
cpy.GasFeeCap.Set(tx.GasFeeCap)
}
if tx.BlobFeeCap != nil {
cpy.BlobFeeCap.Set(tx.BlobFeeCap)
}
if tx.V != nil {
cpy.V.Set(tx.V)
}
if tx.R != nil {
cpy.R.Set(tx.R)
}
if tx.S != nil {
cpy.S.Set(tx.S)
}
return cpy
}
// accessors for innerTx.
func (tx *BlobTx) txType() byte { return BlobTxType }
func (tx *BlobTx) chainID() *big.Int { return tx.ChainID.ToBig() }
func (tx *BlobTx) accessList() AccessList { return tx.AccessList }
func (tx *BlobTx) data() []byte { return tx.Data }
func (tx *BlobTx) gas() uint64 { return tx.Gas }
func (tx *BlobTx) gasFeeCap() *big.Int { return tx.GasFeeCap.ToBig() }
func (tx *BlobTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() }
func (tx *BlobTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() }
func (tx *BlobTx) value() *big.Int { return tx.Value.ToBig() }
func (tx *BlobTx) nonce() uint64 { return tx.Nonce }
func (tx *BlobTx) to() *common.Address { return tx.To }
func (tx *BlobTx) blobGas() uint64 { return params.BlobTxDataGasPerBlob * uint64(len(tx.BlobHashes)) }
func (tx *BlobTx) blobGasFeeCap() *big.Int { return tx.BlobFeeCap.ToBig() }
func (tx *BlobTx) blobHashes() []common.Hash { return tx.BlobHashes }
func (tx *BlobTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
if baseFee == nil {
return dst.Set(tx.GasFeeCap.ToBig())
}
tip := dst.Sub(tx.GasFeeCap.ToBig(), baseFee)
if tip.Cmp(tx.GasTipCap.ToBig()) > 0 {
tip.Set(tx.GasTipCap.ToBig())
}
return tip.Add(tip, baseFee)
}
func (tx *BlobTx) rawSignatureValues() (v, r, s *big.Int) {
return tx.V.ToBig(), tx.R.ToBig(), tx.S.ToBig()
}
func (tx *BlobTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.ChainID.SetFromBig(chainID)
tx.V.SetFromBig(v)
tx.R.SetFromBig(r)
tx.S.SetFromBig(s)
}

@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
// DynamicFeeTx represents an EIP-1559 transaction.
type DynamicFeeTx struct { type DynamicFeeTx struct {
ChainID *big.Int ChainID *big.Int
Nonce uint64 Nonce uint64
@ -93,6 +94,9 @@ func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap }
func (tx *DynamicFeeTx) value() *big.Int { return tx.Value } func (tx *DynamicFeeTx) value() *big.Int { return tx.Value }
func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce } func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce }
func (tx *DynamicFeeTx) to() *common.Address { return tx.To } func (tx *DynamicFeeTx) to() *common.Address { return tx.To }
func (tx *DynamicFeeTx) blobGas() uint64 { return 0 }
func (tx *DynamicFeeTx) blobGasFeeCap() *big.Int { return nil }
func (tx *DynamicFeeTx) blobHashes() []common.Hash { return nil }
func (tx *DynamicFeeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { func (tx *DynamicFeeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
if baseFee == nil { if baseFee == nil {

@ -22,7 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
// LegacyTx is the transaction data of regular Ethereum transactions. // LegacyTx is the transaction data of the original Ethereum transactions.
type LegacyTx struct { type LegacyTx struct {
Nonce uint64 // nonce of sender account Nonce uint64 // nonce of sender account
GasPrice *big.Int // wei per gas GasPrice *big.Int // wei per gas
@ -102,6 +102,9 @@ func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice }
func (tx *LegacyTx) value() *big.Int { return tx.Value } func (tx *LegacyTx) value() *big.Int { return tx.Value }
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce } func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
func (tx *LegacyTx) to() *common.Address { return tx.To } func (tx *LegacyTx) to() *common.Address { return tx.To }
func (tx *LegacyTx) blobGas() uint64 { return 0 }
func (tx *LegacyTx) blobGasFeeCap() *big.Int { return nil }
func (tx *LegacyTx) blobHashes() []common.Hash { return nil }
func (tx *LegacyTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { func (tx *LegacyTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
return dst.Set(tx.GasPrice) return dst.Set(tx.GasPrice)

@ -42,7 +42,7 @@ func makeChain(n int, seed byte, parent *types.Block, empty bool) ([]*types.Bloc
block.SetCoinbase(common.Address{seed}) block.SetCoinbase(common.Address{seed})
// Add one tx to every secondblock // Add one tx to every secondblock
if !empty && i%2 == 0 { if !empty && i%2 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number()) signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp())
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey)
if err != nil { if err != nil {
panic(err) panic(err)

@ -168,7 +168,7 @@ func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool)
} }
// Include transactions to the miner to make blocks more interesting. // Include transactions to the miner to make blocks more interesting.
if parent == tc.blocks[0] && i%22 == 0 { if parent == tc.blocks[0] && i%22 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number()) signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp())
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey)
if err != nil { if err != nil {
panic(err) panic(err)

@ -58,7 +58,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common
// If the block number is multiple of 3, send a bonus transaction to the miner // If the block number is multiple of 3, send a bonus transaction to the miner
if parent == genesis && i%3 == 0 { if parent == genesis && i%3 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number()) signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp())
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey)
if err != nil { if err != nil {
panic(err) panic(err)

@ -111,7 +111,9 @@ func (b *testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.
func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil { if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil {
return rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig), nil if header := rawdb.ReadHeader(b.db, hash, *number); header != nil {
return rawdb.ReadReceipts(b.db, hash, *number, header.Time, params.TestChainConfig), nil
}
} }
return nil, nil return nil, nil
} }

@ -176,7 +176,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
results []*big.Int results []*big.Int
) )
for sent < oracle.checkBlocks && number > 0 { for sent < oracle.checkBlocks && number > 0 {
go oracle.getBlockValues(ctx, types.MakeSigner(oracle.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, oracle.ignorePrice, result, quit) go oracle.getBlockValues(ctx, number, sampleNumber, oracle.ignorePrice, result, quit)
sent++ sent++
exp++ exp++
number-- number--
@ -199,7 +199,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
// meaningful returned, try to query more blocks. But the maximum // meaningful returned, try to query more blocks. But the maximum
// is 2*checkBlocks. // is 2*checkBlocks.
if len(res.values) == 1 && len(results)+1+exp < oracle.checkBlocks*2 && number > 0 { if len(res.values) == 1 && len(results)+1+exp < oracle.checkBlocks*2 && number > 0 {
go oracle.getBlockValues(ctx, types.MakeSigner(oracle.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, oracle.ignorePrice, result, quit) go oracle.getBlockValues(ctx, number, sampleNumber, oracle.ignorePrice, result, quit)
sent++ sent++
exp++ exp++
number-- number--
@ -255,7 +255,7 @@ func (s *txSorter) Less(i, j int) bool {
// and sends it to the result channel. If the block is empty or all transactions // and sends it to the result channel. If the block is empty or all transactions
// are sent by the miner itself(it doesn't make any sense to include this kind of // are sent by the miner itself(it doesn't make any sense to include this kind of
// transaction prices for sampling), nil gasprice is returned. // transaction prices for sampling), nil gasprice is returned.
func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) { func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) {
block, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum)) block, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
if block == nil { if block == nil {
select { select {
@ -264,6 +264,8 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, b
} }
return return
} }
signer := types.MakeSigner(oracle.backend.ChainConfig(), block.Number(), block.Time())
// Sort the transaction by effective tip in ascending sort. // Sort the transaction by effective tip in ascending sort.
txs := make([]*types.Transaction, len(block.Transactions())) txs := make([]*types.Transaction, len(block.Transactions()))
copy(txs, block.Transactions()) copy(txs, block.Transactions())

@ -209,7 +209,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
return nil, vm.BlockContext{}, statedb, release, nil return nil, vm.BlockContext{}, statedb, release, nil
} }
// Recompute transactions up to the target index. // Recompute transactions up to the target index.
signer := types.MakeSigner(eth.blockchain.Config(), block.Number()) signer := types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time())
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset // Assemble the transaction call message and return if the requested offset
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())

@ -288,7 +288,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
// Fetch and execute the block trace taskCh // Fetch and execute the block trace taskCh
for task := range taskCh { for task := range taskCh {
var ( var (
signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number()) signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time())
blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil) blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil)
) )
// Trace all the transactions contained within // Trace all the transactions contained within
@ -544,7 +544,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
var ( var (
roots []common.Hash roots []common.Hash
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
chainConfig = api.backend.ChainConfig() chainConfig = api.backend.ChainConfig()
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
@ -623,7 +623,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
blockHash = block.Hash() blockHash = block.Hash()
is158 = api.backend.ChainConfig().IsEIP158(block.Number()) is158 = api.backend.ChainConfig().IsEIP158(block.Number())
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
results = make([]*txTraceResult, len(txs)) results = make([]*txTraceResult, len(txs))
) )
for i, tx := range txs { for i, tx := range txs {
@ -656,7 +656,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
txs = block.Transactions() txs = block.Transactions()
blockHash = block.Hash() blockHash = block.Hash()
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
results = make([]*txTraceResult, len(txs)) results = make([]*txTraceResult, len(txs))
pend sync.WaitGroup pend sync.WaitGroup
) )
@ -765,7 +765,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
// Execute transaction, either tracing all or just the requested one // Execute transaction, either tracing all or just the requested one
var ( var (
dumps []string dumps []string
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
chainConfig = api.backend.ChainConfig() chainConfig = api.backend.ChainConfig()
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
canon = true canon = true

@ -169,7 +169,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
return nil, vm.BlockContext{}, statedb, release, nil return nil, vm.BlockContext{}, statedb, release, nil
} }
// Recompute transactions up to the target index. // Recompute transactions up to the target index.
signer := types.MakeSigner(b.chainConfig, block.Number()) signer := types.MakeSigner(b.chainConfig, block.Number(), block.Time())
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
txContext := core.NewEVMTxContext(msg) txContext := core.NewEVMTxContext(msg)

@ -121,7 +121,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
} }
// Configure a blockchain with the given prestate // Configure a blockchain with the given prestate
var ( var (
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
origin, _ = signer.Sender(tx) origin, _ = signer.Sender(tx)
txContext = vm.TxContext{ txContext = vm.TxContext{
Origin: origin, Origin: origin,
@ -218,7 +218,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil {
b.Fatalf("failed to parse testcase input: %v", err) b.Fatalf("failed to parse testcase input: %v", err)
} }
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
msg, err := core.TransactionToMessage(tx, signer, nil) msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil { if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err) b.Fatalf("failed to prepare transaction for tracing: %v", err)

@ -85,7 +85,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil {
return fmt.Errorf("failed to parse testcase input: %v", err) return fmt.Errorf("failed to parse testcase input: %v", err)
} }
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
origin, _ := signer.Sender(tx) origin, _ := signer.Sender(tx)
txContext := vm.TxContext{ txContext := vm.TxContext{
Origin: origin, Origin: origin,

@ -92,7 +92,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
} }
// Configure a blockchain with the given prestate // Configure a blockchain with the given prestate
var ( var (
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
origin, _ = signer.Sender(tx) origin, _ = signer.Sender(tx)
txContext = vm.TxContext{ txContext = vm.TxContext{
Origin: origin, Origin: origin,

@ -1305,8 +1305,8 @@ type RPCTransaction struct {
// newRPCTransaction returns a transaction that will serialize to the RPC // newRPCTransaction returns a transaction that will serialize to the RPC
// representation, with the given location metadata set (if available). // representation, with the given location metadata set (if available).
func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction {
signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber)) signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime)
from, _ := types.Sender(signer, tx) from, _ := types.Sender(signer, tx)
v, r, s := tx.RawSignatureValues() v, r, s := tx.RawSignatureValues()
result := &RPCTransaction{ result := &RPCTransaction{
@ -1358,13 +1358,17 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
// NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation // NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction { func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction {
var baseFee *big.Int var (
blockNumber := uint64(0) baseFee *big.Int
blockNumber = uint64(0)
blockTime = uint64(0)
)
if current != nil { if current != nil {
baseFee = misc.CalcBaseFee(config, current) baseFee = misc.CalcBaseFee(config, current)
blockNumber = current.Number.Uint64() blockNumber = current.Number.Uint64()
blockTime = current.Time
} }
return newRPCTransaction(tx, common.Hash{}, blockNumber, 0, baseFee, config) return newRPCTransaction(tx, common.Hash{}, blockNumber, blockTime, 0, baseFee, config)
} }
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. // newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
@ -1373,7 +1377,7 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *param
if index >= uint64(len(txs)) { if index >= uint64(len(txs)) {
return nil return nil
} }
return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee(), config) return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config)
} }
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. // newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
@ -1585,7 +1589,7 @@ func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee, s.b.ChainConfig()), nil return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, s.b.ChainConfig()), nil
} }
// No finalized transaction, try to retrieve it from the pool // No finalized transaction, try to retrieve it from the pool
if tx := s.b.GetPoolTransaction(hash); tx != nil { if tx := s.b.GetPoolTransaction(hash); tx != nil {
@ -1621,7 +1625,10 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.
// as per specification. // as per specification.
return nil, nil return nil, nil
} }
header, err := s.b.HeaderByHash(ctx, blockHash)
if err != nil {
return nil, err
}
receipts, err := s.b.GetReceipts(ctx, blockHash) receipts, err := s.b.GetReceipts(ctx, blockHash)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1632,8 +1639,7 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.
receipt := receipts[index] receipt := receipts[index]
// Derive the sender. // Derive the sender.
bigblock := new(big.Int).SetUint64(blockNumber) signer := types.MakeSigner(s.b.ChainConfig(), header.Number, header.Time)
signer := types.MakeSigner(s.b.ChainConfig(), bigblock)
from, _ := types.Sender(signer, tx) from, _ := types.Sender(signer, tx)
fields := map[string]interface{}{ fields := map[string]interface{}{
@ -1697,7 +1703,8 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c
return common.Hash{}, err return common.Hash{}, err
} }
// Print a log with full tx details for manual investigations and interventions // Print a log with full tx details for manual investigations and interventions
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number) head := b.CurrentBlock()
signer := types.MakeSigner(b.ChainConfig(), head.Number, head.Time)
from, err := types.Sender(signer, tx) from, err := types.Sender(signer, tx)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err

@ -51,7 +51,7 @@ func TestTransaction_RoundTripRpcJSON(t *testing.T) {
} }
// rpcTransaction // rpcTransaction
rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, nil, config) rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config)
if data, err := json.Marshal(rpcTx); err != nil { if data, err := json.Marshal(rpcTx); err != nil {
t.Fatalf("test %d: marshalling failed; %v", i, err) t.Fatalf("test %d: marshalling failed; %v", i, err)
} else if err = tx2.UnmarshalJSON(data); err != nil { } else if err = tx2.UnmarshalJSON(data); err != nil {

@ -41,7 +41,7 @@ func makeChain(n int, seed byte, parent *types.Block, empty bool) ([]*types.Bloc
block.SetCoinbase(common.Address{seed}) block.SetCoinbase(common.Address{seed})
// Add one tx to every secondblock // Add one tx to every secondblock
if !empty && i%2 == 0 { if !empty && i%2 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number()) signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp())
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey)
if err != nil { if err != nil {
panic(err) panic(err)

@ -131,7 +131,7 @@ func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool)
} }
// Include transactions to the miner to make blocks more interesting. // Include transactions to the miner to make blocks more interesting.
if parent == tc.genesis && i%22 == 0 { if parent == tc.genesis && i%22 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number()) signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp())
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey)
if err != nil { if err != nil {
panic(err) panic(err)

@ -57,7 +57,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common
// If the block number is multiple of 3, send a bonus transaction to the miner // If the block number is multiple of 3, send a bonus transaction to the miner
if parent == genesis && i%3 == 0 { if parent == genesis && i%3 == 0 {
signer := types.MakeSigner(params.TestChainConfig, block.Number()) signer := types.MakeSigner(params.TestChainConfig, block.Number(), block.Timestamp())
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, block.BaseFee(), nil), signer, testKey)
if err != nil { if err != nil {
panic(err) panic(err)

@ -371,7 +371,7 @@ func testGetReceipt(t *testing.T, protocol int) {
block := bc.GetBlockByNumber(i) block := bc.GetBlockByNumber(i)
hashes = append(hashes, block.Hash()) hashes = append(hashes, block.Hash())
receipts = append(receipts, rawdb.ReadReceipts(server.db, block.Hash(), block.NumberU64(), bc.Config())) receipts = append(receipts, rawdb.ReadReceipts(server.db, block.Hash(), block.NumberU64(), block.Time(), bc.Config()))
} }
// Send the hash request and verify the response // Send the hash request and verify the response
sendRequest(rawPeer.app, GetReceiptsMsg, 42, hashes) sendRequest(rawPeer.app, GetReceiptsMsg, 42, hashes)

@ -68,7 +68,9 @@ func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.Chain
var receipts types.Receipts var receipts types.Receipts
if bc != nil { if bc != nil {
if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { if number := rawdb.ReadHeaderNumber(db, bhash); number != nil {
receipts = rawdb.ReadReceipts(db, bhash, *number, config) if header := rawdb.ReadHeader(db, bhash, *number); header != nil {
receipts = rawdb.ReadReceipts(db, bhash, *number, header.Time, config)
}
} }
} else { } else {
if number := rawdb.ReadHeaderNumber(db, bhash); number != nil { if number := rawdb.ReadHeaderNumber(db, bhash); number != nil {

@ -57,7 +57,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
return nil, vm.BlockContext{}, statedb, release, nil return nil, vm.BlockContext{}, statedb, release, nil
} }
// Recompute transactions up to the target index. // Recompute transactions up to the target index.
signer := types.MakeSigner(leth.blockchain.Config(), block.Number()) signer := types.MakeSigner(leth.blockchain.Config(), block.Number(), block.Time())
for idx, tx := range block.Transactions() { for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset // Assemble the transaction call message and return if the requested offset
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())

@ -131,9 +131,10 @@ func TestOdrGetReceiptsLes2(t *testing.T) { testChainOdr(t, 1, odrGetReceipts) }
func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
var receipts types.Receipts var receipts types.Receipts
if bc != nil { if bc != nil {
number := rawdb.ReadHeaderNumber(db, bhash) if number := rawdb.ReadHeaderNumber(db, bhash); number != nil {
if number != nil { if header := rawdb.ReadHeader(db, bhash, *number); header != nil {
receipts = rawdb.ReadReceipts(db, bhash, *number, bc.Config()) receipts = rawdb.ReadReceipts(db, bhash, *number, header.Time, bc.Config())
}
} }
} else { } else {
number := rawdb.ReadHeaderNumber(db, bhash) number := rawdb.ReadHeaderNumber(db, bhash)

@ -175,7 +175,7 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num
genesis := rawdb.ReadCanonicalHash(odr.Database(), 0) genesis := rawdb.ReadCanonicalHash(odr.Database(), 0)
config := rawdb.ReadChainConfig(odr.Database(), genesis) config := rawdb.ReadChainConfig(odr.Database(), genesis)
if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.BaseFee(), block.Transactions()); err != nil { if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), block.Transactions()); err != nil {
return nil, err return nil, err
} }
rawdb.WriteReceipts(odr.Database(), hash, number, receipts) rawdb.WriteReceipts(odr.Database(), hash, number, receipts)

@ -801,7 +801,7 @@ func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase co
// Note the passed coinbase may be different with header.Coinbase. // Note the passed coinbase may be different with header.Coinbase.
env := &environment{ env := &environment{
signer: types.MakeSigner(w.chainConfig, header.Number), signer: types.MakeSigner(w.chainConfig, header.Number, header.Time),
state: state, state: state,
coinbase: coinbase, coinbase: coinbase,
ancestors: mapset.NewSet[common.Hash](), ancestors: mapset.NewSet[common.Hash](),

@ -160,6 +160,7 @@ const (
RefundQuotient uint64 = 2 RefundQuotient uint64 = 2
RefundQuotientEIP3529 uint64 = 5 RefundQuotientEIP3529 uint64 = 5
BlobTxDataGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
BlobTxMinDataGasprice = 1 // Minimum gas price for data blobs BlobTxMinDataGasprice = 1 // Minimum gas price for data blobs
BlobTxDataGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for data gas price BlobTxDataGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for data gas price
) )