params,core: add max and target value to chain config (#31002)
Implements [EIP-7840](https://github.com/ethereum/EIPs/pull/9129) and
[EIP-7691](d96625a4dc/EIPS/eip-7691.md
).
---------
Co-authored-by: Marius van der Wijden <m.vanderwijden@live.de>
Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
parent
eee868226a
commit
e6f3ce7b16
|
@ -743,7 +743,7 @@ func (s *Suite) makeBlobTxs(count, blobs int, discriminator byte) (txs types.Tra
|
||||||
GasTipCap: uint256.NewInt(1),
|
GasTipCap: uint256.NewInt(1),
|
||||||
GasFeeCap: uint256.MustFromBig(s.chain.Head().BaseFee()),
|
GasFeeCap: uint256.MustFromBig(s.chain.Head().BaseFee()),
|
||||||
Gas: 100000,
|
Gas: 100000,
|
||||||
BlobFeeCap: uint256.MustFromBig(eip4844.CalcBlobFee(*s.chain.Head().ExcessBlobGas())),
|
BlobFeeCap: uint256.MustFromBig(eip4844.CalcBlobFee(s.chain.config, s.chain.Head().Header())),
|
||||||
BlobHashes: makeSidecar(blobdata...).BlobHashes(),
|
BlobHashes: makeSidecar(blobdata...).BlobHashes(),
|
||||||
Sidecar: makeSidecar(blobdata...),
|
Sidecar: makeSidecar(blobdata...),
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,14 @@
|
||||||
"shanghaiTime": 780,
|
"shanghaiTime": 780,
|
||||||
"cancunTime": 840,
|
"cancunTime": 840,
|
||||||
"terminalTotalDifficulty": 9454784,
|
"terminalTotalDifficulty": 9454784,
|
||||||
"ethash": {}
|
"ethash": {},
|
||||||
|
"blobSchedule": {
|
||||||
|
"cancun": {
|
||||||
|
"target": 3,
|
||||||
|
"max": 6,
|
||||||
|
"baseFeeUpdateFraction": 3338477
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"nonce": "0x0",
|
"nonce": "0x0",
|
||||||
"timestamp": "0x0",
|
"timestamp": "0x0",
|
||||||
|
@ -108,4 +115,4 @@
|
||||||
"baseFeePerGas": null,
|
"baseFeePerGas": null,
|
||||||
"excessBlobGas": null,
|
"excessBlobGas": null,
|
||||||
"blobGasUsed": null
|
"blobGasUsed": null
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,15 +178,28 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
var excessBlobGas uint64
|
var excessBlobGas uint64
|
||||||
if pre.Env.ExcessBlobGas != nil {
|
if pre.Env.ExcessBlobGas != nil {
|
||||||
excessBlobGas = *pre.Env.ExcessBlobGas
|
excessBlobGas = *pre.Env.ExcessBlobGas
|
||||||
vmContext.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas)
|
header := &types.Header{
|
||||||
|
Time: pre.Env.Timestamp,
|
||||||
|
ExcessBlobGas: pre.Env.ExcessBlobGas,
|
||||||
|
}
|
||||||
|
vmContext.BlobBaseFee = eip4844.CalcBlobFee(chainConfig, header)
|
||||||
} else {
|
} else {
|
||||||
// If it is not explicitly defined, but we have the parent values, we try
|
// If it is not explicitly defined, but we have the parent values, we try
|
||||||
// to calculate it ourselves.
|
// to calculate it ourselves.
|
||||||
parentExcessBlobGas := pre.Env.ParentExcessBlobGas
|
parentExcessBlobGas := pre.Env.ParentExcessBlobGas
|
||||||
parentBlobGasUsed := pre.Env.ParentBlobGasUsed
|
parentBlobGasUsed := pre.Env.ParentBlobGasUsed
|
||||||
if parentExcessBlobGas != nil && parentBlobGasUsed != nil {
|
if parentExcessBlobGas != nil && parentBlobGasUsed != nil {
|
||||||
excessBlobGas = eip4844.CalcExcessBlobGas(*parentExcessBlobGas, *parentBlobGasUsed)
|
parent := &types.Header{
|
||||||
vmContext.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas)
|
Time: pre.Env.ParentTimestamp,
|
||||||
|
ExcessBlobGas: pre.Env.ParentExcessBlobGas,
|
||||||
|
BlobGasUsed: pre.Env.ParentBlobGasUsed,
|
||||||
|
}
|
||||||
|
excessBlobGas = eip4844.CalcExcessBlobGas(chainConfig, parent)
|
||||||
|
header := &types.Header{
|
||||||
|
Time: pre.Env.Timestamp,
|
||||||
|
ExcessBlobGas: &excessBlobGas,
|
||||||
|
}
|
||||||
|
vmContext.BlobBaseFee = eip4844.CalcBlobFee(chainConfig, header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's
|
// If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's
|
||||||
|
@ -229,7 +242,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
txBlobGas := uint64(0)
|
txBlobGas := uint64(0)
|
||||||
if tx.Type() == types.BlobTxType {
|
if tx.Type() == types.BlobTxType {
|
||||||
txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes()))
|
txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes()))
|
||||||
if used, max := blobGasUsed+txBlobGas, uint64(params.MaxBlobGasPerBlock); used > max {
|
max := eip4844.MaxBlobGasPerBlock(chainConfig, pre.Env.Timestamp)
|
||||||
|
if used := blobGasUsed + txBlobGas; used > max {
|
||||||
err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max)
|
err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max)
|
||||||
log.Warn("rejected tx", "index", i, "err", err)
|
log.Warn("rejected tx", "index", i, "err", err)
|
||||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||||
|
|
|
@ -282,7 +282,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
if header.ParentBeaconRoot == nil {
|
if header.ParentBeaconRoot == nil {
|
||||||
return errors.New("header is missing beaconRoot")
|
return errors.New("header is missing beaconRoot")
|
||||||
}
|
}
|
||||||
if err := eip4844.VerifyEIP4844Header(parent, header); err != nil {
|
if err := eip4844.VerifyEIP4844Header(chain.Config(), parent, header); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,17 +23,17 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
minBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice)
|
minBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice)
|
||||||
blobGaspriceUpdateFraction = big.NewInt(params.BlobTxBlobGaspriceUpdateFraction)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
|
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
|
||||||
// if the current block contains no transactions, the excessBlobGas is updated
|
// if the current block contains no transactions, the excessBlobGas is updated
|
||||||
// accordingly.
|
// accordingly.
|
||||||
func VerifyEIP4844Header(parent, header *types.Header) error {
|
func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Header) error {
|
||||||
// Verify the header is not malformed
|
// Verify the header is not malformed
|
||||||
if header.ExcessBlobGas == nil {
|
if header.ExcessBlobGas == nil {
|
||||||
return errors.New("header is missing excessBlobGas")
|
return errors.New("header is missing excessBlobGas")
|
||||||
|
@ -42,14 +42,26 @@ func VerifyEIP4844Header(parent, header *types.Header) error {
|
||||||
return errors.New("header is missing blobGasUsed")
|
return errors.New("header is missing blobGasUsed")
|
||||||
}
|
}
|
||||||
// Verify that the blob gas used remains within reasonable limits.
|
// Verify that the blob gas used remains within reasonable limits.
|
||||||
if *header.BlobGasUsed > params.MaxBlobGasPerBlock {
|
maxBlobGas := MaxBlobGasPerBlock(config, header.Time)
|
||||||
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, params.MaxBlobGasPerBlock)
|
if *header.BlobGasUsed > maxBlobGas {
|
||||||
|
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, maxBlobGas)
|
||||||
}
|
}
|
||||||
if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 {
|
if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 {
|
||||||
return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob)
|
return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob)
|
||||||
}
|
}
|
||||||
// Verify the excessBlobGas is correct based on the parent header
|
// Verify the excessBlobGas is correct based on the parent header
|
||||||
|
expectedExcessBlobGas := CalcExcessBlobGas(config, parent)
|
||||||
|
if *header.ExcessBlobGas != expectedExcessBlobGas {
|
||||||
|
return fmt.Errorf("invalid excessBlobGas: have %d, want %d", *header.ExcessBlobGas, expectedExcessBlobGas)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalcExcessBlobGas calculates the excess blob gas after applying the set of
|
||||||
|
// blobs on top of the excess blob gas.
|
||||||
|
func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 {
|
||||||
var (
|
var (
|
||||||
|
targetGas = uint64(targetBlobsPerBlock(config, parent.Time)) * params.BlobTxBlobGasPerBlob
|
||||||
parentExcessBlobGas uint64
|
parentExcessBlobGas uint64
|
||||||
parentBlobGasUsed uint64
|
parentBlobGasUsed uint64
|
||||||
)
|
)
|
||||||
|
@ -57,27 +69,85 @@ func VerifyEIP4844Header(parent, header *types.Header) error {
|
||||||
parentExcessBlobGas = *parent.ExcessBlobGas
|
parentExcessBlobGas = *parent.ExcessBlobGas
|
||||||
parentBlobGasUsed = *parent.BlobGasUsed
|
parentBlobGasUsed = *parent.BlobGasUsed
|
||||||
}
|
}
|
||||||
expectedExcessBlobGas := CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed)
|
|
||||||
if *header.ExcessBlobGas != expectedExcessBlobGas {
|
|
||||||
return fmt.Errorf("invalid excessBlobGas: have %d, want %d, parent excessBlobGas %d, parent blobDataUsed %d",
|
|
||||||
*header.ExcessBlobGas, expectedExcessBlobGas, parentExcessBlobGas, parentBlobGasUsed)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CalcExcessBlobGas calculates the excess blob gas after applying the set of
|
|
||||||
// blobs on top of the excess blob gas.
|
|
||||||
func CalcExcessBlobGas(parentExcessBlobGas uint64, parentBlobGasUsed uint64) uint64 {
|
|
||||||
excessBlobGas := parentExcessBlobGas + parentBlobGasUsed
|
excessBlobGas := parentExcessBlobGas + parentBlobGasUsed
|
||||||
if excessBlobGas < params.BlobTxTargetBlobGasPerBlock {
|
if excessBlobGas < targetGas {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return excessBlobGas - params.BlobTxTargetBlobGasPerBlock
|
return excessBlobGas - targetGas
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalcBlobFee calculates the blobfee from the header's excess blob gas field.
|
// CalcBlobFee calculates the blobfee from the header's excess blob gas field.
|
||||||
func CalcBlobFee(excessBlobGas uint64) *big.Int {
|
func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
|
||||||
return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(excessBlobGas), blobGaspriceUpdateFraction)
|
var frac uint64
|
||||||
|
switch config.LatestFork(header.Time) {
|
||||||
|
case forks.Prague:
|
||||||
|
frac = config.BlobScheduleConfig.Prague.UpdateFraction
|
||||||
|
case forks.Cancun:
|
||||||
|
frac = config.BlobScheduleConfig.Cancun.UpdateFraction
|
||||||
|
default:
|
||||||
|
panic("calculating blob fee on unsupported fork")
|
||||||
|
}
|
||||||
|
return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(frac))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
|
||||||
|
func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
|
||||||
|
if cfg.BlobScheduleConfig == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
london = cfg.LondonBlock
|
||||||
|
s = cfg.BlobScheduleConfig
|
||||||
|
)
|
||||||
|
switch {
|
||||||
|
case cfg.IsPrague(london, time) && s.Prague != nil:
|
||||||
|
return s.Prague.Max
|
||||||
|
case cfg.IsCancun(london, time) && s.Cancun != nil:
|
||||||
|
return s.Cancun.Max
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxBlobsPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp.
|
||||||
|
func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 {
|
||||||
|
return uint64(MaxBlobsPerBlock(cfg, time)) * params.BlobTxBlobGasPerBlob
|
||||||
|
}
|
||||||
|
|
||||||
|
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
|
||||||
|
// configuration, regardless of the currently active fork.
|
||||||
|
func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int {
|
||||||
|
s := cfg.BlobScheduleConfig
|
||||||
|
if s == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case s.Prague != nil:
|
||||||
|
return s.Prague.Max
|
||||||
|
case s.Cancun != nil:
|
||||||
|
return s.Cancun.Max
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp.
|
||||||
|
func targetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
|
||||||
|
if cfg.BlobScheduleConfig == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
london = cfg.LondonBlock
|
||||||
|
s = cfg.BlobScheduleConfig
|
||||||
|
)
|
||||||
|
switch {
|
||||||
|
case cfg.IsPrague(london, time) && s.Prague != nil:
|
||||||
|
return s.Prague.Target
|
||||||
|
case cfg.IsCancun(london, time) && s.Cancun != nil:
|
||||||
|
return s.Cancun.Target
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
||||||
|
|
|
@ -21,36 +21,48 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCalcExcessBlobGas(t *testing.T) {
|
func TestCalcExcessBlobGas(t *testing.T) {
|
||||||
|
var (
|
||||||
|
config = params.MainnetChainConfig
|
||||||
|
targetBlobs = targetBlobsPerBlock(config, *config.CancunTime)
|
||||||
|
targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
|
||||||
|
)
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
excess uint64
|
excess uint64
|
||||||
blobs uint64
|
blobs int
|
||||||
want uint64
|
want uint64
|
||||||
}{
|
}{
|
||||||
// The excess blob gas should not increase from zero if the used blob
|
// The excess blob gas should not increase from zero if the used blob
|
||||||
// slots are below - or equal - to the target.
|
// slots are below - or equal - to the target.
|
||||||
{0, 0, 0},
|
{0, 0, 0},
|
||||||
{0, 1, 0},
|
{0, 1, 0},
|
||||||
{0, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, 0},
|
{0, targetBlobs, 0},
|
||||||
|
|
||||||
// If the target blob gas is exceeded, the excessBlobGas should increase
|
// If the target blob gas is exceeded, the excessBlobGas should increase
|
||||||
// by however much it was overshot
|
// by however much it was overshot
|
||||||
{0, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob},
|
{0, targetBlobs + 1, params.BlobTxBlobGasPerBlob},
|
||||||
{1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob + 1},
|
{1, targetBlobs + 1, params.BlobTxBlobGasPerBlob + 1},
|
||||||
{1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 2, 2*params.BlobTxBlobGasPerBlob + 1},
|
{1, targetBlobs + 2, 2*params.BlobTxBlobGasPerBlob + 1},
|
||||||
|
|
||||||
// The excess blob gas should decrease by however much the target was
|
// The excess blob gas should decrease by however much the target was
|
||||||
// under-shot, capped at zero.
|
// under-shot, capped at zero.
|
||||||
{params.BlobTxTargetBlobGasPerBlock, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, params.BlobTxTargetBlobGasPerBlock},
|
{targetBlobGas, targetBlobs, targetBlobGas},
|
||||||
{params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, params.BlobTxTargetBlobGasPerBlock - params.BlobTxBlobGasPerBlob},
|
{targetBlobGas, targetBlobs - 1, targetBlobGas - params.BlobTxBlobGasPerBlob},
|
||||||
{params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 2, params.BlobTxTargetBlobGasPerBlock - (2 * params.BlobTxBlobGasPerBlob)},
|
{targetBlobGas, targetBlobs - 2, targetBlobGas - (2 * params.BlobTxBlobGasPerBlob)},
|
||||||
{params.BlobTxBlobGasPerBlob - 1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, 0},
|
{params.BlobTxBlobGasPerBlob - 1, targetBlobs - 1, 0},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
result := CalcExcessBlobGas(tt.excess, tt.blobs*params.BlobTxBlobGasPerBlob)
|
blobGasUsed := uint64(tt.blobs) * params.BlobTxBlobGasPerBlob
|
||||||
|
parent := &types.Header{
|
||||||
|
Time: *config.CancunTime,
|
||||||
|
ExcessBlobGas: &tt.excess,
|
||||||
|
BlobGasUsed: &blobGasUsed,
|
||||||
|
}
|
||||||
|
result := CalcExcessBlobGas(config, parent)
|
||||||
if result != tt.want {
|
if result != tt.want {
|
||||||
t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want)
|
t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want)
|
||||||
}
|
}
|
||||||
|
@ -58,6 +70,8 @@ func TestCalcExcessBlobGas(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalcBlobFee(t *testing.T) {
|
func TestCalcBlobFee(t *testing.T) {
|
||||||
|
zero := uint64(0)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
excessBlobGas uint64
|
excessBlobGas uint64
|
||||||
blobfee int64
|
blobfee int64
|
||||||
|
@ -68,7 +82,9 @@ func TestCalcBlobFee(t *testing.T) {
|
||||||
{10 * 1024 * 1024, 23},
|
{10 * 1024 * 1024, 23},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
have := CalcBlobFee(tt.excessBlobGas)
|
config := ¶ms.ChainConfig{LondonBlock: big.NewInt(0), CancunTime: &zero, BlobScheduleConfig: params.DefaultBlobSchedule}
|
||||||
|
header := &types.Header{ExcessBlobGas: &tt.excessBlobGas}
|
||||||
|
have := CalcBlobFee(config, header)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2139,9 +2139,8 @@ func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (co
|
||||||
// processing of a block. These logs are later announced as deleted or reborn.
|
// 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 {
|
||||||
var blobGasPrice *big.Int
|
var blobGasPrice *big.Int
|
||||||
excessBlobGas := b.ExcessBlobGas()
|
if b.ExcessBlobGas() != nil {
|
||||||
if excessBlobGas != nil {
|
blobGasPrice = eip4844.CalcBlobFee(bc.chainConfig, b.Header())
|
||||||
blobGasPrice = eip4844.CalcBlobFee(*excessBlobGas)
|
|
||||||
}
|
}
|
||||||
receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64())
|
receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64())
|
||||||
if err := receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Time(), b.BaseFee(), blobGasPrice, b.Transactions()); err != nil {
|
if err := receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Time(), b.BaseFee(), blobGasPrice, b.Transactions()); err != nil {
|
||||||
|
|
|
@ -143,7 +143,9 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
|
||||||
// instruction will panic during execution if it attempts to access a block number outside
|
// instruction will panic during execution if it attempts to access a block number outside
|
||||||
// of the range created by GenerateChain.
|
// of the range created by GenerateChain.
|
||||||
func (b *BlockGen) AddTx(tx *types.Transaction) {
|
func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||||
b.addTx(nil, vm.Config{}, tx)
|
// Wrap the chain config in an empty BlockChain object to satisfy ChainContext.
|
||||||
|
bc := &BlockChain{chainConfig: b.cm.config}
|
||||||
|
b.addTx(bc, vm.Config{}, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTxWithChain adds a transaction to the generated block. If no coinbase has
|
// AddTxWithChain adds a transaction to the generated block. If no coinbase has
|
||||||
|
@ -445,7 +447,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
}
|
}
|
||||||
var blobGasPrice *big.Int
|
var blobGasPrice *big.Int
|
||||||
if block.ExcessBlobGas() != nil {
|
if block.ExcessBlobGas() != nil {
|
||||||
blobGasPrice = eip4844.CalcBlobFee(*block.ExcessBlobGas())
|
blobGasPrice = eip4844.CalcBlobFee(cm.config, block.Header())
|
||||||
}
|
}
|
||||||
if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil {
|
if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -548,7 +550,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
|
||||||
}
|
}
|
||||||
var blobGasPrice *big.Int
|
var blobGasPrice *big.Int
|
||||||
if block.ExcessBlobGas() != nil {
|
if block.ExcessBlobGas() != nil {
|
||||||
blobGasPrice = eip4844.CalcBlobFee(*block.ExcessBlobGas())
|
blobGasPrice = eip4844.CalcBlobFee(cm.config, block.Header())
|
||||||
}
|
}
|
||||||
if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil {
|
if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -598,15 +600,7 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cm.config.IsCancun(header.Number, header.Time) {
|
if cm.config.IsCancun(header.Number, header.Time) {
|
||||||
var (
|
excessBlobGas := eip4844.CalcExcessBlobGas(cm.config, parent.Header())
|
||||||
parentExcessBlobGas uint64
|
|
||||||
parentBlobGasUsed uint64
|
|
||||||
)
|
|
||||||
if parent.ExcessBlobGas() != nil {
|
|
||||||
parentExcessBlobGas = *parent.ExcessBlobGas()
|
|
||||||
parentBlobGasUsed = *parent.BlobGasUsed()
|
|
||||||
}
|
|
||||||
excessBlobGas := eip4844.CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed)
|
|
||||||
header.ExcessBlobGas = &excessBlobGas
|
header.ExcessBlobGas = &excessBlobGas
|
||||||
header.BlobGasUsed = new(uint64)
|
header.BlobGasUsed = new(uint64)
|
||||||
header.ParentBeaconRoot = new(common.Hash)
|
header.ParentBeaconRoot = new(common.Hash)
|
||||||
|
|
|
@ -42,7 +42,7 @@ func TestGeneratePOSChain(t *testing.T) {
|
||||||
aa = common.Address{0xaa}
|
aa = common.Address{0xaa}
|
||||||
bb = common.Address{0xbb}
|
bb = common.Address{0xbb}
|
||||||
funds = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether))
|
funds = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether))
|
||||||
config = *params.AllEthashProtocolChanges
|
config = *params.MergedTestChainConfig
|
||||||
gspec = &Genesis{
|
gspec = &Genesis{
|
||||||
Config: &config,
|
Config: &config,
|
||||||
Alloc: types.GenesisAlloc{
|
Alloc: types.GenesisAlloc{
|
||||||
|
@ -57,10 +57,6 @@ func TestGeneratePOSChain(t *testing.T) {
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
)
|
)
|
||||||
|
|
||||||
config.TerminalTotalDifficulty = common.Big0
|
|
||||||
config.ShanghaiTime = u64(0)
|
|
||||||
config.CancunTime = u64(0)
|
|
||||||
|
|
||||||
// init 0xaa with some storage elements
|
// init 0xaa with some storage elements
|
||||||
storage := make(map[common.Hash]common.Hash)
|
storage := make(map[common.Hash]common.Hash)
|
||||||
storage[common.Hash{0x00}] = common.Hash{0x00}
|
storage[common.Hash{0x00}] = common.Hash{0x00}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,6 +37,9 @@ type ChainContext interface {
|
||||||
|
|
||||||
// GetHeader returns the header corresponding to the hash/number argument pair.
|
// GetHeader returns the header corresponding to the hash/number argument pair.
|
||||||
GetHeader(common.Hash, uint64) *types.Header
|
GetHeader(common.Hash, uint64) *types.Header
|
||||||
|
|
||||||
|
// Config returns the chain's configuration.
|
||||||
|
Config() *params.ChainConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEVMBlockContext creates a new context for use in the EVM.
|
// NewEVMBlockContext creates a new context for use in the EVM.
|
||||||
|
@ -57,7 +61,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
|
||||||
baseFee = new(big.Int).Set(header.BaseFee)
|
baseFee = new(big.Int).Set(header.BaseFee)
|
||||||
}
|
}
|
||||||
if header.ExcessBlobGas != nil {
|
if header.ExcessBlobGas != nil {
|
||||||
blobBaseFee = eip4844.CalcBlobFee(*header.ExcessBlobGas)
|
blobBaseFee = eip4844.CalcBlobFee(chain.Config(), header)
|
||||||
}
|
}
|
||||||
if header.Difficulty.Sign() == 0 {
|
if header.Difficulty.Sign() == 0 {
|
||||||
random = &header.MixDigest
|
random = &header.MixDigest
|
||||||
|
|
|
@ -278,6 +278,11 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
||||||
EnableVerkleAtGenesis: true,
|
EnableVerkleAtGenesis: true,
|
||||||
Ethash: nil,
|
Ethash: nil,
|
||||||
Clique: nil,
|
Clique: nil,
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Cancun: params.DefaultCancunBlobConfig,
|
||||||
|
Prague: params.DefaultPragueBlobConfig,
|
||||||
|
Verkle: params.DefaultPragueBlobConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
genesis := &Genesis{
|
genesis := &Genesis{
|
||||||
|
|
|
@ -587,7 +587,7 @@ func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, time uint64,
|
||||||
// Compute effective blob gas price.
|
// Compute effective blob gas price.
|
||||||
var blobGasPrice *big.Int
|
var blobGasPrice *big.Int
|
||||||
if header != nil && header.ExcessBlobGas != nil {
|
if header != nil && header.ExcessBlobGas != nil {
|
||||||
blobGasPrice = eip4844.CalcBlobFee(*header.ExcessBlobGas)
|
blobGasPrice = eip4844.CalcBlobFee(config, header)
|
||||||
}
|
}
|
||||||
if err := receipts.DeriveFields(config, hash, number, time, baseFee, blobGasPrice, body.Transactions); err != nil {
|
if err := receipts.DeriveFields(config, hash, number, time, baseFee, blobGasPrice, 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)
|
||||||
|
|
|
@ -46,25 +46,7 @@ func u64(val uint64) *uint64 { return &val }
|
||||||
// contain invalid transactions
|
// contain invalid transactions
|
||||||
func TestStateProcessorErrors(t *testing.T) {
|
func TestStateProcessorErrors(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
config = ¶ms.ChainConfig{
|
config = params.MergedTestChainConfig
|
||||||
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),
|
|
||||||
ShanghaiTime: new(uint64),
|
|
||||||
CancunTime: new(uint64),
|
|
||||||
PragueTime: new(uint64),
|
|
||||||
}
|
|
||||||
signer = types.LatestSigner(config)
|
signer = types.LatestSigner(config)
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020")
|
key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020")
|
||||||
|
@ -425,12 +407,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
|
||||||
}
|
}
|
||||||
header.Root = common.BytesToHash(hasher.Sum(nil))
|
header.Root = common.BytesToHash(hasher.Sum(nil))
|
||||||
if config.IsCancun(header.Number, header.Time) {
|
if config.IsCancun(header.Number, header.Time) {
|
||||||
var pExcess, pUsed = uint64(0), uint64(0)
|
excess := eip4844.CalcExcessBlobGas(config, parent.Header())
|
||||||
if parent.ExcessBlobGas() != nil {
|
|
||||||
pExcess = *parent.ExcessBlobGas()
|
|
||||||
pUsed = *parent.BlobGasUsed()
|
|
||||||
}
|
|
||||||
excess := eip4844.CalcExcessBlobGas(pExcess, pUsed)
|
|
||||||
used := uint64(nBlobs * params.BlobTxBlobGasPerBlob)
|
used := uint64(nBlobs * params.BlobTxBlobGasPerBlob)
|
||||||
header.ExcessBlobGas = &excess
|
header.ExcessBlobGas = &excess
|
||||||
header.BlobGasUsed = &used
|
header.BlobGasUsed = &used
|
||||||
|
|
|
@ -51,11 +51,6 @@ const (
|
||||||
// transaction. There can be multiple of these embedded into a single tx.
|
// transaction. There can be multiple of these embedded into a single tx.
|
||||||
blobSize = params.BlobTxFieldElementsPerBlob * params.BlobTxBytesPerFieldElement
|
blobSize = params.BlobTxFieldElementsPerBlob * params.BlobTxBytesPerFieldElement
|
||||||
|
|
||||||
// maxBlobsPerTransaction is the maximum number of blobs a single transaction
|
|
||||||
// is allowed to contain. Whilst the spec states it's unlimited, the block
|
|
||||||
// data slots are protocol bound, which implicitly also limit this.
|
|
||||||
maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob
|
|
||||||
|
|
||||||
// txAvgSize is an approximate byte size of a transaction metadata to avoid
|
// txAvgSize is an approximate byte size of a transaction metadata to avoid
|
||||||
// tiny overflows causing all txs to move a shelf higher, wasting disk space.
|
// tiny overflows causing all txs to move a shelf higher, wasting disk space.
|
||||||
txAvgSize = 4 * 1024
|
txAvgSize = 4 * 1024
|
||||||
|
@ -223,6 +218,11 @@ func newBlobTxMeta(id uint64, size uint32, tx *types.Transaction) *blobTxMeta {
|
||||||
// very relaxed ones can be included even if the fees go up, when the closer
|
// very relaxed ones can be included even if the fees go up, when the closer
|
||||||
// ones could already be invalid.
|
// ones could already be invalid.
|
||||||
//
|
//
|
||||||
|
// - Because the maximum number of blobs allowed in a block can change per
|
||||||
|
// fork, the pool is designed to handle the maximum number of blobs allowed
|
||||||
|
// in the chain's latest defined fork -- even if it isn't active. This
|
||||||
|
// avoids needing to upgrade the database around the fork boundary.
|
||||||
|
//
|
||||||
// When the pool eventually reaches saturation, some old transactions - that may
|
// When the pool eventually reaches saturation, some old transactions - that may
|
||||||
// never execute - will need to be evicted in favor of newer ones. The eviction
|
// never execute - will need to be evicted in favor of newer ones. The eviction
|
||||||
// strategy is quite complex:
|
// strategy is quite complex:
|
||||||
|
@ -387,7 +387,8 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
|
||||||
fails = append(fails, id)
|
fails = append(fails, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, newSlotter(), index)
|
slotter := newSlotter(eip4844.LatestMaxBlobsPerBlock(p.chain.Config()))
|
||||||
|
store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, slotter, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -414,13 +415,13 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
|
||||||
blobfee = uint256.NewInt(params.BlobTxMinBlobGasprice)
|
blobfee = uint256.NewInt(params.BlobTxMinBlobGasprice)
|
||||||
)
|
)
|
||||||
if p.head.ExcessBlobGas != nil {
|
if p.head.ExcessBlobGas != nil {
|
||||||
blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*p.head.ExcessBlobGas))
|
blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(p.chain.Config(), p.head))
|
||||||
}
|
}
|
||||||
p.evict = newPriceHeap(basefee, blobfee, p.index)
|
p.evict = newPriceHeap(basefee, blobfee, p.index)
|
||||||
|
|
||||||
// Pool initialized, attach the blob limbo to it to track blobs included
|
// Pool initialized, attach the blob limbo to it to track blobs included
|
||||||
// recently but not yet finalized
|
// recently but not yet finalized
|
||||||
p.limbo, err = newLimbo(limbodir)
|
p.limbo, err = newLimbo(limbodir, eip4844.LatestMaxBlobsPerBlock(p.chain.Config()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.Close()
|
p.Close()
|
||||||
return err
|
return err
|
||||||
|
@ -834,7 +835,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
|
||||||
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
|
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
|
||||||
)
|
)
|
||||||
if newHead.ExcessBlobGas != nil {
|
if newHead.ExcessBlobGas != nil {
|
||||||
blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*newHead.ExcessBlobGas))
|
blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(p.chain.Config(), newHead))
|
||||||
}
|
}
|
||||||
p.evict.reinit(basefee, blobfee, false)
|
p.evict.reinit(basefee, blobfee, false)
|
||||||
|
|
||||||
|
@ -1598,7 +1599,8 @@ func (p *BlobPool) updateStorageMetrics() {
|
||||||
metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots))
|
metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots))
|
||||||
metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots))
|
metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots))
|
||||||
|
|
||||||
if shelf.SlotSize/blobSize > maxBlobsPerTransaction {
|
maxBlobs := eip4844.LatestMaxBlobsPerBlock(p.chain.Config())
|
||||||
|
if shelf.SlotSize/blobSize > uint32(maxBlobs) {
|
||||||
oversizedDataused += slotDataused
|
oversizedDataused += slotDataused
|
||||||
oversizedDatagaps += slotDatagaps
|
oversizedDatagaps += slotDatagaps
|
||||||
oversizedSlotused += shelf.FilledSlots
|
oversizedSlotused += shelf.FilledSlots
|
||||||
|
|
|
@ -51,8 +51,10 @@ var (
|
||||||
testBlobVHashes [][32]byte
|
testBlobVHashes [][32]byte
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const testMaxBlobsPerBlock = 6
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 24; i++ {
|
||||||
testBlob := &kzg4844.Blob{byte(i)}
|
testBlob := &kzg4844.Blob{byte(i)}
|
||||||
testBlobs = append(testBlobs, testBlob)
|
testBlobs = append(testBlobs, testBlob)
|
||||||
|
|
||||||
|
@ -121,7 +123,12 @@ func (bc *testBlockChain) CurrentBlock() *types.Header {
|
||||||
mid := new(big.Int).Add(lo, hi)
|
mid := new(big.Int).Add(lo, hi)
|
||||||
mid.Div(mid, big.NewInt(2))
|
mid.Div(mid, big.NewInt(2))
|
||||||
|
|
||||||
if eip4844.CalcBlobFee(mid.Uint64()).Cmp(bc.blobfee.ToBig()) > 0 {
|
tmp := mid.Uint64()
|
||||||
|
if eip4844.CalcBlobFee(bc.Config(), &types.Header{
|
||||||
|
Number: blockNumber,
|
||||||
|
Time: blockTime,
|
||||||
|
ExcessBlobGas: &tmp,
|
||||||
|
}).Cmp(bc.blobfee.ToBig()) > 0 {
|
||||||
hi = mid
|
hi = mid
|
||||||
} else {
|
} else {
|
||||||
lo = mid
|
lo = mid
|
||||||
|
@ -194,10 +201,43 @@ func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64,
|
||||||
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
|
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// makeMultiBlobTx is a utility method to construct a ramdom blob tx with
|
||||||
|
// certain number of blobs in its sidecar.
|
||||||
|
func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, key *ecdsa.PrivateKey) *types.Transaction {
|
||||||
|
var (
|
||||||
|
blobs []kzg4844.Blob
|
||||||
|
blobHashes []common.Hash
|
||||||
|
commitments []kzg4844.Commitment
|
||||||
|
proofs []kzg4844.Proof
|
||||||
|
)
|
||||||
|
for i := 0; i < blobCount; i++ {
|
||||||
|
blobs = append(blobs, *testBlobs[i])
|
||||||
|
commitments = append(commitments, testBlobCommits[i])
|
||||||
|
proofs = append(proofs, testBlobProofs[i])
|
||||||
|
blobHashes = append(blobHashes, testBlobVHashes[i])
|
||||||
|
}
|
||||||
|
blobtx := &types.BlobTx{
|
||||||
|
ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID),
|
||||||
|
Nonce: nonce,
|
||||||
|
GasTipCap: uint256.NewInt(gasTipCap),
|
||||||
|
GasFeeCap: uint256.NewInt(gasFeeCap),
|
||||||
|
Gas: 21000,
|
||||||
|
BlobFeeCap: uint256.NewInt(blobFeeCap),
|
||||||
|
BlobHashes: blobHashes,
|
||||||
|
Value: uint256.NewInt(100),
|
||||||
|
Sidecar: &types.BlobTxSidecar{
|
||||||
|
Blobs: blobs,
|
||||||
|
Commitments: commitments,
|
||||||
|
Proofs: proofs,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
|
||||||
|
}
|
||||||
|
|
||||||
// makeUnsignedTx is a utility method to construct a random blob transaction
|
// makeUnsignedTx is a utility method to construct a random blob transaction
|
||||||
// without signing it.
|
// without signing it.
|
||||||
func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx {
|
func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx {
|
||||||
return makeUnsignedTxWithTestBlob(nonce, gasTipCap, gasFeeCap, blobFeeCap, rand.Intn(len(testBlobs)))
|
return makeUnsignedTxWithTestBlob(nonce, gasTipCap, gasFeeCap, blobFeeCap, rnd.Intn(len(testBlobs)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeUnsignedTx is a utility method to construct a random blob transaction
|
// makeUnsignedTx is a utility method to construct a random blob transaction
|
||||||
|
@ -415,7 +455,7 @@ func TestOpenDrops(t *testing.T) {
|
||||||
defer os.RemoveAll(storage)
|
defer os.RemoveAll(storage)
|
||||||
|
|
||||||
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
||||||
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
|
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
|
||||||
|
|
||||||
// Insert a malformed transaction to verify that decoding errors (or format
|
// Insert a malformed transaction to verify that decoding errors (or format
|
||||||
// changes) are handled gracefully (case 1)
|
// changes) are handled gracefully (case 1)
|
||||||
|
@ -738,7 +778,7 @@ func TestOpenIndex(t *testing.T) {
|
||||||
defer os.RemoveAll(storage)
|
defer os.RemoveAll(storage)
|
||||||
|
|
||||||
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
||||||
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
|
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
|
||||||
|
|
||||||
// Insert a sequence of transactions with varying price points to check that
|
// Insert a sequence of transactions with varying price points to check that
|
||||||
// the cumulative minimum will be maintained.
|
// the cumulative minimum will be maintained.
|
||||||
|
@ -827,7 +867,7 @@ func TestOpenHeap(t *testing.T) {
|
||||||
defer os.RemoveAll(storage)
|
defer os.RemoveAll(storage)
|
||||||
|
|
||||||
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
||||||
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
|
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
|
||||||
|
|
||||||
// Insert a few transactions from a few accounts. To remove randomness from
|
// Insert a few transactions from a few accounts. To remove randomness from
|
||||||
// the heap initialization, use a deterministic account/tx/priority ordering.
|
// the heap initialization, use a deterministic account/tx/priority ordering.
|
||||||
|
@ -914,7 +954,7 @@ func TestOpenCap(t *testing.T) {
|
||||||
defer os.RemoveAll(storage)
|
defer os.RemoveAll(storage)
|
||||||
|
|
||||||
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
||||||
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
|
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
|
||||||
|
|
||||||
// Insert a few transactions from a few accounts
|
// Insert a few transactions from a few accounts
|
||||||
var (
|
var (
|
||||||
|
@ -992,6 +1032,108 @@ func TestOpenCap(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestChangingSlotterSize attempts to mimic a scenario where the max blob count
|
||||||
|
// of the pool is increased. This would happen during a client release where a
|
||||||
|
// new fork is added with a max blob count higher than the previous fork. We
|
||||||
|
// want to make sure transactions a persisted between those runs.
|
||||||
|
func TestChangingSlotterSize(t *testing.T) {
|
||||||
|
//log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
|
||||||
|
|
||||||
|
// Create a temporary folder for the persistent backend
|
||||||
|
storage, _ := os.MkdirTemp("", "blobpool-")
|
||||||
|
defer os.RemoveAll(storage)
|
||||||
|
|
||||||
|
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
||||||
|
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(6), nil)
|
||||||
|
|
||||||
|
// Create transactions from a few accounts.
|
||||||
|
var (
|
||||||
|
key1, _ = crypto.GenerateKey()
|
||||||
|
key2, _ = crypto.GenerateKey()
|
||||||
|
key3, _ = crypto.GenerateKey()
|
||||||
|
|
||||||
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
|
|
||||||
|
tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, key1)
|
||||||
|
tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, key2)
|
||||||
|
tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, key3)
|
||||||
|
|
||||||
|
blob1, _ = rlp.EncodeToBytes(tx1)
|
||||||
|
blob2, _ = rlp.EncodeToBytes(tx2)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Write the two safely sized txs to store. note: although the store is
|
||||||
|
// configured for a blob count of 6, it can also support around ~1mb of call
|
||||||
|
// data - all this to say that we aren't using the the absolute largest shelf
|
||||||
|
// available.
|
||||||
|
store.Put(blob1)
|
||||||
|
store.Put(blob2)
|
||||||
|
store.Close()
|
||||||
|
|
||||||
|
// Mimic a blobpool with max blob count of 6 upgrading to a max blob count of 24.
|
||||||
|
for _, maxBlobs := range []int{6, 24} {
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
|
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
|
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
|
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
|
||||||
|
statedb.Commit(0, true, false)
|
||||||
|
|
||||||
|
// Make custom chain config where the max blob count changes based on the loop variable.
|
||||||
|
cancunTime := uint64(0)
|
||||||
|
config := ¶ms.ChainConfig{
|
||||||
|
ChainID: big.NewInt(1),
|
||||||
|
LondonBlock: big.NewInt(0),
|
||||||
|
BerlinBlock: big.NewInt(0),
|
||||||
|
CancunTime: &cancunTime,
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Cancun: ¶ms.BlobConfig{
|
||||||
|
Target: maxBlobs / 2,
|
||||||
|
Max: maxBlobs,
|
||||||
|
UpdateFraction: params.DefaultCancunBlobConfig.UpdateFraction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
chain := &testBlockChain{
|
||||||
|
config: config,
|
||||||
|
basefee: uint256.NewInt(1050),
|
||||||
|
blobfee: uint256.NewInt(105),
|
||||||
|
statedb: statedb,
|
||||||
|
}
|
||||||
|
pool := New(Config{Datadir: storage}, chain)
|
||||||
|
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||||
|
t.Fatalf("failed to create blob pool: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to add the big blob tx. In the initial iteration it should overflow
|
||||||
|
// the pool. On the subsequent iteration it should be accepted.
|
||||||
|
errs := pool.Add([]*types.Transaction{tx3}, false, true)
|
||||||
|
if _, ok := pool.index[addr3]; ok && maxBlobs == 6 {
|
||||||
|
t.Errorf("expected insert of oversized blob tx to fail: blobs=24, maxBlobs=%d, err=%v", maxBlobs, errs[0])
|
||||||
|
} else if !ok && maxBlobs == 10 {
|
||||||
|
t.Errorf("expected insert of oversized blob tx to succeed: blobs=24, maxBlobs=%d, err=%v", maxBlobs, errs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the regular two txs are always available.
|
||||||
|
if got := pool.Get(tx1.Hash()); got == nil {
|
||||||
|
t.Errorf("expected tx %s from %s in pool", tx1.Hash(), addr1)
|
||||||
|
}
|
||||||
|
if got := pool.Get(tx2.Hash()); got == nil {
|
||||||
|
t.Errorf("expected tx %s from %s in pool", tx2.Hash(), addr2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all the calculated pool internals. Interestingly, this is **not**
|
||||||
|
// a duplication of the above checks, this actually validates the verifier
|
||||||
|
// using the above already hard coded checks.
|
||||||
|
//
|
||||||
|
// Do not remove this, nor alter the above to be generic.
|
||||||
|
verifyPoolInternals(t, pool)
|
||||||
|
|
||||||
|
pool.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that adding transaction will correctly store it in the persistent store
|
// Tests that adding transaction will correctly store it in the persistent store
|
||||||
// and update all the indices.
|
// and update all the indices.
|
||||||
//
|
//
|
||||||
|
@ -1369,7 +1511,7 @@ func TestAdd(t *testing.T) {
|
||||||
defer os.RemoveAll(storage) // late defer, still ok
|
defer os.RemoveAll(storage) // late defer, still ok
|
||||||
|
|
||||||
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
|
||||||
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
|
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)
|
||||||
|
|
||||||
// Insert the seed transactions for the pool startup
|
// Insert the seed transactions for the pool startup
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var rand = mrand.New(mrand.NewSource(1))
|
var rnd = mrand.New(mrand.NewSource(1))
|
||||||
|
|
||||||
// verifyHeapInternals verifies that all accounts present in the index are also
|
// verifyHeapInternals verifies that all accounts present in the index are also
|
||||||
// present in the heap and internals are consistent across various indices.
|
// present in the heap and internals are consistent across various indices.
|
||||||
|
@ -193,12 +193,12 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) {
|
||||||
index := make(map[common.Address][]*blobTxMeta)
|
index := make(map[common.Address][]*blobTxMeta)
|
||||||
for i := 0; i < int(blobs); i++ {
|
for i := 0; i < int(blobs); i++ {
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
rand.Read(addr[:])
|
rnd.Read(addr[:])
|
||||||
|
|
||||||
var (
|
var (
|
||||||
execTip = uint256.NewInt(rand.Uint64())
|
execTip = uint256.NewInt(rnd.Uint64())
|
||||||
execFee = uint256.NewInt(rand.Uint64())
|
execFee = uint256.NewInt(rnd.Uint64())
|
||||||
blobFee = uint256.NewInt(rand.Uint64())
|
blobFee = uint256.NewInt(rnd.Uint64())
|
||||||
|
|
||||||
basefeeJumps = dynamicFeeJumps(execFee)
|
basefeeJumps = dynamicFeeJumps(execFee)
|
||||||
blobfeeJumps = dynamicFeeJumps(blobFee)
|
blobfeeJumps = dynamicFeeJumps(blobFee)
|
||||||
|
@ -218,13 +218,13 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
// Create a price heap and reinit it over and over
|
// Create a price heap and reinit it over and over
|
||||||
heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index)
|
heap := newPriceHeap(uint256.NewInt(rnd.Uint64()), uint256.NewInt(rnd.Uint64()), index)
|
||||||
|
|
||||||
basefees := make([]*uint256.Int, b.N)
|
basefees := make([]*uint256.Int, b.N)
|
||||||
blobfees := make([]*uint256.Int, b.N)
|
blobfees := make([]*uint256.Int, b.N)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
basefees[i] = uint256.NewInt(rand.Uint64())
|
basefees[i] = uint256.NewInt(rnd.Uint64())
|
||||||
blobfees[i] = uint256.NewInt(rand.Uint64())
|
blobfees[i] = uint256.NewInt(rnd.Uint64())
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
@ -269,12 +269,12 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) {
|
||||||
index := make(map[common.Address][]*blobTxMeta)
|
index := make(map[common.Address][]*blobTxMeta)
|
||||||
for i := 0; i < int(blobs); i++ {
|
for i := 0; i < int(blobs); i++ {
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
rand.Read(addr[:])
|
rnd.Read(addr[:])
|
||||||
|
|
||||||
var (
|
var (
|
||||||
execTip = uint256.NewInt(rand.Uint64())
|
execTip = uint256.NewInt(rnd.Uint64())
|
||||||
execFee = uint256.NewInt(rand.Uint64())
|
execFee = uint256.NewInt(rnd.Uint64())
|
||||||
blobFee = uint256.NewInt(rand.Uint64())
|
blobFee = uint256.NewInt(rnd.Uint64())
|
||||||
|
|
||||||
basefeeJumps = dynamicFeeJumps(execFee)
|
basefeeJumps = dynamicFeeJumps(execFee)
|
||||||
blobfeeJumps = dynamicFeeJumps(blobFee)
|
blobfeeJumps = dynamicFeeJumps(blobFee)
|
||||||
|
@ -294,18 +294,18 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
// Create a price heap and overflow it over and over
|
// Create a price heap and overflow it over and over
|
||||||
evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index)
|
evict := newPriceHeap(uint256.NewInt(rnd.Uint64()), uint256.NewInt(rnd.Uint64()), index)
|
||||||
var (
|
var (
|
||||||
addrs = make([]common.Address, b.N)
|
addrs = make([]common.Address, b.N)
|
||||||
metas = make([]*blobTxMeta, b.N)
|
metas = make([]*blobTxMeta, b.N)
|
||||||
)
|
)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
rand.Read(addrs[i][:])
|
rnd.Read(addrs[i][:])
|
||||||
|
|
||||||
var (
|
var (
|
||||||
execTip = uint256.NewInt(rand.Uint64())
|
execTip = uint256.NewInt(rnd.Uint64())
|
||||||
execFee = uint256.NewInt(rand.Uint64())
|
execFee = uint256.NewInt(rnd.Uint64())
|
||||||
blobFee = uint256.NewInt(rand.Uint64())
|
blobFee = uint256.NewInt(rnd.Uint64())
|
||||||
|
|
||||||
basefeeJumps = dynamicFeeJumps(execFee)
|
basefeeJumps = dynamicFeeJumps(execFee)
|
||||||
blobfeeJumps = dynamicFeeJumps(blobFee)
|
blobfeeJumps = dynamicFeeJumps(blobFee)
|
||||||
|
|
|
@ -48,7 +48,7 @@ type limbo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// newLimbo opens and indexes a set of limboed blob transactions.
|
// newLimbo opens and indexes a set of limboed blob transactions.
|
||||||
func newLimbo(datadir string) (*limbo, error) {
|
func newLimbo(datadir string, maxBlobsPerTransaction int) (*limbo, error) {
|
||||||
l := &limbo{
|
l := &limbo{
|
||||||
index: make(map[common.Hash]uint64),
|
index: make(map[common.Hash]uint64),
|
||||||
groups: make(map[uint64]map[uint64]common.Hash),
|
groups: make(map[uint64]map[uint64]common.Hash),
|
||||||
|
@ -60,7 +60,7 @@ func newLimbo(datadir string) (*limbo, error) {
|
||||||
fails = append(fails, id)
|
fails = append(fails, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
store, err := billy.Open(billy.Options{Path: datadir, Repair: true}, newSlotter(), index)
|
store, err := billy.Open(billy.Options{Path: datadir, Repair: true}, newSlotter(maxBlobsPerTransaction), index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func TestPriorityCalculation(t *testing.T) {
|
||||||
func BenchmarkDynamicFeeJumpCalculation(b *testing.B) {
|
func BenchmarkDynamicFeeJumpCalculation(b *testing.B) {
|
||||||
fees := make([]*uint256.Int, b.N)
|
fees := make([]*uint256.Int, b.N)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
fees[i] = uint256.NewInt(rand.Uint64())
|
fees[i] = uint256.NewInt(rnd.Uint64())
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
@ -76,8 +76,8 @@ func BenchmarkPriorityCalculation(b *testing.B) {
|
||||||
txBasefeeJumps := make([]float64, b.N)
|
txBasefeeJumps := make([]float64, b.N)
|
||||||
txBlobfeeJumps := make([]float64, b.N)
|
txBlobfeeJumps := make([]float64, b.N)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
txBasefeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rand.Uint64()))
|
txBasefeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rnd.Uint64()))
|
||||||
txBlobfeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rand.Uint64()))
|
txBlobfeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rnd.Uint64()))
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
|
|
@ -25,13 +25,13 @@ package blobpool
|
||||||
// The slotter also creates a shelf for 0-blob transactions. Whilst those are not
|
// The slotter also creates a shelf for 0-blob transactions. Whilst those are not
|
||||||
// allowed in the current protocol, having an empty shelf is not a relevant use
|
// allowed in the current protocol, having an empty shelf is not a relevant use
|
||||||
// of resources, but it makes stress testing with junk transactions simpler.
|
// of resources, but it makes stress testing with junk transactions simpler.
|
||||||
func newSlotter() func() (uint32, bool) {
|
func newSlotter(maxBlobsPerTransaction int) func() (uint32, bool) {
|
||||||
slotsize := uint32(txAvgSize)
|
slotsize := uint32(txAvgSize)
|
||||||
slotsize -= uint32(blobSize) // underflows, it's ok, will overflow back in the first return
|
slotsize -= uint32(blobSize) // underflows, it's ok, will overflow back in the first return
|
||||||
|
|
||||||
return func() (size uint32, done bool) {
|
return func() (size uint32, done bool) {
|
||||||
slotsize += blobSize
|
slotsize += blobSize
|
||||||
finished := slotsize > maxBlobsPerTransaction*blobSize+txMaxSize
|
finished := slotsize > uint32(maxBlobsPerTransaction)*blobSize+txMaxSize
|
||||||
|
|
||||||
return slotsize, finished
|
return slotsize, finished
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import "testing"
|
||||||
// Tests that the slotter creates the expected database shelves.
|
// Tests that the slotter creates the expected database shelves.
|
||||||
func TestNewSlotter(t *testing.T) {
|
func TestNewSlotter(t *testing.T) {
|
||||||
// Generate the database shelve sizes
|
// Generate the database shelve sizes
|
||||||
slotter := newSlotter()
|
slotter := newSlotter(6)
|
||||||
|
|
||||||
var shelves []uint32
|
var shelves []uint32
|
||||||
for {
|
for {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
@ -144,8 +145,9 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
|
||||||
if len(hashes) == 0 {
|
if len(hashes) == 0 {
|
||||||
return errors.New("blobless blob transaction")
|
return errors.New("blobless blob transaction")
|
||||||
}
|
}
|
||||||
if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob {
|
maxBlobs := eip4844.MaxBlobsPerBlock(opts.Config, head.Time)
|
||||||
return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob)
|
if len(hashes) > maxBlobs {
|
||||||
|
return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), maxBlobs)
|
||||||
}
|
}
|
||||||
// Ensure commitments, proofs and hashes are valid
|
// Ensure commitments, proofs and hashes are valid
|
||||||
if err := validateBlobSidecar(hashes, sidecar); err != nil {
|
if err := validateBlobSidecar(hashes, sidecar); err != nil {
|
||||||
|
|
|
@ -58,6 +58,9 @@ var (
|
||||||
VerkleTime: u64(0),
|
VerkleTime: u64(0),
|
||||||
TerminalTotalDifficulty: common.Big0,
|
TerminalTotalDifficulty: common.Big0,
|
||||||
EnableVerkleAtGenesis: true,
|
EnableVerkleAtGenesis: true,
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Verkle: params.DefaultPragueBlobConfig,
|
||||||
|
},
|
||||||
// TODO uncomment when proof generation is merged
|
// TODO uncomment when proof generation is merged
|
||||||
// ProofInBlocks: true,
|
// ProofInBlocks: true,
|
||||||
}
|
}
|
||||||
|
@ -79,6 +82,9 @@ var (
|
||||||
VerkleTime: u64(0),
|
VerkleTime: u64(0),
|
||||||
TerminalTotalDifficulty: common.Big0,
|
TerminalTotalDifficulty: common.Big0,
|
||||||
EnableVerkleAtGenesis: true,
|
EnableVerkleAtGenesis: true,
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Verkle: params.DefaultPragueBlobConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -226,11 +232,11 @@ func TestProcessParentBlockHash(t *testing.T) {
|
||||||
var num = 2
|
var num = 2
|
||||||
for i := 1; i <= num; i++ {
|
for i := 1; i <= num; i++ {
|
||||||
header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)}
|
header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)}
|
||||||
vmContext := NewEVMBlockContext(header, nil, new(common.Address))
|
|
||||||
chainConfig := params.MergedTestChainConfig
|
chainConfig := params.MergedTestChainConfig
|
||||||
if isVerkle {
|
if isVerkle {
|
||||||
chainConfig = testVerkleChainConfig
|
chainConfig = testVerkleChainConfig
|
||||||
}
|
}
|
||||||
|
vmContext := NewEVMBlockContext(header, nil, new(common.Address))
|
||||||
evm := vm.NewEVM(vmContext, statedb, chainConfig, vm.Config{})
|
evm := vm.NewEVM(vmContext, statedb, chainConfig, vm.Config{})
|
||||||
ProcessParentBlockHash(header.ParentHash, evm)
|
ProcessParentBlockHash(header.ParentHash, evm)
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,6 +314,10 @@ func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header {
|
||||||
return fakeHeader(n, parentHash)
|
return fakeHeader(n, parentHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dummyChain) Config() *params.ChainConfig {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TestBlockhash tests the blockhash operation. It's a bit special, since it internally
|
// TestBlockhash tests the blockhash operation. It's a bit special, since it internally
|
||||||
// requires access to a chain reader.
|
// requires access to a chain reader.
|
||||||
func TestBlockhash(t *testing.T) {
|
func TestBlockhash(t *testing.T) {
|
||||||
|
|
|
@ -356,7 +356,7 @@ func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount uint64, lastB
|
||||||
|
|
||||||
func (b *EthAPIBackend) BlobBaseFee(ctx context.Context) *big.Int {
|
func (b *EthAPIBackend) BlobBaseFee(ctx context.Context) *big.Int {
|
||||||
if excess := b.CurrentHeader().ExcessBlobGas; excess != nil {
|
if excess := b.CurrentHeader().ExcessBlobGas; excess != nil {
|
||||||
return eip4844.CalcBlobFee(*excess)
|
return eip4844.CalcBlobFee(b.ChainConfig(), b.CurrentHeader())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1227,6 +1227,7 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
|
||||||
genesis.Config.ShanghaiTime = &time
|
genesis.Config.ShanghaiTime = &time
|
||||||
genesis.Config.CancunTime = &time
|
genesis.Config.CancunTime = &time
|
||||||
genesis.Config.PragueTime = &time
|
genesis.Config.PragueTime = &time
|
||||||
|
genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule
|
||||||
|
|
||||||
n, ethservice := startEthService(t, genesis, blocks)
|
n, ethservice := startEthService(t, genesis, blocks)
|
||||||
|
|
||||||
|
@ -1543,6 +1544,7 @@ func TestParentBeaconBlockRoot(t *testing.T) {
|
||||||
time := blocks[len(blocks)-1].Time() + 5
|
time := blocks[len(blocks)-1].Time() + 5
|
||||||
genesis.Config.ShanghaiTime = &time
|
genesis.Config.ShanghaiTime = &time
|
||||||
genesis.Config.CancunTime = &time
|
genesis.Config.CancunTime = &time
|
||||||
|
genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule
|
||||||
|
|
||||||
n, ethservice := startEthService(t, genesis, blocks)
|
n, ethservice := startEthService(t, genesis, blocks)
|
||||||
defer n.Close()
|
defer n.Close()
|
||||||
|
@ -1625,6 +1627,7 @@ func TestWitnessCreationAndConsumption(t *testing.T) {
|
||||||
timestamp := blocks[len(blocks)-2].Time() + 5
|
timestamp := blocks[len(blocks)-2].Time() + 5
|
||||||
genesis.Config.ShanghaiTime = ×tamp
|
genesis.Config.ShanghaiTime = ×tamp
|
||||||
genesis.Config.CancunTime = ×tamp
|
genesis.Config.CancunTime = ×tamp
|
||||||
|
genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule
|
||||||
|
|
||||||
n, ethservice := startEthService(t, genesis, blocks[:9])
|
n, ethservice := startEthService(t, genesis, blocks[:9])
|
||||||
defer n.Close()
|
defer n.Close()
|
||||||
|
|
|
@ -1108,7 +1108,7 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) {
|
||||||
doTxNotify{peer: "C",
|
doTxNotify{peer: "C",
|
||||||
hashes: []common.Hash{{0x07}, {0x08}},
|
hashes: []common.Hash{{0x07}, {0x08}},
|
||||||
types: []byte{types.BlobTxType, types.BlobTxType},
|
types: []byte{types.BlobTxType, types.BlobTxType},
|
||||||
sizes: []uint32{params.MaxBlobGasPerBlock, params.MaxBlobGasPerBlock},
|
sizes: []uint32{params.BlobTxBlobGasPerBlob * 10, params.BlobTxBlobGasPerBlob * 10},
|
||||||
},
|
},
|
||||||
doWait{time: txArriveTimeout, step: true},
|
doWait{time: txArriveTimeout, step: true},
|
||||||
isWaiting(nil),
|
isWaiting(nil),
|
||||||
|
@ -1125,8 +1125,8 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) {
|
||||||
{common.Hash{0x06}, types.LegacyTxType, maxTxRetrievalSize},
|
{common.Hash{0x06}, types.LegacyTxType, maxTxRetrievalSize},
|
||||||
},
|
},
|
||||||
"C": {
|
"C": {
|
||||||
{common.Hash{0x07}, types.BlobTxType, params.MaxBlobGasPerBlock},
|
{common.Hash{0x07}, types.BlobTxType, params.BlobTxBlobGasPerBlob * 10},
|
||||||
{common.Hash{0x08}, types.BlobTxType, params.MaxBlobGasPerBlock},
|
{common.Hash{0x08}, types.BlobTxType, params.BlobTxBlobGasPerBlob * 10},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fetching: map[string][]common.Hash{
|
fetching: map[string][]common.Hash{
|
||||||
|
|
|
@ -31,7 +31,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"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/params"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -97,8 +96,10 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
|
||||||
}
|
}
|
||||||
// Fill in blob base fee and next blob base fee.
|
// Fill in blob base fee and next blob base fee.
|
||||||
if excessBlobGas := bf.header.ExcessBlobGas; excessBlobGas != nil {
|
if excessBlobGas := bf.header.ExcessBlobGas; excessBlobGas != nil {
|
||||||
bf.results.blobBaseFee = eip4844.CalcBlobFee(*excessBlobGas)
|
bf.results.blobBaseFee = eip4844.CalcBlobFee(config, bf.header)
|
||||||
bf.results.nextBlobBaseFee = eip4844.CalcBlobFee(eip4844.CalcExcessBlobGas(*excessBlobGas, *bf.header.BlobGasUsed))
|
excess := eip4844.CalcExcessBlobGas(config, bf.header)
|
||||||
|
next := &types.Header{Number: bf.header.Number, Time: bf.header.Time, ExcessBlobGas: &excess}
|
||||||
|
bf.results.nextBlobBaseFee = eip4844.CalcBlobFee(config, next)
|
||||||
} else {
|
} else {
|
||||||
bf.results.blobBaseFee = new(big.Int)
|
bf.results.blobBaseFee = new(big.Int)
|
||||||
bf.results.nextBlobBaseFee = new(big.Int)
|
bf.results.nextBlobBaseFee = new(big.Int)
|
||||||
|
@ -106,7 +107,8 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
|
||||||
// Compute gas used ratio for normal and blob gas.
|
// Compute gas used ratio for normal and blob gas.
|
||||||
bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit)
|
bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit)
|
||||||
if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil {
|
if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil {
|
||||||
bf.results.blobGasUsedRatio = float64(*blobGasUsed) / params.MaxBlobGasPerBlock
|
maxBlobs := eip4844.MaxBlobsPerBlock(config, bf.header.Time)
|
||||||
|
bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(maxBlobs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(percentiles) == 0 {
|
if len(percentiles) == 0 {
|
||||||
|
|
|
@ -157,6 +157,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe
|
||||||
ts := gspec.Timestamp + cancunBlock.Uint64()*10 // fixed 10 sec block time in blockgen
|
ts := gspec.Timestamp + cancunBlock.Uint64()*10 // fixed 10 sec block time in blockgen
|
||||||
config.ShanghaiTime = &ts
|
config.ShanghaiTime = &ts
|
||||||
config.CancunTime = &ts
|
config.CancunTime = &ts
|
||||||
|
config.BlobScheduleConfig = params.DefaultBlobSchedule
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -360,6 +360,7 @@ func TestSupplySelfdestruct(t *testing.T) {
|
||||||
cancunTime := uint64(0)
|
cancunTime := uint64(0)
|
||||||
gspec.Config.ShanghaiTime = &cancunTime
|
gspec.Config.ShanghaiTime = &cancunTime
|
||||||
gspec.Config.CancunTime = &cancunTime
|
gspec.Config.CancunTime = &cancunTime
|
||||||
|
gspec.Config.BlobScheduleConfig = params.DefaultBlobSchedule
|
||||||
|
|
||||||
postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc)
|
postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -41,7 +41,14 @@
|
||||||
"grayGlacierBlock": 0,
|
"grayGlacierBlock": 0,
|
||||||
"shanghaiTime": 0,
|
"shanghaiTime": 0,
|
||||||
"cancunTime": 0,
|
"cancunTime": 0,
|
||||||
"terminalTotalDifficulty": 0
|
"terminalTotalDifficulty": 0,
|
||||||
|
"blobSchedule": {
|
||||||
|
"cancun": {
|
||||||
|
"target": 3,
|
||||||
|
"max": 6,
|
||||||
|
"baseFeeUpdateFraction": 3338477
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"context": {
|
"context": {
|
||||||
|
|
|
@ -41,7 +41,14 @@
|
||||||
"grayGlacierBlock": 0,
|
"grayGlacierBlock": 0,
|
||||||
"shanghaiTime": 0,
|
"shanghaiTime": 0,
|
||||||
"cancunTime": 0,
|
"cancunTime": 0,
|
||||||
"terminalTotalDifficulty": 0
|
"terminalTotalDifficulty": 0,
|
||||||
|
"blobSchedule": {
|
||||||
|
"cancun": {
|
||||||
|
"target": 3,
|
||||||
|
"max": 6,
|
||||||
|
"baseFeeUpdateFraction": 3338477
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"context": {
|
"context": {
|
||||||
|
@ -54,7 +61,9 @@
|
||||||
},
|
},
|
||||||
"input": "0x03f8b1820539806485174876e800825208940c2c51a0990aee1d73c1228de1586883415575088080c083020000f842a00100c9fbdf97f747e85847b4f3fff408f89c26842f77c882858bf2c89923849aa00138e3896f3c27f2389147507f8bcec52028b0efca6ee842ed83c9158873943880a0dbac3f97a532c9b00e6239b29036245a5bfbb96940b9d848634661abee98b945a03eec8525f261c2e79798f7b45a5d6ccaefa24576d53ba5023e919b86841c0675",
|
"input": "0x03f8b1820539806485174876e800825208940c2c51a0990aee1d73c1228de1586883415575088080c083020000f842a00100c9fbdf97f747e85847b4f3fff408f89c26842f77c882858bf2c89923849aa00138e3896f3c27f2389147507f8bcec52028b0efca6ee842ed83c9158873943880a0dbac3f97a532c9b00e6239b29036245a5bfbb96940b9d848634661abee98b945a03eec8525f261c2e79798f7b45a5d6ccaefa24576d53ba5023e919b86841c0675",
|
||||||
"result": {
|
"result": {
|
||||||
"0x0000000000000000000000000000000000000000": { "balance": "0x272e0528" },
|
"0x0000000000000000000000000000000000000000": {
|
||||||
|
"balance": "0x272e0528"
|
||||||
|
},
|
||||||
"0x0c2c51a0990aee1d73c1228de158688341557508": {
|
"0x0c2c51a0990aee1d73c1228de158688341557508": {
|
||||||
"balance": "0xde0b6b3a7640000"
|
"balance": "0xde0b6b3a7640000"
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,19 @@
|
||||||
"shanghaiTime": 0,
|
"shanghaiTime": 0,
|
||||||
"cancunTime": 0,
|
"cancunTime": 0,
|
||||||
"pragueTime": 0,
|
"pragueTime": 0,
|
||||||
"terminalTotalDifficulty": 0
|
"terminalTotalDifficulty": 0,
|
||||||
|
"blobSchedule": {
|
||||||
|
"cancun": {
|
||||||
|
"target": 3,
|
||||||
|
"max": 6,
|
||||||
|
"baseFeeUpdateFraction": 3338477
|
||||||
|
},
|
||||||
|
"prague": {
|
||||||
|
"target": 3,
|
||||||
|
"max": 6,
|
||||||
|
"baseFeeUpdateFraction": 5007716
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"context": {
|
"context": {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
||||||
// Force-load native and js packages, to trigger registration
|
// Force-load native and js packages, to trigger registration
|
||||||
|
@ -53,8 +54,9 @@ func (c *callContext) toBlockContext(genesis *core.Genesis) vm.BlockContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
if genesis.ExcessBlobGas != nil && genesis.BlobGasUsed != nil {
|
if genesis.ExcessBlobGas != nil && genesis.BlobGasUsed != nil {
|
||||||
excessBlobGas := eip4844.CalcExcessBlobGas(*genesis.ExcessBlobGas, *genesis.BlobGasUsed)
|
excess := eip4844.CalcExcessBlobGas(genesis.Config, genesis.ToBlock().Header())
|
||||||
context.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas)
|
header := &types.Header{ExcessBlobGas: &excess, Number: genesis.Config.LondonBlock, Time: *genesis.Config.CancunTime}
|
||||||
|
context.BlobBaseFee = eip4844.CalcBlobFee(genesis.Config, header)
|
||||||
}
|
}
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"gopkg.in/natefinch/lumberjack.v2"
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -83,6 +84,7 @@ type supplyTracer struct {
|
||||||
delta supplyInfo
|
delta supplyInfo
|
||||||
txCallstack []supplyTxCallstack // Callstack for current transaction
|
txCallstack []supplyTxCallstack // Callstack for current transaction
|
||||||
logger *lumberjack.Logger
|
logger *lumberjack.Logger
|
||||||
|
chainConfig *params.ChainConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type supplyTracerConfig struct {
|
type supplyTracerConfig struct {
|
||||||
|
@ -112,14 +114,15 @@ func newSupplyTracer(cfg json.RawMessage) (*tracing.Hooks, error) {
|
||||||
logger: logger,
|
logger: logger,
|
||||||
}
|
}
|
||||||
return &tracing.Hooks{
|
return &tracing.Hooks{
|
||||||
OnBlockStart: t.onBlockStart,
|
OnBlockchainInit: t.onBlockchainInit,
|
||||||
OnBlockEnd: t.onBlockEnd,
|
OnBlockStart: t.onBlockStart,
|
||||||
OnGenesisBlock: t.onGenesisBlock,
|
OnBlockEnd: t.onBlockEnd,
|
||||||
OnTxStart: t.onTxStart,
|
OnGenesisBlock: t.onGenesisBlock,
|
||||||
OnBalanceChange: t.onBalanceChange,
|
OnTxStart: t.onTxStart,
|
||||||
OnEnter: t.onEnter,
|
OnBalanceChange: t.onBalanceChange,
|
||||||
OnExit: t.onExit,
|
OnEnter: t.onEnter,
|
||||||
OnClose: t.onClose,
|
OnExit: t.onExit,
|
||||||
|
OnClose: t.onClose,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +149,10 @@ func (s *supplyTracer) resetDelta() {
|
||||||
s.delta = newSupplyInfo()
|
s.delta = newSupplyInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *supplyTracer) onBlockchainInit(chainConfig *params.ChainConfig) {
|
||||||
|
s.chainConfig = chainConfig
|
||||||
|
}
|
||||||
|
|
||||||
func (s *supplyTracer) onBlockStart(ev tracing.BlockEvent) {
|
func (s *supplyTracer) onBlockStart(ev tracing.BlockEvent) {
|
||||||
s.resetDelta()
|
s.resetDelta()
|
||||||
|
|
||||||
|
@ -161,8 +168,7 @@ func (s *supplyTracer) onBlockStart(ev tracing.BlockEvent) {
|
||||||
// Blob burnt gas
|
// Blob burnt gas
|
||||||
if blobGas := ev.Block.BlobGasUsed(); blobGas != nil && *blobGas > 0 && ev.Block.ExcessBlobGas() != nil {
|
if blobGas := ev.Block.BlobGasUsed(); blobGas != nil && *blobGas > 0 && ev.Block.ExcessBlobGas() != nil {
|
||||||
var (
|
var (
|
||||||
excess = *ev.Block.ExcessBlobGas()
|
baseFee = eip4844.CalcBlobFee(s.chainConfig, ev.Block.Header())
|
||||||
baseFee = eip4844.CalcBlobFee(excess)
|
|
||||||
burn = new(big.Int).Mul(new(big.Int).SetUint64(*blobGas), baseFee)
|
burn = new(big.Int).Mul(new(big.Int).SetUint64(*blobGas), baseFee)
|
||||||
)
|
)
|
||||||
s.delta.Burn.Blob = burn
|
s.delta.Burn.Blob = burn
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
@ -65,7 +66,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var genesis = &core.Genesis{
|
var genesis = &core.Genesis{
|
||||||
Config: params.AllEthashProtocolChanges,
|
Config: params.AllDevChainProtocolChanges,
|
||||||
Alloc: types.GenesisAlloc{
|
Alloc: types.GenesisAlloc{
|
||||||
testAddr: {Balance: testBalance},
|
testAddr: {Balance: testBalance},
|
||||||
revertContractAddr: {Code: revertCode},
|
revertContractAddr: {Code: revertCode},
|
||||||
|
@ -136,7 +137,7 @@ func generateTestChain() []*types.Block {
|
||||||
g.AddTx(testTx2)
|
g.AddTx(testTx2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 2, generate)
|
_, blocks, _ := core.GenerateChainWithGenesis(genesis, beacon.New(ethash.NewFaker()), 2, generate)
|
||||||
return append([]*types.Block{genesis.ToBlock()}, blocks...)
|
return append([]*types.Block{genesis.ToBlock()}, blocks...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +224,7 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) {
|
||||||
if got != nil && got.Number != nil && got.Number.Sign() == 0 {
|
if got != nil && got.Number != nil && got.Number.Sign() == 0 {
|
||||||
got.Number = big.NewInt(0) // hack to make DeepEqual work
|
got.Number = big.NewInt(0) // hack to make DeepEqual work
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if got.Hash() != tt.want.Hash() {
|
||||||
t.Fatalf("HeaderByNumber(%v) got = %v, want %v", tt.block, got, tt.want)
|
t.Fatalf("HeaderByNumber(%v) got = %v, want %v", tt.block, got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -314,7 +315,7 @@ func testChainID(t *testing.T, client *rpc.Client) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 {
|
if id == nil || id.Cmp(params.AllDevChainProtocolChanges.ChainID) != 0 {
|
||||||
t.Fatalf("ChainID returned wrong number: %+v", id)
|
t.Fatalf("ChainID returned wrong number: %+v", id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -624,6 +624,7 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp
|
||||||
type ChainContextBackend interface {
|
type ChainContextBackend interface {
|
||||||
Engine() consensus.Engine
|
Engine() consensus.Engine
|
||||||
HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error)
|
HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error)
|
||||||
|
ChainConfig() *params.ChainConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainContext is an implementation of core.ChainContext. It's main use-case
|
// ChainContext is an implementation of core.ChainContext. It's main use-case
|
||||||
|
@ -652,6 +653,10 @@ func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.H
|
||||||
return header
|
return header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (context *ChainContext) Config() *params.ChainConfig {
|
||||||
|
return context.b.ChainConfig()
|
||||||
|
}
|
||||||
|
|
||||||
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
||||||
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
|
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
|
||||||
if blockOverrides != nil {
|
if blockOverrides != nil {
|
||||||
|
|
|
@ -159,9 +159,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
if sim.chainConfig.IsCancun(header.Number, header.Time) {
|
if sim.chainConfig.IsCancun(header.Number, header.Time) {
|
||||||
var excess uint64
|
var excess uint64
|
||||||
if sim.chainConfig.IsCancun(parent.Number, parent.Time) {
|
if sim.chainConfig.IsCancun(parent.Number, parent.Time) {
|
||||||
excess = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed)
|
excess = eip4844.CalcExcessBlobGas(sim.chainConfig, parent)
|
||||||
} else {
|
|
||||||
excess = eip4844.CalcExcessBlobGas(0, 0)
|
|
||||||
}
|
}
|
||||||
header.ExcessBlobGas = &excess
|
header.ExcessBlobGas = &excess
|
||||||
}
|
}
|
||||||
|
@ -415,3 +413,7 @@ func (b *simBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber)
|
||||||
}
|
}
|
||||||
return nil, errors.New("header not found")
|
return nil, errors.New("header not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *simBackend) ChainConfig() *params.ChainConfig {
|
||||||
|
return b.b.ChainConfig()
|
||||||
|
}
|
||||||
|
|
|
@ -37,10 +37,6 @@ import (
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob
|
|
||||||
)
|
|
||||||
|
|
||||||
// TransactionArgs represents the arguments to construct a new transaction
|
// TransactionArgs represents the arguments to construct a new transaction
|
||||||
// or a message call.
|
// or a message call.
|
||||||
type TransactionArgs struct {
|
type TransactionArgs struct {
|
||||||
|
@ -125,8 +121,9 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas
|
||||||
if args.BlobHashes != nil && len(args.BlobHashes) == 0 {
|
if args.BlobHashes != nil && len(args.BlobHashes) == 0 {
|
||||||
return errors.New(`need at least 1 blob for a blob transaction`)
|
return errors.New(`need at least 1 blob for a blob transaction`)
|
||||||
}
|
}
|
||||||
if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobsPerTransaction {
|
maxBlobs := eip4844.MaxBlobsPerBlock(b.ChainConfig(), b.CurrentHeader().Time)
|
||||||
return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobsPerTransaction)
|
if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobs {
|
||||||
|
return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create check
|
// create check
|
||||||
|
@ -191,7 +188,9 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend, head
|
||||||
if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 {
|
if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 {
|
||||||
return errors.New("maxFeePerBlobGas, if specified, must be non-zero")
|
return errors.New("maxFeePerBlobGas, if specified, must be non-zero")
|
||||||
}
|
}
|
||||||
args.setCancunFeeDefaults(head)
|
if b.ChainConfig().IsCancun(head.Number, head.Time) {
|
||||||
|
args.setCancunFeeDefaults(b.ChainConfig(), head)
|
||||||
|
}
|
||||||
// If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error.
|
// If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error.
|
||||||
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
||||||
return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
||||||
|
@ -243,15 +242,10 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend, head
|
||||||
}
|
}
|
||||||
|
|
||||||
// setCancunFeeDefaults fills in reasonable default fee values for unspecified fields.
|
// setCancunFeeDefaults fills in reasonable default fee values for unspecified fields.
|
||||||
func (args *TransactionArgs) setCancunFeeDefaults(head *types.Header) {
|
func (args *TransactionArgs) setCancunFeeDefaults(config *params.ChainConfig, head *types.Header) {
|
||||||
// Set maxFeePerBlobGas if it is missing.
|
// Set maxFeePerBlobGas if it is missing.
|
||||||
if args.BlobHashes != nil && args.BlobFeeCap == nil {
|
if args.BlobHashes != nil && args.BlobFeeCap == nil {
|
||||||
var excessBlobGas uint64
|
blobBaseFee := eip4844.CalcBlobFee(config, head)
|
||||||
if head.ExcessBlobGas != nil {
|
|
||||||
excessBlobGas = *head.ExcessBlobGas
|
|
||||||
}
|
|
||||||
// ExcessBlobGas must be set for a Cancun block.
|
|
||||||
blobBaseFee := eip4844.CalcBlobFee(excessBlobGas)
|
|
||||||
// Set the max fee to be 2 times larger than the previous block's blob base fee.
|
// Set the max fee to be 2 times larger than the previous block's blob base fee.
|
||||||
// The additional slack allows the tx to not become invalidated if the base
|
// The additional slack allows the tx to not become invalidated if the base
|
||||||
// fee is rising.
|
// fee is rising.
|
||||||
|
|
|
@ -279,6 +279,7 @@ func newBackendMock() *backendMock {
|
||||||
BerlinBlock: big.NewInt(0),
|
BerlinBlock: big.NewInt(0),
|
||||||
LondonBlock: big.NewInt(1000),
|
LondonBlock: big.NewInt(1000),
|
||||||
CancunTime: &cancunTime,
|
CancunTime: &cancunTime,
|
||||||
|
BlobScheduleConfig: params.DefaultBlobSchedule,
|
||||||
}
|
}
|
||||||
return &backendMock{
|
return &backendMock{
|
||||||
current: &types.Header{
|
current: &types.Header{
|
||||||
|
|
|
@ -210,10 +210,7 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir
|
||||||
if miner.chainConfig.IsCancun(header.Number, header.Time) {
|
if miner.chainConfig.IsCancun(header.Number, header.Time) {
|
||||||
var excessBlobGas uint64
|
var excessBlobGas uint64
|
||||||
if miner.chainConfig.IsCancun(parent.Number, parent.Time) {
|
if miner.chainConfig.IsCancun(parent.Number, parent.Time) {
|
||||||
excessBlobGas = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed)
|
excessBlobGas = eip4844.CalcExcessBlobGas(miner.chainConfig, parent)
|
||||||
} else {
|
|
||||||
// For the first post-fork block, both parent.data_gas_used and parent.excess_data_gas are evaluated as 0
|
|
||||||
excessBlobGas = eip4844.CalcExcessBlobGas(0, 0)
|
|
||||||
}
|
}
|
||||||
header.BlobGasUsed = new(uint64)
|
header.BlobGasUsed = new(uint64)
|
||||||
header.ExcessBlobGas = &excessBlobGas
|
header.ExcessBlobGas = &excessBlobGas
|
||||||
|
@ -284,7 +281,8 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
|
||||||
// isn't really a better place right now. The blob gas limit is checked at block validation time
|
// isn't really a better place right now. The blob gas limit is checked at block validation time
|
||||||
// and not during execution. This means core.ApplyTransaction will not return an error if the
|
// and not during execution. This means core.ApplyTransaction will not return an error if the
|
||||||
// tx has too many blobs. So we have to explicitly check it here.
|
// tx has too many blobs. So we have to explicitly check it here.
|
||||||
if (env.blobs+len(sc.Blobs))*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock {
|
maxBlobs := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time)
|
||||||
|
if env.blobs+len(sc.Blobs) > maxBlobs {
|
||||||
return errors.New("max data blobs reached")
|
return errors.New("max data blobs reached")
|
||||||
}
|
}
|
||||||
receipt, err := miner.applyTransaction(env, tx)
|
receipt, err := miner.applyTransaction(env, tx)
|
||||||
|
@ -333,7 +331,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
||||||
}
|
}
|
||||||
// If we don't have enough blob space for any further blob transactions,
|
// If we don't have enough blob space for any further blob transactions,
|
||||||
// skip that list altogether
|
// skip that list altogether
|
||||||
if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= params.MaxBlobGasPerBlock {
|
if !blobTxs.Empty() && env.blobs >= eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) {
|
||||||
log.Trace("Not enough blob space for further blob transactions")
|
log.Trace("Not enough blob space for further blob transactions")
|
||||||
blobTxs.Clear()
|
blobTxs.Clear()
|
||||||
// Fall though to pick up any plain txs
|
// Fall though to pick up any plain txs
|
||||||
|
@ -367,11 +365,19 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
||||||
txs.Pop()
|
txs.Pop()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if left := uint64(params.MaxBlobGasPerBlock - env.blobs*params.BlobTxBlobGasPerBlob); left < ltx.BlobGas {
|
|
||||||
log.Trace("Not enough blob gas left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas)
|
// Most of the blob gas logic here is agnostic as to if the chain supports
|
||||||
txs.Pop()
|
// blobs or not, however the max check panics when called on a chain without
|
||||||
continue
|
// a defined schedule, so we need to verify it's safe to call.
|
||||||
|
if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) {
|
||||||
|
left := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) - env.blobs
|
||||||
|
if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) {
|
||||||
|
log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob)
|
||||||
|
txs.Pop()
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transaction seems to fit, pull it up from the pool
|
// Transaction seems to fit, pull it up from the pool
|
||||||
tx := ltx.Resolve()
|
tx := ltx.Resolve()
|
||||||
if tx == nil {
|
if tx == nil {
|
||||||
|
@ -379,6 +385,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
||||||
txs.Pop()
|
txs.Pop()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error may be ignored here. The error has already been checked
|
// Error may be ignored here. The error has already been checked
|
||||||
// during transaction acceptance in the transaction pool.
|
// during transaction acceptance in the transaction pool.
|
||||||
from, _ := types.Sender(env.signer, tx)
|
from, _ := types.Sender(env.signer, tx)
|
||||||
|
@ -430,7 +437,7 @@ func (miner *Miner) fillTransactions(interrupt *atomic.Int32, env *environment)
|
||||||
filter.BaseFee = uint256.MustFromBig(env.header.BaseFee)
|
filter.BaseFee = uint256.MustFromBig(env.header.BaseFee)
|
||||||
}
|
}
|
||||||
if env.header.ExcessBlobGas != nil {
|
if env.header.ExcessBlobGas != nil {
|
||||||
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas))
|
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(miner.chainConfig, env.header))
|
||||||
}
|
}
|
||||||
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
|
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
|
||||||
pendingPlainTxs := miner.txpool.Pending(filter)
|
pendingPlainTxs := miner.txpool.Pending(filter)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package params
|
package params
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -60,6 +61,9 @@ var (
|
||||||
CancunTime: newUint64(1710338135),
|
CancunTime: newUint64(1710338135),
|
||||||
DepositContractAddress: common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa"),
|
DepositContractAddress: common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa"),
|
||||||
Ethash: new(EthashConfig),
|
Ethash: new(EthashConfig),
|
||||||
|
BlobScheduleConfig: &BlobScheduleConfig{
|
||||||
|
Cancun: DefaultCancunBlobConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
// HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network.
|
// HoleskyChainConfig contains the chain parameters to run a node on the Holesky test network.
|
||||||
HoleskyChainConfig = &ChainConfig{
|
HoleskyChainConfig = &ChainConfig{
|
||||||
|
@ -84,6 +88,9 @@ var (
|
||||||
ShanghaiTime: newUint64(1696000704),
|
ShanghaiTime: newUint64(1696000704),
|
||||||
CancunTime: newUint64(1707305664),
|
CancunTime: newUint64(1707305664),
|
||||||
Ethash: new(EthashConfig),
|
Ethash: new(EthashConfig),
|
||||||
|
BlobScheduleConfig: &BlobScheduleConfig{
|
||||||
|
Cancun: DefaultCancunBlobConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
// SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network.
|
// SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network.
|
||||||
SepoliaChainConfig = &ChainConfig{
|
SepoliaChainConfig = &ChainConfig{
|
||||||
|
@ -108,6 +115,9 @@ var (
|
||||||
ShanghaiTime: newUint64(1677557088),
|
ShanghaiTime: newUint64(1677557088),
|
||||||
CancunTime: newUint64(1706655072),
|
CancunTime: newUint64(1706655072),
|
||||||
Ethash: new(EthashConfig),
|
Ethash: new(EthashConfig),
|
||||||
|
BlobScheduleConfig: &BlobScheduleConfig{
|
||||||
|
Cancun: DefaultCancunBlobConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
|
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
|
||||||
// and accepted by the Ethereum core developers into the Ethash consensus.
|
// and accepted by the Ethereum core developers into the Ethash consensus.
|
||||||
|
@ -158,6 +168,10 @@ var (
|
||||||
CancunTime: newUint64(0),
|
CancunTime: newUint64(0),
|
||||||
TerminalTotalDifficulty: big.NewInt(0),
|
TerminalTotalDifficulty: big.NewInt(0),
|
||||||
PragueTime: newUint64(0),
|
PragueTime: newUint64(0),
|
||||||
|
BlobScheduleConfig: &BlobScheduleConfig{
|
||||||
|
Cancun: DefaultCancunBlobConfig,
|
||||||
|
Prague: DefaultPragueBlobConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
||||||
|
@ -248,6 +262,10 @@ var (
|
||||||
TerminalTotalDifficulty: big.NewInt(0),
|
TerminalTotalDifficulty: big.NewInt(0),
|
||||||
Ethash: new(EthashConfig),
|
Ethash: new(EthashConfig),
|
||||||
Clique: nil,
|
Clique: nil,
|
||||||
|
BlobScheduleConfig: &BlobScheduleConfig{
|
||||||
|
Cancun: DefaultCancunBlobConfig,
|
||||||
|
Prague: DefaultPragueBlobConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// NonActivatedConfig defines the chain configuration without activating
|
// NonActivatedConfig defines the chain configuration without activating
|
||||||
|
@ -282,6 +300,26 @@ var (
|
||||||
TestRules = TestChainConfig.Rules(new(big.Int), false, 0)
|
TestRules = TestChainConfig.Rules(new(big.Int), false, 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultCancunBlobConfig is the default blob configuration for the Cancun fork.
|
||||||
|
DefaultCancunBlobConfig = &BlobConfig{
|
||||||
|
Target: 3,
|
||||||
|
Max: 6,
|
||||||
|
UpdateFraction: 3338477,
|
||||||
|
}
|
||||||
|
// DefaultPragueBlobConfig is the default blob configuration for the Prague fork.
|
||||||
|
DefaultPragueBlobConfig = &BlobConfig{
|
||||||
|
Target: 6,
|
||||||
|
Max: 9,
|
||||||
|
UpdateFraction: 5007716,
|
||||||
|
}
|
||||||
|
// DefaultBlobSchedule is the latest configured blob schedule for test chains.
|
||||||
|
DefaultBlobSchedule = &BlobScheduleConfig{
|
||||||
|
Cancun: DefaultCancunBlobConfig,
|
||||||
|
Prague: DefaultPragueBlobConfig,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// NetworkNames are user friendly names to use in the chain spec banner.
|
// NetworkNames are user friendly names to use in the chain spec banner.
|
||||||
var NetworkNames = map[string]string{
|
var NetworkNames = map[string]string{
|
||||||
MainnetChainConfig.ChainID.String(): "mainnet",
|
MainnetChainConfig.ChainID.String(): "mainnet",
|
||||||
|
@ -346,8 +384,9 @@ type ChainConfig struct {
|
||||||
EnableVerkleAtGenesis bool `json:"enableVerkleAtGenesis,omitempty"`
|
EnableVerkleAtGenesis bool `json:"enableVerkleAtGenesis,omitempty"`
|
||||||
|
|
||||||
// Various consensus engines
|
// Various consensus engines
|
||||||
Ethash *EthashConfig `json:"ethash,omitempty"`
|
Ethash *EthashConfig `json:"ethash,omitempty"`
|
||||||
Clique *CliqueConfig `json:"clique,omitempty"`
|
Clique *CliqueConfig `json:"clique,omitempty"`
|
||||||
|
BlobScheduleConfig *BlobScheduleConfig `json:"blobSchedule,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
|
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
|
||||||
|
@ -447,6 +486,20 @@ func (c *ChainConfig) Description() string {
|
||||||
return banner
|
return banner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlobConfig specifies the target and max blobs per block for the associated fork.
|
||||||
|
type BlobConfig struct {
|
||||||
|
Target int `json:"target"`
|
||||||
|
Max int `json:"max"`
|
||||||
|
UpdateFraction uint64 `json:"baseFeeUpdateFraction"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlobScheduleConfig determines target and max number of blobs allow per fork.
|
||||||
|
type BlobScheduleConfig struct {
|
||||||
|
Cancun *BlobConfig `json:"cancun,omitempty"`
|
||||||
|
Prague *BlobConfig `json:"prague,omitempty"`
|
||||||
|
Verkle *BlobConfig `json:"verkle,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// IsHomestead returns whether num is either equal to the homestead block or greater.
|
// IsHomestead returns whether num is either equal to the homestead block or greater.
|
||||||
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
|
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
|
||||||
return isBlockForked(c.HomesteadBlock, num)
|
return isBlockForked(c.HomesteadBlock, num)
|
||||||
|
@ -662,6 +715,45 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
|
||||||
lastFork = cur
|
lastFork = cur
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that all forks with blobs explicitly define the blob schedule configuration.
|
||||||
|
bsc := c.BlobScheduleConfig
|
||||||
|
if bsc == nil {
|
||||||
|
bsc = new(BlobScheduleConfig)
|
||||||
|
}
|
||||||
|
for _, cur := range []struct {
|
||||||
|
name string
|
||||||
|
timestamp *uint64
|
||||||
|
config *BlobConfig
|
||||||
|
}{
|
||||||
|
{name: "cancun", timestamp: c.CancunTime, config: bsc.Cancun},
|
||||||
|
{name: "prague", timestamp: c.PragueTime, config: bsc.Prague},
|
||||||
|
} {
|
||||||
|
if cur.config != nil {
|
||||||
|
if err := cur.config.validate(); err != nil {
|
||||||
|
return fmt.Errorf("invalid blob configuration for fork %s: %v", cur.name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cur.timestamp != nil {
|
||||||
|
// If the fork is configured, a blob schedule must be defined for it.
|
||||||
|
if cur.config == nil {
|
||||||
|
return fmt.Errorf("unsupported fork configuration: missing blob configuration entry for %v in schedule", cur.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlobConfig) validate() error {
|
||||||
|
if bc.Max < 0 {
|
||||||
|
return errors.New("max < 0")
|
||||||
|
}
|
||||||
|
if bc.Target < 0 {
|
||||||
|
return errors.New("target < 0")
|
||||||
|
}
|
||||||
|
if bc.UpdateFraction == 0 {
|
||||||
|
return errors.New("update fraction must be defined and non-zero")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -172,12 +172,8 @@ const (
|
||||||
BlobTxFieldElementsPerBlob = 4096 // Number of field elements stored in a single data blob
|
BlobTxFieldElementsPerBlob = 4096 // Number of field elements stored in a single data blob
|
||||||
BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
|
BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
|
||||||
BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs
|
BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs
|
||||||
BlobTxBlobGaspriceUpdateFraction = 3338477 // Controls the maximum rate of change for blob gas price
|
|
||||||
BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile.
|
BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile.
|
||||||
|
|
||||||
BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing)
|
|
||||||
MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block
|
|
||||||
|
|
||||||
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
|
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -334,6 +334,9 @@ var Forks = map[string]*params.ChainConfig{
|
||||||
TerminalTotalDifficulty: big.NewInt(0),
|
TerminalTotalDifficulty: big.NewInt(0),
|
||||||
ShanghaiTime: u64(0),
|
ShanghaiTime: u64(0),
|
||||||
CancunTime: u64(0),
|
CancunTime: u64(0),
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Cancun: params.DefaultCancunBlobConfig,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"ShanghaiToCancunAtTime15k": {
|
"ShanghaiToCancunAtTime15k": {
|
||||||
ChainID: big.NewInt(1),
|
ChainID: big.NewInt(1),
|
||||||
|
@ -353,6 +356,9 @@ var Forks = map[string]*params.ChainConfig{
|
||||||
TerminalTotalDifficulty: big.NewInt(0),
|
TerminalTotalDifficulty: big.NewInt(0),
|
||||||
ShanghaiTime: u64(0),
|
ShanghaiTime: u64(0),
|
||||||
CancunTime: u64(15_000),
|
CancunTime: u64(15_000),
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Cancun: params.DefaultCancunBlobConfig,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"Prague": {
|
"Prague": {
|
||||||
ChainID: big.NewInt(1),
|
ChainID: big.NewInt(1),
|
||||||
|
@ -374,6 +380,10 @@ var Forks = map[string]*params.ChainConfig{
|
||||||
CancunTime: u64(0),
|
CancunTime: u64(0),
|
||||||
PragueTime: u64(0),
|
PragueTime: u64(0),
|
||||||
DepositContractAddress: params.MainnetChainConfig.DepositContractAddress,
|
DepositContractAddress: params.MainnetChainConfig.DepositContractAddress,
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Cancun: params.DefaultCancunBlobConfig,
|
||||||
|
Prague: params.DefaultPragueBlobConfig,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"CancunToPragueAtTime15k": {
|
"CancunToPragueAtTime15k": {
|
||||||
ChainID: big.NewInt(1),
|
ChainID: big.NewInt(1),
|
||||||
|
@ -395,6 +405,10 @@ var Forks = map[string]*params.ChainConfig{
|
||||||
CancunTime: u64(0),
|
CancunTime: u64(0),
|
||||||
PragueTime: u64(15_000),
|
PragueTime: u64(15_000),
|
||||||
DepositContractAddress: params.MainnetChainConfig.DepositContractAddress,
|
DepositContractAddress: params.MainnetChainConfig.DepositContractAddress,
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Cancun: params.DefaultCancunBlobConfig,
|
||||||
|
Prague: params.DefaultPragueBlobConfig,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"Osaka": {
|
"Osaka": {
|
||||||
ChainID: big.NewInt(1),
|
ChainID: big.NewInt(1),
|
||||||
|
|
|
@ -303,7 +303,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
|
||||||
|
|
||||||
// Prepare the EVM.
|
// Prepare the EVM.
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
|
context := core.NewEVMBlockContext(block.Header(), &dummyChain{config: config}, &t.json.Env.Coinbase)
|
||||||
context.GetHash = vmTestBlockHash
|
context.GetHash = vmTestBlockHash
|
||||||
context.BaseFee = baseFee
|
context.BaseFee = baseFee
|
||||||
evm := vm.NewEVM(context, state.StateDB, config, vmconfig)
|
evm := vm.NewEVM(context, state.StateDB, config, vmconfig)
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
@ -275,13 +276,14 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
return st, common.Hash{}, 0, err
|
return st, common.Hash{}, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Blob transactions may be present after the Cancun fork.
|
// Blob transactions may be present after the Cancun fork.
|
||||||
// In production,
|
// In production,
|
||||||
// - the header is verified against the max in eip4844.go:VerifyEIP4844Header
|
// - the header is verified against the max in eip4844.go:VerifyEIP4844Header
|
||||||
// - the block body is verified against the header in block_validator.go:ValidateBody
|
// - the block body is verified against the header in block_validator.go:ValidateBody
|
||||||
// Here, we just do this shortcut smaller fix, since state tests do not
|
// Here, we just do this shortcut smaller fix, since state tests do not
|
||||||
// utilize those codepaths
|
// utilize those codepaths.
|
||||||
if len(msg.BlobHashes)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock {
|
if config.IsCancun(new(big.Int), block.Time()) {
|
||||||
|
if len(msg.BlobHashes) > eip4844.MaxBlobsPerBlock(config, block.Time()) {
|
||||||
return st, common.Hash{}, 0, errors.New("blob gas exceeds maximum")
|
return st, common.Hash{}, 0, errors.New("blob gas exceeds maximum")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,7 +301,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the EVM.
|
// Prepare the EVM.
|
||||||
context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
|
context := core.NewEVMBlockContext(block.Header(), &dummyChain{config: config}, &t.json.Env.Coinbase)
|
||||||
context.GetHash = vmTestBlockHash
|
context.GetHash = vmTestBlockHash
|
||||||
context.BaseFee = baseFee
|
context.BaseFee = baseFee
|
||||||
context.Random = nil
|
context.Random = nil
|
||||||
|
@ -312,8 +314,13 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
context.Difficulty = big.NewInt(0)
|
context.Difficulty = big.NewInt(0)
|
||||||
}
|
}
|
||||||
if config.IsCancun(new(big.Int), block.Time()) && t.json.Env.ExcessBlobGas != nil {
|
if config.IsCancun(new(big.Int), block.Time()) && t.json.Env.ExcessBlobGas != nil {
|
||||||
context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas)
|
header := &types.Header{
|
||||||
|
Time: block.Time(),
|
||||||
|
ExcessBlobGas: t.json.Env.ExcessBlobGas,
|
||||||
|
}
|
||||||
|
context.BlobBaseFee = eip4844.CalcBlobFee(config, header)
|
||||||
}
|
}
|
||||||
|
|
||||||
evm := vm.NewEVM(context, st.StateDB, config, vmconfig)
|
evm := vm.NewEVM(context, st.StateDB, config, vmconfig)
|
||||||
|
|
||||||
if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil {
|
if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil {
|
||||||
|
@ -543,3 +550,12 @@ func (st *StateTestState) Close() {
|
||||||
st.Snapshots = nil
|
st.Snapshots = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dummyChain implements the core.ChainContext interface.
|
||||||
|
type dummyChain struct {
|
||||||
|
config *params.ChainConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyChain) Engine() consensus.Engine { return nil }
|
||||||
|
func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header { return nil }
|
||||||
|
func (d *dummyChain) Config() *params.ChainConfig { return d.config }
|
||||||
|
|
Loading…
Reference in New Issue