mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
Merge branch 'develop' into fix-requests-hash-in-sdk
This commit is contained in:
commit
47bc86cd96
37 changed files with 461 additions and 118 deletions
|
|
@ -640,7 +640,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
|||
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
||||
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
signer := types.MakeSigner(b.blockchain.Config(), head.Number, head.Time)
|
||||
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, head.BaseFee, b.blockchain.Config(), signer, stateDB, head.Number)
|
||||
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, head.BaseFee, b.blockchain.Config(), signer, stateDB, head.Number, head.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
if chainConfig.CurieBlock != nil && chainConfig.CurieBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 {
|
||||
misc.ApplyCurieHardFork(statedb)
|
||||
}
|
||||
// Apply Feynman hard fork
|
||||
if chainConfig.IsFeynmanTransitionBlock(pre.Env.Timestamp, pre.Env.ParentTimestamp) {
|
||||
misc.ApplyFeynmanHardFork(statedb)
|
||||
}
|
||||
// Apply EIP-2935
|
||||
if pre.Env.BlockHashes != nil && chainConfig.IsFeynman(pre.Env.Timestamp) {
|
||||
var (
|
||||
|
|
@ -180,7 +184,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
snapshot := statedb.Snapshot()
|
||||
evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
|
||||
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, chainConfig, new(big.Int).SetUint64(pre.Env.Number))
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
|
||||
if err != nil {
|
||||
log.Info("rejected tx due to fees.CalculateL1DataFee", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
|
||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||
|
|
|
|||
|
|
@ -176,6 +176,8 @@ var (
|
|||
utils.CircuitCapacityCheckWorkersFlag,
|
||||
utils.RollupVerifyEnabledFlag,
|
||||
utils.ShadowforkPeersFlag,
|
||||
utils.TxGossipBroadcastDisabledFlag,
|
||||
utils.TxGossipReceivingDisabledFlag,
|
||||
utils.DASyncEnabledFlag,
|
||||
utils.DABlockNativeAPIEndpointFlag,
|
||||
utils.DABlobScanAPIEndpointFlag,
|
||||
|
|
|
|||
|
|
@ -248,6 +248,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{
|
|||
utils.DARecoveryProduceBlocksFlag,
|
||||
utils.CircuitCapacityCheckEnabledFlag,
|
||||
utils.CircuitCapacityCheckWorkersFlag,
|
||||
utils.TxGossipBroadcastDisabledFlag,
|
||||
utils.TxGossipReceivingDisabledFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -893,6 +893,16 @@ var (
|
|||
Usage: "peer ids of shadow fork peers",
|
||||
}
|
||||
|
||||
// Tx gossip settings
|
||||
TxGossipBroadcastDisabledFlag = cli.BoolFlag{
|
||||
Name: "txgossip.disablebroadcast",
|
||||
Usage: "Disable gossip broadcast transactions to other peers",
|
||||
}
|
||||
TxGossipReceivingDisabledFlag = cli.BoolFlag{
|
||||
Name: "txgossip.disablereceiving",
|
||||
Usage: "Disable gossip receiving transactions from other peers",
|
||||
}
|
||||
|
||||
// DA syncing settings
|
||||
DASyncEnabledFlag = cli.BoolFlag{
|
||||
Name: "da.sync",
|
||||
|
|
@ -1790,6 +1800,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||
cfg.ShadowForkPeerIDs = ctx.GlobalStringSlice(ShadowforkPeersFlag.Name)
|
||||
log.Info("Shadow fork peers", "ids", cfg.ShadowForkPeerIDs)
|
||||
}
|
||||
if ctx.GlobalIsSet(TxGossipBroadcastDisabledFlag.Name) {
|
||||
cfg.TxGossipBroadcastDisabled = ctx.GlobalBool(TxGossipBroadcastDisabledFlag.Name)
|
||||
log.Info("Transaction gossip broadcast disabled", "disabled", cfg.TxGossipBroadcastDisabled)
|
||||
}
|
||||
if ctx.GlobalIsSet(TxGossipReceivingDisabledFlag.Name) {
|
||||
cfg.TxGossipReceivingDisabled = ctx.GlobalBool(TxGossipReceivingDisabledFlag.Name)
|
||||
log.Info("Transaction gossip receiving disabled", "disabled", cfg.TxGossipReceivingDisabled)
|
||||
}
|
||||
|
||||
// Cap the cache allowance and tune the garbage collector
|
||||
mem, err := gopsutil.VirtualMemory()
|
||||
|
|
|
|||
22
consensus/misc/feynman.go
Normal file
22
consensus/misc/feynman.go
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package misc
|
||||
|
||||
import (
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/state"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
||||
)
|
||||
|
||||
// ApplyFeynmanHardFork modifies the state database according to the Feynman hard-fork rules,
|
||||
// updating the bytecode and storage of the L1GasPriceOracle contract.
|
||||
func ApplyFeynmanHardFork(statedb *state.StateDB) {
|
||||
log.Info("Applying Feynman hard fork")
|
||||
|
||||
// update contract byte code
|
||||
statedb.SetCode(rcfg.L1GasPriceOracleAddress, rcfg.FeynmanL1GasPriceOracleBytecode)
|
||||
|
||||
// initialize new storage slots
|
||||
statedb.SetState(rcfg.L1GasPriceOracleAddress, rcfg.IsFeynmanSlot, common.BytesToHash([]byte{1}))
|
||||
statedb.SetState(rcfg.L1GasPriceOracleAddress, rcfg.PenaltyThresholdSlot, common.BigToHash(rcfg.InitialPenaltyThreshold))
|
||||
statedb.SetState(rcfg.L1GasPriceOracleAddress, rcfg.PenaltyFactorSlot, common.BigToHash(rcfg.InitialPenaltyFactor))
|
||||
}
|
||||
|
|
@ -249,6 +249,9 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
if config.CurieBlock != nil && config.CurieBlock.Cmp(b.header.Number) == 0 {
|
||||
misc.ApplyCurieHardFork(statedb)
|
||||
}
|
||||
if config.IsFeynmanTransitionBlock(b.Time(), parent.Time()) {
|
||||
misc.ApplyFeynmanHardFork(statedb)
|
||||
}
|
||||
// Execute any user modifications to the block
|
||||
if gen != nil {
|
||||
gen(i, b)
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
|||
}
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, p.config, block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, p.config, block.Number(), block.Time())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
header = block.Header()
|
||||
blockHash = block.Hash()
|
||||
blockNumber = block.Number()
|
||||
blockTime = block.Time()
|
||||
allLogs []*types.Log
|
||||
gp = new(GasPool).AddGas(block.GasLimit())
|
||||
)
|
||||
|
|
@ -91,6 +92,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
if p.config.CurieBlock != nil && p.config.CurieBlock.Cmp(block.Number()) == 0 {
|
||||
misc.ApplyCurieHardFork(statedb)
|
||||
}
|
||||
// Apply Feynman hard fork
|
||||
parent := p.bc.GetHeaderByHash(block.ParentHash())
|
||||
if p.config.IsFeynmanTransitionBlock(block.Time(), parent.Time) {
|
||||
misc.ApplyFeynmanHardFork(statedb)
|
||||
}
|
||||
blockContext := NewEVMBlockContext(header, p.bc, p.config, nil)
|
||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
||||
processorBlockTransactionGauge.Update(int64(block.Transactions().Len()))
|
||||
|
|
@ -105,7 +111,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
|
||||
receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockTime, blockHash, tx, usedGas, vmenv)
|
||||
if err != nil {
|
||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
|
|
@ -120,7 +126,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
return receipts, allLogs, *usedGas, nil
|
||||
}
|
||||
|
||||
func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
|
||||
func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockTime uint64, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
|
||||
defer func(t0 time.Time) {
|
||||
applyTransactionTimer.Update(time.Since(t0))
|
||||
}(time.Now())
|
||||
|
|
@ -129,7 +135,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
|
|||
txContext := NewEVMTxContext(msg)
|
||||
evm.Reset(txContext, statedb)
|
||||
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, config, blockNumber)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, config, blockNumber, blockTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -201,7 +207,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
|||
// Create a new context to be used in the EVM environment
|
||||
blockContext := NewEVMBlockContext(header, bc, config, author)
|
||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
|
||||
return applyTransaction(msg, config, bc, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
|
||||
return applyTransaction(msg, config, bc, author, gp, statedb, header.Number, header.Time, header.Hash(), tx, usedGas, vmenv)
|
||||
}
|
||||
|
||||
// ProcessParentBlockHash stores the parent block hash in the history storage contract
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ func (l *txList) Overlaps(tx *types.Transaction) bool {
|
|||
//
|
||||
// If the new transaction is accepted into the list, the lists' cost and gas
|
||||
// thresholds are also potentially updated.
|
||||
func (l *txList) Add(tx *types.Transaction, state *state.StateDB, priceBump uint64, chainconfig *params.ChainConfig, blockNumber *big.Int) (bool, *types.Transaction) {
|
||||
func (l *txList) Add(tx *types.Transaction, state *state.StateDB, priceBump uint64, chainconfig *params.ChainConfig, blockNumber *big.Int, blockTime uint64) (bool, *types.Transaction) {
|
||||
// If there's an older better transaction, abort
|
||||
old := l.txs.Get(tx.Nonce())
|
||||
if old != nil {
|
||||
|
|
@ -310,7 +310,7 @@ func (l *txList) Add(tx *types.Transaction, state *state.StateDB, priceBump uint
|
|||
l1DataFee := big.NewInt(0)
|
||||
if state != nil && chainconfig != nil {
|
||||
var err error
|
||||
l1DataFee, err = fees.CalculateL1DataFee(tx, state, chainconfig, blockNumber)
|
||||
l1DataFee, err = fees.CalculateL1DataFee(tx, state, chainconfig, blockNumber, blockTime)
|
||||
if err != nil {
|
||||
log.Error("Failed to calculate L1 data fee", "err", err, "tx", tx)
|
||||
return false, nil
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ func TestStrictTxListAdd(t *testing.T) {
|
|||
// Insert the transactions in a random order
|
||||
list := newTxList(true)
|
||||
for _, v := range rand.Perm(len(txs)) {
|
||||
list.Add(txs[v], nil, DefaultTxPoolConfig.PriceBump, nil, nil)
|
||||
list.Add(txs[v], nil, DefaultTxPoolConfig.PriceBump, nil, nil, 0)
|
||||
}
|
||||
// Verify internal state
|
||||
if len(list.txs.items) != len(txs) {
|
||||
|
|
@ -65,7 +65,7 @@ func BenchmarkTxListAdd(b *testing.B) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
list := newTxList(true)
|
||||
for _, v := range rand.Perm(len(txs)) {
|
||||
list.Add(txs[v], nil, DefaultTxPoolConfig.PriceBump, nil, nil)
|
||||
list.Add(txs[v], nil, DefaultTxPoolConfig.PriceBump, nil, nil, 0)
|
||||
list.Filter(priceLimit, DefaultTxPoolConfig.PriceBump)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -301,6 +301,7 @@ type TxPool struct {
|
|||
|
||||
currentState *state.StateDB // Current state in the blockchain head
|
||||
currentHead *big.Int // Current blockchain head
|
||||
currentTime uint64 // Current blockchain head time
|
||||
pendingNonces *txNoncer // Pending state tracking virtual nonces
|
||||
currentMaxGas uint64 // Current gas limit for transaction caps
|
||||
|
||||
|
|
@ -838,7 +839,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
|
|||
// 2. If FeeVault is enabled, perform an additional check for L1 data fees.
|
||||
if pool.chainconfig.Scroll.FeeVaultEnabled() {
|
||||
// Get L1 data fee in current state
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, pool.currentState, pool.chainconfig, pool.currentHead)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, pool.currentState, pool.chainconfig, pool.currentHead, pool.currentTime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to calculate L1 data fee, err: %w", err)
|
||||
}
|
||||
|
|
@ -947,7 +948,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
|||
from, _ := types.Sender(pool.signer, tx) // already validated
|
||||
if list := pool.pending[from]; list != nil && list.Overlaps(tx) {
|
||||
// Nonce already pending, check if required price bump is met
|
||||
inserted, old := list.Add(tx, pool.currentState, pool.config.PriceBump, pool.chainconfig, pool.currentHead)
|
||||
inserted, old := list.Add(tx, pool.currentState, pool.config.PriceBump, pool.chainconfig, pool.currentHead, pool.currentTime)
|
||||
if !inserted {
|
||||
log.Debug("Discarding underpriced pending transaction", "hash", hash.Hex(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
||||
pendingDiscardMeter.Mark(1)
|
||||
|
|
@ -1001,7 +1002,7 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction, local boo
|
|||
pool.queue[from] = newTxList(false)
|
||||
}
|
||||
|
||||
inserted, old := pool.queue[from].Add(tx, pool.currentState, pool.config.PriceBump, pool.chainconfig, pool.currentHead)
|
||||
inserted, old := pool.queue[from].Add(tx, pool.currentState, pool.config.PriceBump, pool.chainconfig, pool.currentHead, pool.currentTime)
|
||||
if !inserted {
|
||||
// An older transaction was better, discard this
|
||||
log.Debug("Discarding underpriced queued transaction", "hash", hash.Hex(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
||||
|
|
@ -1068,7 +1069,7 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T
|
|||
return false
|
||||
}
|
||||
|
||||
inserted, old := list.Add(tx, pool.currentState, pool.config.PriceBump, pool.chainconfig, pool.currentHead)
|
||||
inserted, old := list.Add(tx, pool.currentState, pool.config.PriceBump, pool.chainconfig, pool.currentHead, pool.currentTime)
|
||||
if !inserted {
|
||||
// An older transaction was better, discard this
|
||||
log.Debug("Discarding underpriced pending transaction", "hash", hash.Hex(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
||||
|
|
@ -1603,6 +1604,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
|
|||
|
||||
// Update current head
|
||||
pool.currentHead = next
|
||||
pool.currentTime = newHead.Time
|
||||
}
|
||||
|
||||
// promoteExecutables moves transactions that have become processable from the
|
||||
|
|
@ -1690,7 +1692,7 @@ func (pool *TxPool) executableTxFilter(costLimit *big.Int) func(tx *types.Transa
|
|||
|
||||
if pool.chainconfig.Scroll.FeeVaultEnabled() {
|
||||
// recheck L1 data fee, as the oracle price may have changed
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, pool.currentState, pool.chainconfig, pool.currentHead)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, pool.currentState, pool.chainconfig, pool.currentHead, pool.currentTime)
|
||||
if err != nil {
|
||||
log.Error("Failed to calculate L1 data fee", "err", err, "tx", tx)
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -362,6 +362,11 @@ func generateWitness(blockchain *core.BlockChain, block *types.Block) (*stateles
|
|||
// Collect storage locations that prover needs but sequencer might not touch necessarily
|
||||
statedb.GetState(rcfg.L2MessageQueueAddress, rcfg.WithdrawTrieRootSlot)
|
||||
|
||||
// Note: scroll-revm detects the Feynman transition block using this storage slot,
|
||||
// since it does not have access to the parent block timestamp. We need to make
|
||||
// sure that this is always present in the execution witness.
|
||||
statedb.GetState(rcfg.L1GasPriceOracleAddress, rcfg.IsFeynmanSlot)
|
||||
|
||||
receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, *blockchain.GetVMConfig())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to process block %d: %w", block.Number(), err)
|
||||
|
|
|
|||
|
|
@ -273,16 +273,18 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client l1.Client) (*Ether
|
|||
checkpoint = params.TrustedCheckpoints[genesisHash]
|
||||
}
|
||||
if eth.handler, err = newHandler(&handlerConfig{
|
||||
Database: chainDb,
|
||||
Chain: eth.blockchain,
|
||||
TxPool: eth.txPool,
|
||||
Network: config.NetworkId,
|
||||
Sync: config.SyncMode,
|
||||
BloomCache: uint64(cacheLimit),
|
||||
EventMux: eth.eventMux,
|
||||
Checkpoint: checkpoint,
|
||||
Whitelist: config.Whitelist,
|
||||
ShadowForkPeerIDs: config.ShadowForkPeerIDs,
|
||||
Database: chainDb,
|
||||
Chain: eth.blockchain,
|
||||
TxPool: eth.txPool,
|
||||
Network: config.NetworkId,
|
||||
Sync: config.SyncMode,
|
||||
BloomCache: uint64(cacheLimit),
|
||||
EventMux: eth.eventMux,
|
||||
Checkpoint: checkpoint,
|
||||
Whitelist: config.Whitelist,
|
||||
ShadowForkPeerIDs: config.ShadowForkPeerIDs,
|
||||
DisableTxBroadcast: config.TxGossipBroadcastDisabled,
|
||||
DisableTxReceiving: config.TxGossipReceivingDisabled,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -230,6 +230,9 @@ type Config struct {
|
|||
|
||||
// DA syncer options
|
||||
DA da_syncer.Config
|
||||
|
||||
TxGossipBroadcastDisabled bool
|
||||
TxGossipReceivingDisabled bool
|
||||
}
|
||||
|
||||
// CreateConsensusEngine creates a consensus engine for the given chain configuration.
|
||||
|
|
|
|||
|
|
@ -93,6 +93,9 @@ type handlerConfig struct {
|
|||
Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges
|
||||
Whitelist map[uint64]common.Hash // Hard coded whitelist for sync challenged
|
||||
ShadowForkPeerIDs []string // List of peer ids that take part in the shadow-fork
|
||||
|
||||
DisableTxBroadcast bool
|
||||
DisableTxReceiving bool
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
|
|
@ -131,7 +134,9 @@ type handler struct {
|
|||
wg sync.WaitGroup
|
||||
peerWG sync.WaitGroup
|
||||
|
||||
shadowForkPeerIDs []string
|
||||
shadowForkPeerIDs []string
|
||||
disableTxBroadcast bool
|
||||
disableTxReceiving bool
|
||||
}
|
||||
|
||||
// newHandler returns a handler for all Ethereum chain management protocol.
|
||||
|
|
@ -141,16 +146,18 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
|||
config.EventMux = new(event.TypeMux) // Nicety initialization for tests
|
||||
}
|
||||
h := &handler{
|
||||
networkID: config.Network,
|
||||
forkFilter: forkid.NewFilter(config.Chain),
|
||||
eventMux: config.EventMux,
|
||||
database: config.Database,
|
||||
txpool: config.TxPool,
|
||||
chain: config.Chain,
|
||||
peers: newPeerSet(),
|
||||
whitelist: config.Whitelist,
|
||||
quitSync: make(chan struct{}),
|
||||
shadowForkPeerIDs: config.ShadowForkPeerIDs,
|
||||
networkID: config.Network,
|
||||
forkFilter: forkid.NewFilter(config.Chain),
|
||||
eventMux: config.EventMux,
|
||||
database: config.Database,
|
||||
txpool: config.TxPool,
|
||||
chain: config.Chain,
|
||||
peers: newPeerSet(),
|
||||
whitelist: config.Whitelist,
|
||||
quitSync: make(chan struct{}),
|
||||
shadowForkPeerIDs: config.ShadowForkPeerIDs,
|
||||
disableTxBroadcast: config.DisableTxBroadcast,
|
||||
disableTxReceiving: config.DisableTxReceiving,
|
||||
}
|
||||
if config.Sync == downloader.FullSync {
|
||||
// The database seems empty as the current block is the genesis. Yet the fast
|
||||
|
|
@ -415,10 +422,12 @@ func (h *handler) Start(maxPeers int) {
|
|||
h.maxPeers = maxPeers
|
||||
|
||||
// broadcast transactions
|
||||
h.wg.Add(1)
|
||||
h.txsCh = make(chan core.NewTxsEvent, txChanSize)
|
||||
h.txsSub = h.txpool.SubscribeNewTxsEvent(h.txsCh)
|
||||
go h.txBroadcastLoop()
|
||||
if !h.disableTxBroadcast {
|
||||
h.wg.Add(1)
|
||||
h.txsCh = make(chan core.NewTxsEvent, txChanSize)
|
||||
h.txsSub = h.txpool.SubscribeNewTxsEvent(h.txsCh)
|
||||
go h.txBroadcastLoop()
|
||||
}
|
||||
|
||||
// broadcast mined blocks
|
||||
h.wg.Add(1)
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ func (h *ethHandler) PeerInfo(id enode.ID) interface{} {
|
|||
// AcceptTxs retrieves whether transaction processing is enabled on the node
|
||||
// or if inbound transactions should simply be dropped.
|
||||
func (h *ethHandler) AcceptTxs() bool {
|
||||
if h.disableTxReceiving {
|
||||
return false
|
||||
}
|
||||
return atomic.LoadUint32(&h.acceptTxs) == 1
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec
|
|||
// Not yet the searched for transaction, execute on top of the current state
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
|
||||
statedb.SetTxContext(tx.Hash(), idx)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, eth.blockchain.Config(), block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, eth.blockchain.Config(), block.Number(), block.Time())
|
||||
if err != nil {
|
||||
return nil, vm.BlockContext{}, nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
|
|||
TxHash: tx.Hash(),
|
||||
}
|
||||
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, task.statedb, api.backend.ChainConfig(), task.block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, task.statedb, api.backend.ChainConfig(), task.block.Number(), task.block.Time())
|
||||
if err != nil {
|
||||
// though it's not a "tracing error", we still need to put it here
|
||||
task.results[i] = &txTraceResult{Error: err.Error()}
|
||||
|
|
@ -557,7 +557,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
|||
)
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
if err != nil {
|
||||
log.Warn("Tracing intermediate roots did not complete due to fees.CalculateL1DataFee", "txindex", i, "txhash", tx.Hash(), "err", err)
|
||||
return nil, err
|
||||
|
|
@ -645,7 +645,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||
TxHash: txs[task.index].Hash(),
|
||||
}
|
||||
|
||||
l1DataFee, err := fees.CalculateL1DataFee(txs[task.index], task.statedb, api.backend.ChainConfig(), block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(txs[task.index], task.statedb, api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
if err != nil {
|
||||
// though it's not a "tracing error", we still need to put it here
|
||||
results[task.index] = &txTraceResult{
|
||||
|
|
@ -679,7 +679,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
if err != nil {
|
||||
failed = err
|
||||
break
|
||||
|
|
@ -804,7 +804,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
|||
// Execute the transaction and flush any traces to disk
|
||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
if err == nil {
|
||||
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee)
|
||||
}
|
||||
|
|
@ -869,7 +869,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
|
|||
TxIndex: int(index),
|
||||
TxHash: hash,
|
||||
}
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -929,7 +929,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
|||
}
|
||||
|
||||
signer := types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
||||
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, block.BaseFee(), api.backend.ChainConfig(), signer, statedb, block.Number())
|
||||
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, block.BaseFee(), api.backend.ChainConfig(), signer, statedb, block.Number(), block.Time())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
|||
return msg, context, statedb, nil
|
||||
}
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, b.chainConfig, block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, b.chainConfig, block.Number(), block.Time())
|
||||
if err != nil {
|
||||
return nil, vm.BlockContext{}, nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
}
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, test.Genesis.Config, context.BlockNumber)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, test.Genesis.Config, context.BlockNumber, context.Time.Uint64())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to calculate l1DataFee: %v", err)
|
||||
}
|
||||
|
|
@ -308,7 +308,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
|||
}
|
||||
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||
snap := statedb.Snapshot()
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, test.Genesis.Config, context.BlockNumber)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, test.Genesis.Config, context.BlockNumber, context.Time.Uint64())
|
||||
if err != nil {
|
||||
b.Fatalf("failed to calculate l1DataFee: %v", err)
|
||||
}
|
||||
|
|
@ -381,7 +381,7 @@ func TestZeroValueToNotExitCall(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
}
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, params.MainnetChainConfig, context.BlockNumber)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, params.MainnetChainConfig, context.BlockNumber, context.Time.Uint64())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to calculate l1DataFee: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
|||
|
||||
for i := 0; i < b.N; i++ {
|
||||
snap := statedb.Snapshot()
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, params.AllEthashProtocolChanges, context.BlockNumber)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, params.AllEthashProtocolChanges, context.BlockNumber, context.Time.Uint64())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -51,7 +51,7 @@ require (
|
|||
github.com/prometheus/tsdb v0.7.1
|
||||
github.com/rjeczalik/notify v0.9.1
|
||||
github.com/rs/cors v1.7.0
|
||||
github.com/scroll-tech/da-codec v0.1.3-0.20250313120912-344f2d5e33e1
|
||||
github.com/scroll-tech/da-codec v0.1.3-0.20250626091118-58b899494da6
|
||||
github.com/scroll-tech/zktrie v0.8.4
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/sourcegraph/conc v0.3.0
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -396,8 +396,8 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj
|
|||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/scroll-tech/da-codec v0.1.3-0.20250313120912-344f2d5e33e1 h1:Dhd58LE1D+dnoxpgLVeQBMF9uweL/fhQfZHWtWSiOlE=
|
||||
github.com/scroll-tech/da-codec v0.1.3-0.20250313120912-344f2d5e33e1/go.mod h1:yhTS9OVC0xQGhg7DN5iV5KZJvnSIlFWAxDdp+6jxQtY=
|
||||
github.com/scroll-tech/da-codec v0.1.3-0.20250626091118-58b899494da6 h1:vb2XLvQwCf+F/ifP6P/lfeiQrHY6+Yb/E3R4KHXLqSE=
|
||||
github.com/scroll-tech/da-codec v0.1.3-0.20250626091118-58b899494da6/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg=
|
||||
github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE=
|
||||
github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
|
|
|
|||
|
|
@ -999,7 +999,7 @@ func EstimateL1MsgFee(ctx context.Context, b Backend, args TransactionArgs, bloc
|
|||
}()
|
||||
|
||||
signer := types.MakeSigner(config, header.Number, header.Time)
|
||||
return fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, evm.StateDB, header.Number)
|
||||
return fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, evm.StateDB, header.Number, header.Time)
|
||||
}
|
||||
|
||||
func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
||||
|
|
@ -1595,7 +1595,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
|||
return nil, 0, nil, err
|
||||
}
|
||||
signer := types.MakeSigner(b.ChainConfig(), header.Number, header.Time)
|
||||
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, b.ChainConfig(), signer, statedb, header.Number)
|
||||
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, b.ChainConfig(), signer, statedb, header.Number, header.Time)
|
||||
if err != nil {
|
||||
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
|||
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
|
||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
signer := types.MakeSigner(config, header.Number, header.Time)
|
||||
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, statedb, header.Number)
|
||||
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, statedb, header.Number, header.Time)
|
||||
result, _ := core.ApplyMessage(vmenv, msg, gp, l1DataFee)
|
||||
res = append(res, result.Return()...)
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
|||
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true})
|
||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
signer := types.MakeSigner(config, header.Number, header.Time)
|
||||
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, state, header.Number)
|
||||
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, state, header.Number, header.Time)
|
||||
result, _ := core.ApplyMessage(vmenv, msg, gp, l1DataFee)
|
||||
if state.Error() == nil {
|
||||
res = append(res, result.Return()...)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
|
|||
}
|
||||
// Not yet the searched for transaction, execute on top of the current state
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{})
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, leth.blockchain.Config(), block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, leth.blockchain.Config(), block.Number(), block.Time())
|
||||
if err != nil {
|
||||
return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
|||
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
|
||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
signer := types.MakeSigner(config, header.Number, header.Time)
|
||||
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, st, header.Number)
|
||||
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config, signer, st, header.Number, header.Time)
|
||||
result, _ := core.ApplyMessage(vmenv, msg, gp, l1DataFee)
|
||||
res = append(res, result.Return()...)
|
||||
if st.Error() != nil {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ type TxPool struct {
|
|||
shanghai bool // Fork indicator whether we are in the shanghai stage.
|
||||
|
||||
currentHead *big.Int // Current blockchain head
|
||||
currentTime uint64 // Current blockchain head time
|
||||
}
|
||||
|
||||
// TxRelayBackend provides an interface to the mechanism that forwards transacions
|
||||
|
|
@ -326,6 +327,7 @@ func (pool *TxPool) setNewHead(head *types.Header) {
|
|||
pool.shanghai = pool.config.IsShanghai(next)
|
||||
|
||||
pool.currentHead = next
|
||||
pool.currentTime = head.Time
|
||||
}
|
||||
|
||||
// Stop stops the light transaction pool
|
||||
|
|
@ -408,7 +410,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
|
|||
// 2. If FeeVault is enabled, perform an additional check for L1 data fees.
|
||||
if pool.config.Scroll.FeeVaultEnabled() {
|
||||
// Get L1 data fee in current state
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, currentState, pool.config, pool.currentHead)
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, currentState, pool.config, pool.currentHead, pool.currentTime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to calculate L1 data fee, err: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -464,8 +464,7 @@ func (w *worker) collectPendingL1Messages(startIndex uint64) []types.L1MessageTx
|
|||
}
|
||||
|
||||
// newWork
|
||||
func (w *worker) newWork(now time.Time, parentHash common.Hash, reorging bool, reorgReason error) error {
|
||||
parent := w.chain.GetBlockByHash(parentHash)
|
||||
func (w *worker) newWork(now time.Time, parent *types.Block, reorging bool, reorgReason error) error {
|
||||
header := &types.Header{
|
||||
ParentHash: parent.Hash(),
|
||||
Number: new(big.Int).Add(parent.Number(), common.Big1),
|
||||
|
|
@ -586,13 +585,14 @@ func (w *worker) newWork(now time.Time, parentHash common.Hash, reorging bool, r
|
|||
}
|
||||
|
||||
// tryCommitNewWork
|
||||
func (w *worker) tryCommitNewWork(now time.Time, parent common.Hash, reorging bool, reorgReason error) (common.Hash, error) {
|
||||
func (w *worker) tryCommitNewWork(now time.Time, parentHash common.Hash, reorging bool, reorgReason error) (common.Hash, error) {
|
||||
parent := w.chain.GetBlockByHash(parentHash)
|
||||
err := w.newWork(now, parent, reorging, reorgReason)
|
||||
if err != nil {
|
||||
return common.Hash{}, fmt.Errorf("failed creating new work: %w", err)
|
||||
}
|
||||
|
||||
shouldCommit, err := w.handleForks()
|
||||
shouldCommit, err := w.handleForks(parent)
|
||||
if err != nil {
|
||||
return common.Hash{}, fmt.Errorf("failed handling forks: %w", err)
|
||||
}
|
||||
|
|
@ -626,17 +626,16 @@ func (w *worker) tryCommitNewWork(now time.Time, parent common.Hash, reorging bo
|
|||
}
|
||||
|
||||
// handleForks
|
||||
func (w *worker) handleForks() (bool, error) {
|
||||
func (w *worker) handleForks(parent *types.Block) (bool, error) {
|
||||
// Apply Curie predeployed contract update
|
||||
if w.chainConfig.CurieBlock != nil && w.chainConfig.CurieBlock.Cmp(w.current.header.Number) == 0 {
|
||||
misc.ApplyCurieHardFork(w.current.state)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Stop/start miner at Euclid fork boundary on zktrie/mpt nodes
|
||||
if w.chainConfig.IsEuclid(w.current.header.Time) {
|
||||
parent := w.chain.GetBlockByHash(w.current.header.ParentHash)
|
||||
return parent != nil && !w.chainConfig.IsEuclid(parent.Time()), nil
|
||||
// Apply Feynman hard fork
|
||||
if w.chainConfig.IsFeynmanTransitionBlock(w.current.header.Time, parent.Time()) {
|
||||
misc.ApplyFeynmanHardFork(w.current.state)
|
||||
}
|
||||
|
||||
// Apply EIP-2935
|
||||
|
|
@ -646,6 +645,12 @@ func (w *worker) handleForks() (bool, error) {
|
|||
core.ProcessParentBlockHash(w.current.header.ParentHash, vmenv, w.current.state)
|
||||
}
|
||||
|
||||
// Stop/start miner at Euclid fork boundary on zktrie/mpt nodes
|
||||
if w.chainConfig.IsEuclid(w.current.header.Time) {
|
||||
parent := w.chain.GetBlockByHash(w.current.header.ParentHash)
|
||||
return parent != nil && !w.chainConfig.IsEuclid(parent.Time()), nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1002,6 +1002,11 @@ func (c *ChainConfig) IsFeynman(now uint64) bool {
|
|||
return isForkedTime(now, c.FeynmanTime)
|
||||
}
|
||||
|
||||
// IsFeynmanTransitionBlock returns whether the given block timestamp corresponds to the first Feynman block.
|
||||
func (c *ChainConfig) IsFeynmanTransitionBlock(blockTimestamp uint64, parentTimestamp uint64) bool {
|
||||
return isForkedTime(blockTimestamp, c.FeynmanTime) && !isForkedTime(parentTimestamp, c.FeynmanTime)
|
||||
}
|
||||
|
||||
// IsTerminalPoWBlock returns whether the given block is the last block of PoW stage.
|
||||
func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool {
|
||||
if c.TerminalTotalDifficulty == nil {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
const (
|
||||
VersionMajor = 5 // Major version component of the current release
|
||||
VersionMinor = 8 // Minor version component of the current release
|
||||
VersionPatch = 56 // Patch version component of the current release
|
||||
VersionPatch = 59 // Patch version component of the current release
|
||||
VersionMeta = "mainnet" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,17 @@ package fees
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/scroll-tech/da-codec/encoding"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/scroll-tech/go-ethereum/params"
|
||||
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
||||
)
|
||||
|
|
@ -54,15 +57,17 @@ type StateDB interface {
|
|||
}
|
||||
|
||||
type gpoState struct {
|
||||
l1BaseFee *big.Int
|
||||
overhead *big.Int
|
||||
scalar *big.Int
|
||||
l1BlobBaseFee *big.Int
|
||||
commitScalar *big.Int
|
||||
blobScalar *big.Int
|
||||
l1BaseFee *big.Int
|
||||
overhead *big.Int
|
||||
scalar *big.Int
|
||||
l1BlobBaseFee *big.Int
|
||||
commitScalar *big.Int
|
||||
blobScalar *big.Int
|
||||
penaltyThreshold *big.Int
|
||||
penaltyFactor *big.Int
|
||||
}
|
||||
|
||||
func EstimateL1DataFeeForMessage(msg Message, baseFee *big.Int, config *params.ChainConfig, signer types.Signer, state StateDB, blockNumber *big.Int) (*big.Int, error) {
|
||||
func EstimateL1DataFeeForMessage(msg Message, baseFee *big.Int, config *params.ChainConfig, signer types.Signer, state StateDB, blockNumber *big.Int, blockTime uint64) (*big.Int, error) {
|
||||
if msg.IsL1MessageTx() {
|
||||
return big.NewInt(0), nil
|
||||
}
|
||||
|
|
@ -74,22 +79,7 @@ func EstimateL1DataFeeForMessage(msg Message, baseFee *big.Int, config *params.C
|
|||
return nil, err
|
||||
}
|
||||
|
||||
raw, err := tx.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gpoState := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
|
||||
|
||||
var l1DataFee *big.Int
|
||||
|
||||
if !config.IsCurie(blockNumber) {
|
||||
l1DataFee = calculateEncodedL1DataFee(raw, gpoState.overhead, gpoState.l1BaseFee, gpoState.scalar)
|
||||
} else {
|
||||
l1DataFee = calculateEncodedL1DataFeeCurie(raw, gpoState.l1BaseFee, gpoState.l1BlobBaseFee, gpoState.commitScalar, gpoState.blobScalar)
|
||||
}
|
||||
|
||||
return l1DataFee, nil
|
||||
return CalculateL1DataFee(tx, state, config, blockNumber, blockTime)
|
||||
}
|
||||
|
||||
// asUnsignedTx turns a Message into a types.Transaction
|
||||
|
|
@ -173,9 +163,58 @@ func readGPOStorageSlots(addr common.Address, state StateDB) gpoState {
|
|||
gpoState.l1BlobBaseFee = state.GetState(addr, rcfg.L1BlobBaseFeeSlot).Big()
|
||||
gpoState.commitScalar = state.GetState(addr, rcfg.CommitScalarSlot).Big()
|
||||
gpoState.blobScalar = state.GetState(addr, rcfg.BlobScalarSlot).Big()
|
||||
gpoState.penaltyThreshold = state.GetState(addr, rcfg.PenaltyThresholdSlot).Big()
|
||||
gpoState.penaltyFactor = state.GetState(addr, rcfg.PenaltyFactorSlot).Big()
|
||||
return gpoState
|
||||
}
|
||||
|
||||
// estimateTxCompressionRatio estimates the compression ratio for transaction data using da-codec
|
||||
// compression_ratio(tx) = size(tx) * PRECISION / size(zstd(tx))
|
||||
func estimateTxCompressionRatio(data []byte, blockNumber uint64, blockTime uint64, config *params.ChainConfig) (*big.Int, error) {
|
||||
if len(data) == 0 {
|
||||
return nil, fmt.Errorf("raw data is empty")
|
||||
}
|
||||
|
||||
// Compress data using da-codec
|
||||
compressed, err := encoding.CompressScrollBatchBytes(data, blockNumber, blockTime, config)
|
||||
if err != nil {
|
||||
log.Error("Batch compression failed, using 1.0 compression ratio", "error", err, "data size", len(data), "data", common.Bytes2Hex(data))
|
||||
return nil, fmt.Errorf("batch compression failed: %w", err)
|
||||
}
|
||||
|
||||
if len(compressed) == 0 {
|
||||
log.Error("Compressed data is empty, using 1.0 compression ratio", "data size", len(data), "data", common.Bytes2Hex(data))
|
||||
return nil, fmt.Errorf("compressed data is empty")
|
||||
}
|
||||
|
||||
// compression_ratio = size(tx) * PRECISION / size(zstd(tx))
|
||||
originalSize := new(big.Int).SetUint64(uint64(len(data)))
|
||||
compressedSize := new(big.Int).SetUint64(uint64(len(compressed)))
|
||||
|
||||
// Make sure compression ratio >= 1 by checking if compressed data is bigger or equal to original data
|
||||
// This behavior is consistent with DA Batch compression in codecv7 and later versions
|
||||
if len(compressed) >= len(data) {
|
||||
log.Debug("Compressed data is bigger or equal to the original data, using 1.0 compression ratio", "original size", len(data), "compressed size", len(compressed))
|
||||
return rcfg.Precision, nil
|
||||
}
|
||||
|
||||
ratio := new(big.Int).Mul(originalSize, rcfg.Precision)
|
||||
ratio.Div(ratio, compressedSize)
|
||||
|
||||
return ratio, nil
|
||||
}
|
||||
|
||||
// calculatePenalty computes the penalty multiplier based on compression ratio
|
||||
// penalty(tx) = compression_ratio(tx) >= penalty_threshold ? 1 * PRECISION : penalty_factor
|
||||
func calculatePenalty(compressionRatio, penaltyThreshold, penaltyFactor *big.Int) *big.Int {
|
||||
if compressionRatio.Cmp(penaltyThreshold) >= 0 {
|
||||
// No penalty
|
||||
return rcfg.Precision
|
||||
}
|
||||
// Apply penalty
|
||||
return penaltyFactor
|
||||
}
|
||||
|
||||
// calculateEncodedL1DataFee computes the L1 fee for an RLP-encoded tx
|
||||
func calculateEncodedL1DataFee(data []byte, overhead, l1BaseFee *big.Int, scalar *big.Int) *big.Int {
|
||||
l1GasUsed := calculateL1GasUsed(data, overhead)
|
||||
|
|
@ -200,6 +239,51 @@ func calculateEncodedL1DataFeeCurie(data []byte, l1BaseFee *big.Int, l1BlobBaseF
|
|||
return l1DataFee
|
||||
}
|
||||
|
||||
// calculateEncodedL1DataFeeFeynman computes the L1 fee for an RLP-encoded tx, post Feynman
|
||||
//
|
||||
// Post Feynman formula:
|
||||
// rollup_fee(tx) = (execScalar * l1BaseFee + blobScalar * l1BlobBaseFee) * size(tx) * penalty(tx) / PRECISION / PRECISION
|
||||
//
|
||||
// Where:
|
||||
// penalty(tx) = compression_ratio(tx) >= penalty_threshold ? 1 * PRECISION : penalty_factor
|
||||
//
|
||||
// compression_ratio(tx) = size(tx) * PRECISION / size(zstd(tx))
|
||||
// exec_scalar = compression_scalar * (commit_scalar + verification_scalar)
|
||||
// blob_scalar = compression_scalar * blob_scalar
|
||||
func calculateEncodedL1DataFeeFeynman(
|
||||
data []byte,
|
||||
l1BaseFee *big.Int,
|
||||
l1BlobBaseFee *big.Int,
|
||||
execScalar *big.Int,
|
||||
blobScalar *big.Int,
|
||||
penaltyThreshold *big.Int,
|
||||
penaltyFactor *big.Int,
|
||||
compressionRatio *big.Int,
|
||||
) *big.Int {
|
||||
// Calculate penalty multiplier
|
||||
penalty := calculatePenalty(compressionRatio, penaltyThreshold, penaltyFactor)
|
||||
|
||||
// Transaction size (RLP-encoded)
|
||||
txSize := big.NewInt(int64(len(data)))
|
||||
|
||||
// Compute gas components
|
||||
execGas := new(big.Int).Mul(execScalar, l1BaseFee)
|
||||
blobGas := new(big.Int).Mul(blobScalar, l1BlobBaseFee)
|
||||
|
||||
// fee per byte = execGas + blobGas
|
||||
feePerByte := new(big.Int).Add(execGas, blobGas)
|
||||
|
||||
// l1DataFee = feePerByte * txSize * penalty
|
||||
l1DataFee := new(big.Int).Mul(feePerByte, txSize)
|
||||
l1DataFee.Mul(l1DataFee, penalty)
|
||||
|
||||
// Divide by rcfg.Precision (once for scalars, once for penalty)
|
||||
l1DataFee.Div(l1DataFee, rcfg.Precision) // account for scalars
|
||||
l1DataFee.Div(l1DataFee, rcfg.Precision) // accounts for penalty
|
||||
|
||||
return l1DataFee
|
||||
}
|
||||
|
||||
// calculateL1GasUsed computes the L1 gas used based on the calldata and
|
||||
// constant sized overhead. The overhead can be decreased as the cost of the
|
||||
// batch submission goes down via contract optimizations. This will not overflow
|
||||
|
|
@ -233,7 +317,7 @@ func mulAndScale(x *big.Int, y *big.Int, precision *big.Int) *big.Int {
|
|||
return new(big.Int).Quo(z, precision)
|
||||
}
|
||||
|
||||
func CalculateL1DataFee(tx *types.Transaction, state StateDB, config *params.ChainConfig, blockNumber *big.Int) (*big.Int, error) {
|
||||
func CalculateL1DataFee(tx *types.Transaction, state StateDB, config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) (*big.Int, error) {
|
||||
if tx.IsL1MessageTx() {
|
||||
return big.NewInt(0), nil
|
||||
}
|
||||
|
|
@ -249,8 +333,26 @@ func CalculateL1DataFee(tx *types.Transaction, state StateDB, config *params.Cha
|
|||
|
||||
if !config.IsCurie(blockNumber) {
|
||||
l1DataFee = calculateEncodedL1DataFee(raw, gpoState.overhead, gpoState.l1BaseFee, gpoState.scalar)
|
||||
} else {
|
||||
} else if !config.IsFeynman(blockTime) {
|
||||
l1DataFee = calculateEncodedL1DataFeeCurie(raw, gpoState.l1BaseFee, gpoState.l1BlobBaseFee, gpoState.commitScalar, gpoState.blobScalar)
|
||||
} else {
|
||||
// Calculate compression ratio for Feynman
|
||||
compressionRatio, err := estimateTxCompressionRatio(raw, blockNumber.Uint64(), blockTime, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to estimate compression ratio: tx hash=%s: %w", tx.Hash().Hex(), err)
|
||||
}
|
||||
|
||||
// The contract slot for commitScalar is changed to execScalar in Feynman
|
||||
l1DataFee = calculateEncodedL1DataFeeFeynman(
|
||||
raw,
|
||||
gpoState.l1BaseFee,
|
||||
gpoState.l1BlobBaseFee,
|
||||
gpoState.commitScalar, // now represents execScalar
|
||||
gpoState.blobScalar,
|
||||
gpoState.penaltyThreshold,
|
||||
gpoState.penaltyFactor,
|
||||
compressionRatio,
|
||||
)
|
||||
}
|
||||
|
||||
// ensure l1DataFee fits into uint64 for circuit compatibility
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/scroll-tech/go-ethereum/params"
|
||||
)
|
||||
|
||||
func TestL1DataFeeBeforeCurie(t *testing.T) {
|
||||
|
|
@ -31,3 +33,109 @@ func TestL1DataFeeAfterCurie(t *testing.T) {
|
|||
actual := calculateEncodedL1DataFeeCurie(data, l1BaseFee, l1BlobBaseFee, commitScalar, blobScalar)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestL1DataFeeFeynman(t *testing.T) {
|
||||
l1BaseFee := new(big.Int).SetInt64(1_000_000_000)
|
||||
l1BlobBaseFee := new(big.Int).SetInt64(1_000_000_000)
|
||||
execScalar := new(big.Int).SetInt64(10)
|
||||
blobScalar := new(big.Int).SetInt64(20)
|
||||
penaltyThreshold := new(big.Int).SetInt64(6_000_000_000) // 6 * PRECISION
|
||||
penaltyFactor := new(big.Int).SetInt64(2_000_000_000) // 2 * PRECISION (200% penalty)
|
||||
|
||||
// Test case 1: No penalty (compression ratio >= threshold)
|
||||
t.Run("no penalty case", func(t *testing.T) {
|
||||
data := make([]byte, 100) // txSize = 100
|
||||
compressionRatio := new(big.Int).SetInt64(6_000_000_000) // exactly at threshold
|
||||
|
||||
// Since compression ratio >= penaltyThreshold, penalty = 1 * PRECISION
|
||||
// feePerByte = execScalar * l1BaseFee + blobScalar * l1BlobBaseFee = 10 * 1_000_000_000 + 20 * 1_000_000_000 = 30_000_000_000
|
||||
// l1DataFee = feePerByte * txSize * penalty / PRECISION / PRECISION
|
||||
// = 30_000_000_000 * 100 * 1_000_000_000 / 1_000_000_000 / 1_000_000_000 = 3000
|
||||
|
||||
expected := new(big.Int).SetInt64(3000)
|
||||
|
||||
actual := calculateEncodedL1DataFeeFeynman(
|
||||
data,
|
||||
l1BaseFee,
|
||||
l1BlobBaseFee,
|
||||
execScalar,
|
||||
blobScalar,
|
||||
penaltyThreshold,
|
||||
penaltyFactor,
|
||||
compressionRatio,
|
||||
)
|
||||
|
||||
assert.Equal(t, expected, actual)
|
||||
})
|
||||
|
||||
// Test case 2: With penalty (compression ratio < threshold)
|
||||
t.Run("with penalty case", func(t *testing.T) {
|
||||
data := make([]byte, 100) // txSize = 100
|
||||
compressionRatio := new(big.Int).SetInt64(5_000_000_000) // below threshold
|
||||
|
||||
// Since compression ratio < penaltyThreshold, penalty = penaltyFactor
|
||||
// feePerByte = execScalar * l1BaseFee + blobScalar * l1BlobBaseFee = 30_000_000_000
|
||||
// l1DataFee = feePerByte * txSize * penaltyFactor / PRECISION / PRECISION
|
||||
// = 30_000_000_000 * 100 * 2_000_000_000 / 1_000_000_000 / 1_000_000_000 = 6000
|
||||
|
||||
expected := new(big.Int).SetInt64(6000)
|
||||
|
||||
actual := calculateEncodedL1DataFeeFeynman(
|
||||
data,
|
||||
l1BaseFee,
|
||||
l1BlobBaseFee,
|
||||
execScalar,
|
||||
blobScalar,
|
||||
penaltyThreshold,
|
||||
penaltyFactor,
|
||||
compressionRatio,
|
||||
)
|
||||
|
||||
assert.Equal(t, expected, actual)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEstimateTxCompressionRatio(t *testing.T) {
|
||||
// Mock config that would select a specific codec version
|
||||
// Note: You'll need to adjust this based on your actual params.ChainConfig structure
|
||||
|
||||
t.Run("empty data", func(t *testing.T) {
|
||||
data := []byte{}
|
||||
// Should return 1.0 ratio (PRECISION)
|
||||
ratio, err := estimateTxCompressionRatio(data, 1000000, 1700000000, params.TestChainConfig)
|
||||
assert.Error(t, err, "raw data is empty")
|
||||
assert.Nil(t, ratio)
|
||||
// The exact value depends on rcfg.Precision, but should be the "1.0" equivalent
|
||||
})
|
||||
|
||||
t.Run("non-empty data", func(t *testing.T) {
|
||||
// Create some compressible data
|
||||
data := make([]byte, 1000)
|
||||
for i := range data {
|
||||
data[i] = byte(i % 10) // Create patterns for better compression
|
||||
}
|
||||
|
||||
ratio, err := estimateTxCompressionRatio(data, 1000000, 1700000000, params.TestChainConfig)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, ratio)
|
||||
// Should return a ratio > 1.0 (since compressed size < original size)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCalculatePenalty(t *testing.T) {
|
||||
precision := new(big.Int).SetInt64(1_000_000_000) // PRECISION
|
||||
penaltyThreshold := new(big.Int).SetInt64(6_000_000_000) // 6 * PRECISION
|
||||
penaltyFactor := new(big.Int).SetInt64(2_000_000_000) // 2 * PRECISION
|
||||
|
||||
t.Run("no penalty when ratio >= threshold", func(t *testing.T) {
|
||||
compressionRatio := new(big.Int).SetInt64(6_000_000_000) // exactly at threshold
|
||||
penalty := calculatePenalty(compressionRatio, penaltyThreshold, penaltyFactor)
|
||||
assert.Equal(t, precision, penalty)
|
||||
})
|
||||
|
||||
t.Run("penalty when ratio < threshold", func(t *testing.T) {
|
||||
compressionRatio := new(big.Int).SetInt64(5_000_000_000) // below threshold
|
||||
penalty := calculatePenalty(compressionRatio, penaltyThreshold, penaltyFactor)
|
||||
assert.Equal(t, penaltyFactor, penalty)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -239,7 +239,7 @@ func (env *TraceEnv) GetBlockTrace(block *types.Block) (*types.BlockTrace, error
|
|||
msg, _ := tx.AsMessage(env.signer, block.BaseFee())
|
||||
env.state.SetTxContext(tx.Hash(), i)
|
||||
vmenv := vm.NewEVM(env.blockCtx, core.NewEVMTxContext(msg), env.state, env.chainConfig, vm.Config{})
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, env.state, env.chainConfig, block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, env.state, env.chainConfig, block.Number(), block.Time())
|
||||
if err != nil {
|
||||
failed = err
|
||||
break
|
||||
|
|
@ -342,7 +342,7 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B
|
|||
state.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||
|
||||
// Computes the new state by applying the given message.
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, state, env.chainConfig, block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(tx, state, env.chainConfig, block.Number(), block.Time())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
|||
gaspool := new(core.GasPool)
|
||||
gaspool.AddGas(block.GasLimit())
|
||||
|
||||
l1DataFee, err := fees.CalculateL1DataFee(&ttx, statedb, config, block.Number())
|
||||
l1DataFee, err := fees.CalculateL1DataFee(&ttx, statedb, config, block.Number(), block.Time())
|
||||
if err != nil {
|
||||
return nil, nil, common.Hash{}, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue