consensus, core, eth/downloader, params: 4844 chain validation (#27382)
This commit is contained in:
parent
cc2ab421e4
commit
1f9b69b36d
@ -257,7 +257,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
|||||||
return consensus.ErrInvalidNumber
|
return consensus.ErrInvalidNumber
|
||||||
}
|
}
|
||||||
// Verify the header's EIP-1559 attributes.
|
// Verify the header's EIP-1559 attributes.
|
||||||
if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil {
|
if err := misc.VerifyEIP1559Header(chain.Config(), parent, header); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Verify existence / non-existence of withdrawalsHash.
|
// Verify existence / non-existence of withdrawalsHash.
|
||||||
@ -270,12 +270,17 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
|||||||
}
|
}
|
||||||
// Verify the existence / non-existence of excessDataGas
|
// Verify the existence / non-existence of excessDataGas
|
||||||
cancun := chain.Config().IsCancun(header.Number, header.Time)
|
cancun := chain.Config().IsCancun(header.Number, header.Time)
|
||||||
if cancun && header.ExcessDataGas == nil {
|
|
||||||
return errors.New("missing excessDataGas")
|
|
||||||
}
|
|
||||||
if !cancun && header.ExcessDataGas != nil {
|
if !cancun && header.ExcessDataGas != nil {
|
||||||
return fmt.Errorf("invalid excessDataGas: have %d, expected nil", header.ExcessDataGas)
|
return fmt.Errorf("invalid excessDataGas: have %d, expected nil", header.ExcessDataGas)
|
||||||
}
|
}
|
||||||
|
if !cancun && header.DataGasUsed != nil {
|
||||||
|
return fmt.Errorf("invalid dataGasUsed: have %d, expected nil", header.DataGasUsed)
|
||||||
|
}
|
||||||
|
if cancun {
|
||||||
|
if err := misc.VerifyEIP4844Header(parent, header); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header
|
|||||||
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
|
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil {
|
} else if err := misc.VerifyEIP1559Header(chain.Config(), parent, header); err != nil {
|
||||||
// Verify the header's EIP-1559 attributes.
|
// Verify the header's EIP-1559 attributes.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
|||||||
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
|
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil {
|
} else if err := misc.VerifyEIP1559Header(chain.Config(), parent, header); err != nil {
|
||||||
// Verify the header's EIP-1559 attributes.
|
// Verify the header's EIP-1559 attributes.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,10 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VerifyEip1559Header verifies some header attributes which were changed in EIP-1559,
|
// VerifyEIP1559Header verifies some header attributes which were changed in EIP-1559,
|
||||||
// - gas limit check
|
// - gas limit check
|
||||||
// - basefee check
|
// - basefee check
|
||||||
func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Header) error {
|
func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Header) error {
|
||||||
// Verify that the gas limit remains within allowed bounds
|
// Verify that the gas limit remains within allowed bounds
|
||||||
parentGasLimit := parent.GasLimit
|
parentGasLimit := parent.GasLimit
|
||||||
if !config.IsLondon(parent.Number) {
|
if !config.IsLondon(parent.Number) {
|
||||||
|
@ -95,7 +95,7 @@ func TestBlockGasLimits(t *testing.T) {
|
|||||||
BaseFee: initial,
|
BaseFee: initial,
|
||||||
Number: big.NewInt(tc.pNum + 1),
|
Number: big.NewInt(tc.pNum + 1),
|
||||||
}
|
}
|
||||||
err := VerifyEip1559Header(config(), parent, header)
|
err := VerifyEIP1559Header(config(), parent, header)
|
||||||
if tc.ok && err != nil {
|
if tc.ok && err != nil {
|
||||||
t.Errorf("test %d: Expected valid header: %s", i, err)
|
t.Errorf("test %d: Expected valid header: %s", i, err)
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,11 @@
|
|||||||
package misc
|
package misc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,13 +30,54 @@ var (
|
|||||||
dataGaspriceUpdateFraction = big.NewInt(params.BlobTxDataGaspriceUpdateFraction)
|
dataGaspriceUpdateFraction = big.NewInt(params.BlobTxDataGaspriceUpdateFraction)
|
||||||
)
|
)
|
||||||
|
|
||||||
// CalcBlobFee calculates the blobfee from the header's excess data gas field.
|
// VerifyEIP4844Header verifies the presence of the excessDataGas field and that
|
||||||
func CalcBlobFee(excessDataGas *big.Int) *big.Int {
|
// if the current block contains no transactions, the excessDataGas is updated
|
||||||
// If this block does not yet have EIP-4844 enabled, return the starting fee
|
// accordingly.
|
||||||
if excessDataGas == nil {
|
func VerifyEIP4844Header(parent, header *types.Header) error {
|
||||||
return big.NewInt(params.BlobTxMinDataGasprice)
|
// Verify the header is not malformed
|
||||||
|
if header.ExcessDataGas == nil {
|
||||||
|
return errors.New("header is missing excessDataGas")
|
||||||
}
|
}
|
||||||
return fakeExponential(minDataGasPrice, excessDataGas, dataGaspriceUpdateFraction)
|
if header.DataGasUsed == nil {
|
||||||
|
return errors.New("header is missing dataGasUsed")
|
||||||
|
}
|
||||||
|
// Verify that the data gas used remains within reasonable limits.
|
||||||
|
if *header.DataGasUsed > params.BlobTxMaxDataGasPerBlock {
|
||||||
|
return fmt.Errorf("data gas used %d exceeds maximum allowance %d", *header.DataGasUsed, params.BlobTxMaxDataGasPerBlock)
|
||||||
|
}
|
||||||
|
if *header.DataGasUsed%params.BlobTxDataGasPerBlob != 0 {
|
||||||
|
return fmt.Errorf("data gas used %d not a multiple of data gas per blob %d", header.DataGasUsed, params.BlobTxDataGasPerBlob)
|
||||||
|
}
|
||||||
|
// Verify the excessDataGas is correct based on the parent header
|
||||||
|
var (
|
||||||
|
parentExcessDataGas uint64
|
||||||
|
parentDataGasUsed uint64
|
||||||
|
)
|
||||||
|
if parent.ExcessDataGas != nil {
|
||||||
|
parentExcessDataGas = *parent.ExcessDataGas
|
||||||
|
parentDataGasUsed = *parent.DataGasUsed
|
||||||
|
}
|
||||||
|
expectedExcessDataGas := CalcExcessDataGas(parentExcessDataGas, parentDataGasUsed)
|
||||||
|
if *header.ExcessDataGas != expectedExcessDataGas {
|
||||||
|
return fmt.Errorf("invalid excessDataGas: have %d, want %d, parent excessDataGas %d, parent blobDataUsed %d",
|
||||||
|
*header.ExcessDataGas, expectedExcessDataGas, parentExcessDataGas, parentDataGasUsed)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalcExcessDataGas calculates the excess data gas after applying the set of
|
||||||
|
// blobs on top of the excess data gas.
|
||||||
|
func CalcExcessDataGas(parentExcessDataGas uint64, parentDataGasUsed uint64) uint64 {
|
||||||
|
excessDataGas := parentExcessDataGas + parentDataGasUsed
|
||||||
|
if excessDataGas < params.BlobTxTargetDataGasPerBlock {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return excessDataGas - params.BlobTxTargetDataGasPerBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalcBlobFee calculates the blobfee from the header's excess data gas field.
|
||||||
|
func CalcBlobFee(excessDataGas uint64) *big.Int {
|
||||||
|
return fakeExponential(minDataGasPrice, new(big.Int).SetUint64(excessDataGas), dataGaspriceUpdateFraction)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
||||||
|
@ -24,9 +24,42 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestCalcExcessDataGas(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
excess uint64
|
||||||
|
blobs uint64
|
||||||
|
want uint64
|
||||||
|
}{
|
||||||
|
// The excess data gas should not increase from zero if the used blob
|
||||||
|
// slots are below - or equal - to the target.
|
||||||
|
{0, 0, 0},
|
||||||
|
{0, 1, 0},
|
||||||
|
{0, params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob, 0},
|
||||||
|
|
||||||
|
// If the target data gas is exceeded, the excessDataGas should increase
|
||||||
|
// by however much it was overshot
|
||||||
|
{0, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) + 1, params.BlobTxDataGasPerBlob},
|
||||||
|
{1, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) + 1, params.BlobTxDataGasPerBlob + 1},
|
||||||
|
{1, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) + 2, 2*params.BlobTxDataGasPerBlob + 1},
|
||||||
|
|
||||||
|
// The excess data gas should decrease by however much the target was
|
||||||
|
// under-shot, capped at zero.
|
||||||
|
{params.BlobTxTargetDataGasPerBlock, params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob, params.BlobTxTargetDataGasPerBlock},
|
||||||
|
{params.BlobTxTargetDataGasPerBlock, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) - 1, params.BlobTxDataGasPerBlob},
|
||||||
|
{params.BlobTxTargetDataGasPerBlock, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) - 2, 0},
|
||||||
|
{params.BlobTxDataGasPerBlob - 1, (params.BlobTxTargetDataGasPerBlock / params.BlobTxDataGasPerBlob) - 1, 0},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
result := CalcExcessDataGas(tt.excess, tt.blobs*params.BlobTxDataGasPerBlob)
|
||||||
|
if result != tt.want {
|
||||||
|
t.Errorf("excess data gas mismatch: have %v, want %v", result, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCalcBlobFee(t *testing.T) {
|
func TestCalcBlobFee(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
excessDataGas int64
|
excessDataGas uint64
|
||||||
blobfee int64
|
blobfee int64
|
||||||
}{
|
}{
|
||||||
{0, 1},
|
{0, 1},
|
||||||
@ -34,12 +67,8 @@ func TestCalcBlobFee(t *testing.T) {
|
|||||||
{1542707, 2},
|
{1542707, 2},
|
||||||
{10 * 1024 * 1024, 111},
|
{10 * 1024 * 1024, 111},
|
||||||
}
|
}
|
||||||
have := CalcBlobFee(nil)
|
|
||||||
if have.Int64() != params.BlobTxMinDataGasprice {
|
|
||||||
t.Errorf("nil test: blobfee mismatch: have %v, want %v", have, params.BlobTxMinDataGasprice)
|
|
||||||
}
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
have := CalcBlobFee(big.NewInt(tt.excessDataGas))
|
have := CalcBlobFee(tt.excessDataGas)
|
||||||
if have.Int64() != tt.blobfee {
|
if have.Int64() != tt.blobfee {
|
||||||
t.Errorf("test %d: blobfee mismatch: have %v want %v", i, have, tt.blobfee)
|
t.Errorf("test %d: blobfee mismatch: have %v want %v", i, have, tt.blobfee)
|
||||||
}
|
}
|
||||||
|
@ -78,10 +78,23 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||||||
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
|
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
|
||||||
}
|
}
|
||||||
} else if block.Withdrawals() != nil {
|
} else if block.Withdrawals() != nil {
|
||||||
// Withdrawals are not allowed prior to shanghai fork
|
// Withdrawals are not allowed prior to Shanghai fork
|
||||||
return errors.New("withdrawals present in block body")
|
return errors.New("withdrawals present in block body")
|
||||||
}
|
}
|
||||||
|
// Blob transactions may be present after the Cancun fork.
|
||||||
|
var blobs int
|
||||||
|
for _, tx := range block.Transactions() {
|
||||||
|
blobs += len(tx.BlobHashes())
|
||||||
|
}
|
||||||
|
if header.DataGasUsed != nil {
|
||||||
|
if want := *header.DataGasUsed / params.BlobTxDataGasPerBlob; uint64(blobs) != want { // div because the header is surely good vs the body might be bloated
|
||||||
|
return fmt.Errorf("data gas used mismatch (header %v, calculated %v)", *header.DataGasUsed, blobs*params.BlobTxDataGasPerBlob)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if blobs > 0 {
|
||||||
|
return errors.New("data blobs present in block body")
|
||||||
|
}
|
||||||
|
}
|
||||||
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
||||||
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
|
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
|
||||||
return consensus.ErrUnknownAncestor
|
return consensus.ErrUnknownAncestor
|
||||||
|
@ -86,19 +86,24 @@ type Header struct {
|
|||||||
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
||||||
|
|
||||||
// ExcessDataGas was added by EIP-4844 and is ignored in legacy headers.
|
// ExcessDataGas was added by EIP-4844 and is ignored in legacy headers.
|
||||||
ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"`
|
ExcessDataGas *uint64 `json:"excessDataGas" rlp:"optional"`
|
||||||
|
|
||||||
|
// DataGasUsed was added by EIP-4844 and is ignored in legacy headers.
|
||||||
|
DataGasUsed *uint64 `json:"dataGasUsed" rlp:"optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// field type overrides for gencodec
|
// field type overrides for gencodec
|
||||||
type headerMarshaling struct {
|
type headerMarshaling struct {
|
||||||
Difficulty *hexutil.Big
|
Difficulty *hexutil.Big
|
||||||
Number *hexutil.Big
|
Number *hexutil.Big
|
||||||
GasLimit hexutil.Uint64
|
GasLimit hexutil.Uint64
|
||||||
GasUsed hexutil.Uint64
|
GasUsed hexutil.Uint64
|
||||||
Time hexutil.Uint64
|
Time hexutil.Uint64
|
||||||
Extra hexutil.Bytes
|
Extra hexutil.Bytes
|
||||||
BaseFee *hexutil.Big
|
BaseFee *hexutil.Big
|
||||||
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
|
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
|
||||||
|
ExcessDataGas *hexutil.Uint64
|
||||||
|
DataGasUsed *hexutil.Uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash returns the block hash of the header, which is simply the keccak256 hash of its
|
// Hash returns the block hash of the header, which is simply the keccak256 hash of its
|
||||||
@ -146,10 +151,10 @@ func (h *Header) SanityCheck() error {
|
|||||||
// EmptyBody returns true if there is no additional 'body' to complete the header
|
// EmptyBody returns true if there is no additional 'body' to complete the header
|
||||||
// that is: no transactions, no uncles and no withdrawals.
|
// that is: no transactions, no uncles and no withdrawals.
|
||||||
func (h *Header) EmptyBody() bool {
|
func (h *Header) EmptyBody() bool {
|
||||||
if h.WithdrawalsHash == nil {
|
if h.WithdrawalsHash != nil {
|
||||||
return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash
|
return h.TxHash == EmptyTxsHash && *h.WithdrawalsHash == EmptyWithdrawalsHash
|
||||||
}
|
}
|
||||||
return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash && *h.WithdrawalsHash == EmptyWithdrawalsHash
|
return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmptyReceipts returns true if there are no receipts for this header/block.
|
// EmptyReceipts returns true if there are no receipts for this header/block.
|
||||||
@ -347,6 +352,24 @@ func (b *Block) Withdrawals() Withdrawals {
|
|||||||
return b.withdrawals
|
return b.withdrawals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Block) ExcessDataGas() *uint64 {
|
||||||
|
var excessDataGas *uint64
|
||||||
|
if b.header.ExcessDataGas != nil {
|
||||||
|
excessDataGas = new(uint64)
|
||||||
|
*excessDataGas = *b.header.ExcessDataGas
|
||||||
|
}
|
||||||
|
return excessDataGas
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Block) DataGasUsed() *uint64 {
|
||||||
|
var dataGasUsed *uint64
|
||||||
|
if b.header.DataGasUsed != nil {
|
||||||
|
dataGasUsed = new(uint64)
|
||||||
|
*dataGasUsed = *b.header.DataGasUsed
|
||||||
|
}
|
||||||
|
return dataGasUsed
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Block) Header() *Header { return CopyHeader(b.header) }
|
func (b *Block) Header() *Header { return CopyHeader(b.header) }
|
||||||
|
|
||||||
// Body returns the non-header content of the block.
|
// Body returns the non-header content of the block.
|
||||||
|
@ -16,25 +16,26 @@ var _ = (*headerMarshaling)(nil)
|
|||||||
// MarshalJSON marshals as JSON.
|
// MarshalJSON marshals as JSON.
|
||||||
func (h Header) MarshalJSON() ([]byte, error) {
|
func (h Header) MarshalJSON() ([]byte, error) {
|
||||||
type Header struct {
|
type Header struct {
|
||||||
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
|
||||||
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
|
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
|
||||||
Coinbase common.Address `json:"miner"`
|
Coinbase common.Address `json:"miner"`
|
||||||
Root common.Hash `json:"stateRoot" gencodec:"required"`
|
Root common.Hash `json:"stateRoot" gencodec:"required"`
|
||||||
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
|
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
|
||||||
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
|
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
|
||||||
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
|
||||||
Number *hexutil.Big `json:"number" gencodec:"required"`
|
Number *hexutil.Big `json:"number" gencodec:"required"`
|
||||||
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
|
||||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
Time hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
Time hexutil.Uint64 `json:"timestamp" gencodec:"required"`
|
||||||
Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
|
Extra hexutil.Bytes `json:"extraData" gencodec:"required"`
|
||||||
MixDigest common.Hash `json:"mixHash"`
|
MixDigest common.Hash `json:"mixHash"`
|
||||||
Nonce BlockNonce `json:"nonce"`
|
Nonce BlockNonce `json:"nonce"`
|
||||||
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
||||||
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
||||||
ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"`
|
ExcessDataGas *hexutil.Uint64 `json:"excessDataGas" rlp:"optional"`
|
||||||
Hash common.Hash `json:"hash"`
|
DataGasUsed *hexutil.Uint64 `json:"dataGasUsed" rlp:"optional"`
|
||||||
|
Hash common.Hash `json:"hash"`
|
||||||
}
|
}
|
||||||
var enc Header
|
var enc Header
|
||||||
enc.ParentHash = h.ParentHash
|
enc.ParentHash = h.ParentHash
|
||||||
@ -54,7 +55,8 @@ func (h Header) MarshalJSON() ([]byte, error) {
|
|||||||
enc.Nonce = h.Nonce
|
enc.Nonce = h.Nonce
|
||||||
enc.BaseFee = (*hexutil.Big)(h.BaseFee)
|
enc.BaseFee = (*hexutil.Big)(h.BaseFee)
|
||||||
enc.WithdrawalsHash = h.WithdrawalsHash
|
enc.WithdrawalsHash = h.WithdrawalsHash
|
||||||
enc.ExcessDataGas = h.ExcessDataGas
|
enc.ExcessDataGas = (*hexutil.Uint64)(h.ExcessDataGas)
|
||||||
|
enc.DataGasUsed = (*hexutil.Uint64)(h.DataGasUsed)
|
||||||
enc.Hash = h.Hash()
|
enc.Hash = h.Hash()
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
@ -79,7 +81,8 @@ func (h *Header) UnmarshalJSON(input []byte) error {
|
|||||||
Nonce *BlockNonce `json:"nonce"`
|
Nonce *BlockNonce `json:"nonce"`
|
||||||
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
|
||||||
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
|
||||||
ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"`
|
ExcessDataGas *hexutil.Uint64 `json:"excessDataGas" rlp:"optional"`
|
||||||
|
DataGasUsed *hexutil.Uint64 `json:"dataGasUsed" rlp:"optional"`
|
||||||
}
|
}
|
||||||
var dec Header
|
var dec Header
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
@ -149,7 +152,10 @@ func (h *Header) UnmarshalJSON(input []byte) error {
|
|||||||
h.WithdrawalsHash = dec.WithdrawalsHash
|
h.WithdrawalsHash = dec.WithdrawalsHash
|
||||||
}
|
}
|
||||||
if dec.ExcessDataGas != nil {
|
if dec.ExcessDataGas != nil {
|
||||||
h.ExcessDataGas = dec.ExcessDataGas
|
h.ExcessDataGas = (*uint64)(dec.ExcessDataGas)
|
||||||
|
}
|
||||||
|
if dec.DataGasUsed != nil {
|
||||||
|
h.DataGasUsed = (*uint64)(dec.DataGasUsed)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
|
|||||||
_tmp1 := obj.BaseFee != nil
|
_tmp1 := obj.BaseFee != nil
|
||||||
_tmp2 := obj.WithdrawalsHash != nil
|
_tmp2 := obj.WithdrawalsHash != nil
|
||||||
_tmp3 := obj.ExcessDataGas != nil
|
_tmp3 := obj.ExcessDataGas != nil
|
||||||
if _tmp1 || _tmp2 || _tmp3 {
|
_tmp4 := obj.DataGasUsed != nil
|
||||||
|
if _tmp1 || _tmp2 || _tmp3 || _tmp4 {
|
||||||
if obj.BaseFee == nil {
|
if obj.BaseFee == nil {
|
||||||
w.Write(rlp.EmptyString)
|
w.Write(rlp.EmptyString)
|
||||||
} else {
|
} else {
|
||||||
@ -53,21 +54,25 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
|
|||||||
w.WriteBigInt(obj.BaseFee)
|
w.WriteBigInt(obj.BaseFee)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp2 || _tmp3 {
|
if _tmp2 || _tmp3 || _tmp4 {
|
||||||
if obj.WithdrawalsHash == nil {
|
if obj.WithdrawalsHash == nil {
|
||||||
w.Write([]byte{0x80})
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
w.WriteBytes(obj.WithdrawalsHash[:])
|
w.WriteBytes(obj.WithdrawalsHash[:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _tmp3 {
|
if _tmp3 || _tmp4 {
|
||||||
if obj.ExcessDataGas == nil {
|
if obj.ExcessDataGas == nil {
|
||||||
w.Write(rlp.EmptyString)
|
w.Write([]byte{0x80})
|
||||||
} else {
|
} else {
|
||||||
if obj.ExcessDataGas.Sign() == -1 {
|
w.WriteUint64((*obj.ExcessDataGas))
|
||||||
return rlp.ErrNegativeBigInt
|
}
|
||||||
}
|
}
|
||||||
w.WriteBigInt(obj.ExcessDataGas)
|
if _tmp4 {
|
||||||
|
if obj.DataGasUsed == nil {
|
||||||
|
w.Write([]byte{0x80})
|
||||||
|
} else {
|
||||||
|
w.WriteUint64((*obj.DataGasUsed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.ListEnd(_tmp0)
|
w.ListEnd(_tmp0)
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -796,6 +797,21 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH
|
|||||||
return errInvalidBody
|
return errInvalidBody
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Blocks must have a number of blobs corresponding to the header gas usage,
|
||||||
|
// and zero before the Cancun hardfork
|
||||||
|
var blobs int
|
||||||
|
for _, tx := range txLists[index] {
|
||||||
|
blobs += len(tx.BlobHashes())
|
||||||
|
}
|
||||||
|
if header.DataGasUsed != nil {
|
||||||
|
if want := *header.DataGasUsed / params.BlobTxDataGasPerBlob; uint64(blobs) != want { // div because the header is surely good vs the body might be bloated
|
||||||
|
return errInvalidBody
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if blobs != 0 {
|
||||||
|
return errInvalidBody
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +160,8 @@ const (
|
|||||||
RefundQuotient uint64 = 2
|
RefundQuotient uint64 = 2
|
||||||
RefundQuotientEIP3529 uint64 = 5
|
RefundQuotientEIP3529 uint64 = 5
|
||||||
|
|
||||||
|
BlobTxMaxDataGasPerBlock = 1 << 19 // Maximum consumable data gas for data blobs per block
|
||||||
|
BlobTxTargetDataGasPerBlock = 1 << 18 // Target consumable data gas for data blobs per block (for 1559-like pricing)
|
||||||
BlobTxDataGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user