mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 21:26:42 +00:00
feat(feynman): add new compression-aware rollup fee formula (#1196)
* Change l1DataFee to rollupFee for Feynman * Update CommitScalarSlot to ExecScalarSlot * Rename l1DataFee to rollupFee * Scale compression ratio to match scalars precision * Use l1DataFee and commitScalar instead of rollupFee and execScalar * Use blocktime not blocknumber * Add unit test * Clarify test comment * feat(feynman): upgrade gas oracle predeploy * address comments * revert renaming CalculateL1DataFee to CalculateRollupFee * simplify EstimateL1DataFeeForMessage * address comments * add a comment based on pr reviews * update formula * tweaks * tweak comments * Estimate compression ratio at rollupFee for Feynman (#1197) * Estimate compression ratio * Update rollup/fees/rollup_fee.go Co-authored-by: Péter Garamvölgyi <peter@scroll.io> * Check compressed size smaller and remove unnecessary checks/changes * goimports locally run * rollback format changes * update da-codec's zstd function * apply zstd * tweaks * tweak unit test * make sure compression ratio >= 1 * nit --------- Co-authored-by: Péter Garamvölgyi <peter@scroll.io> Co-authored-by: colinlyguo <colinlyguo@scroll.io> Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com> * refactoring * remove incorrect merge artifact * error handling * update da-codec commit * update da-codec commit --------- Co-authored-by: Péter Garamvölgyi <peter@scroll.io> Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com> Co-authored-by: colinlyguo <colinlyguo@scroll.io>
This commit is contained in:
parent
a67863c655
commit
c0d89415da
23 changed files with 282 additions and 67 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})
|
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
||||||
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
signer := types.MakeSigner(b.blockchain.Config(), head.Number, head.Time)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
snapshot := statedb.Snapshot()
|
snapshot := statedb.Snapshot()
|
||||||
evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
|
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 {
|
if err != nil {
|
||||||
log.Info("rejected tx due to fees.CalculateL1DataFee", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
|
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()})
|
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||||
}
|
}
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
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 {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
header = block.Header()
|
header = block.Header()
|
||||||
blockHash = block.Hash()
|
blockHash = block.Hash()
|
||||||
blockNumber = block.Number()
|
blockNumber = block.Number()
|
||||||
|
blockTime = block.Time()
|
||||||
allLogs []*types.Log
|
allLogs []*types.Log
|
||||||
gp = new(GasPool).AddGas(block.GasLimit())
|
gp = new(GasPool).AddGas(block.GasLimit())
|
||||||
)
|
)
|
||||||
|
|
@ -110,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)
|
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
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 {
|
if err != nil {
|
||||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +126,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
return receipts, allLogs, *usedGas, nil
|
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) {
|
defer func(t0 time.Time) {
|
||||||
applyTransactionTimer.Update(time.Since(t0))
|
applyTransactionTimer.Update(time.Since(t0))
|
||||||
}(time.Now())
|
}(time.Now())
|
||||||
|
|
@ -134,7 +135,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
|
||||||
txContext := NewEVMTxContext(msg)
|
txContext := NewEVMTxContext(msg)
|
||||||
evm.Reset(txContext, statedb)
|
evm.Reset(txContext, statedb)
|
||||||
|
|
||||||
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, config, blockNumber)
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb, config, blockNumber, blockTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -206,7 +207,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
||||||
// Create a new context to be used in the EVM environment
|
// Create a new context to be used in the EVM environment
|
||||||
blockContext := NewEVMBlockContext(header, bc, config, author)
|
blockContext := NewEVMBlockContext(header, bc, config, author)
|
||||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
|
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
|
// 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
|
// If the new transaction is accepted into the list, the lists' cost and gas
|
||||||
// thresholds are also potentially updated.
|
// 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
|
// If there's an older better transaction, abort
|
||||||
old := l.txs.Get(tx.Nonce())
|
old := l.txs.Get(tx.Nonce())
|
||||||
if old != nil {
|
if old != nil {
|
||||||
|
|
@ -310,7 +310,7 @@ func (l *txList) Add(tx *types.Transaction, state *state.StateDB, priceBump uint
|
||||||
l1DataFee := big.NewInt(0)
|
l1DataFee := big.NewInt(0)
|
||||||
if state != nil && chainconfig != nil {
|
if state != nil && chainconfig != nil {
|
||||||
var err error
|
var err error
|
||||||
l1DataFee, err = fees.CalculateL1DataFee(tx, state, chainconfig, blockNumber)
|
l1DataFee, err = fees.CalculateL1DataFee(tx, state, chainconfig, blockNumber, blockTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to calculate L1 data fee", "err", err, "tx", tx)
|
log.Error("Failed to calculate L1 data fee", "err", err, "tx", tx)
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ func TestStrictTxListAdd(t *testing.T) {
|
||||||
// Insert the transactions in a random order
|
// Insert the transactions in a random order
|
||||||
list := newTxList(true)
|
list := newTxList(true)
|
||||||
for _, v := range rand.Perm(len(txs)) {
|
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
|
// Verify internal state
|
||||||
if len(list.txs.items) != len(txs) {
|
if len(list.txs.items) != len(txs) {
|
||||||
|
|
@ -65,7 +65,7 @@ func BenchmarkTxListAdd(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
list := newTxList(true)
|
list := newTxList(true)
|
||||||
for _, v := range rand.Perm(len(txs)) {
|
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)
|
list.Filter(priceLimit, DefaultTxPoolConfig.PriceBump)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -301,6 +301,7 @@ type TxPool struct {
|
||||||
|
|
||||||
currentState *state.StateDB // Current state in the blockchain head
|
currentState *state.StateDB // Current state in the blockchain head
|
||||||
currentHead *big.Int // Current blockchain head
|
currentHead *big.Int // Current blockchain head
|
||||||
|
currentTime uint64 // Current blockchain head time
|
||||||
pendingNonces *txNoncer // Pending state tracking virtual nonces
|
pendingNonces *txNoncer // Pending state tracking virtual nonces
|
||||||
currentMaxGas uint64 // Current gas limit for transaction caps
|
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.
|
// 2. If FeeVault is enabled, perform an additional check for L1 data fees.
|
||||||
if pool.chainconfig.Scroll.FeeVaultEnabled() {
|
if pool.chainconfig.Scroll.FeeVaultEnabled() {
|
||||||
// Get L1 data fee in current state
|
// 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 {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to calculate L1 data fee, err: %w", err)
|
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
|
from, _ := types.Sender(pool.signer, tx) // already validated
|
||||||
if list := pool.pending[from]; list != nil && list.Overlaps(tx) {
|
if list := pool.pending[from]; list != nil && list.Overlaps(tx) {
|
||||||
// Nonce already pending, check if required price bump is met
|
// 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 {
|
if !inserted {
|
||||||
log.Debug("Discarding underpriced pending transaction", "hash", hash.Hex(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
log.Debug("Discarding underpriced pending transaction", "hash", hash.Hex(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
||||||
pendingDiscardMeter.Mark(1)
|
pendingDiscardMeter.Mark(1)
|
||||||
|
|
@ -1001,7 +1002,7 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction, local boo
|
||||||
pool.queue[from] = newTxList(false)
|
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 {
|
if !inserted {
|
||||||
// An older transaction was better, discard this
|
// An older transaction was better, discard this
|
||||||
log.Debug("Discarding underpriced queued transaction", "hash", hash.Hex(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
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
|
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 {
|
if !inserted {
|
||||||
// An older transaction was better, discard this
|
// An older transaction was better, discard this
|
||||||
log.Debug("Discarding underpriced pending transaction", "hash", hash.Hex(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
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
|
// Update current head
|
||||||
pool.currentHead = next
|
pool.currentHead = next
|
||||||
|
pool.currentTime = newHead.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// promoteExecutables moves transactions that have become processable from the
|
// 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() {
|
if pool.chainconfig.Scroll.FeeVaultEnabled() {
|
||||||
// recheck L1 data fee, as the oracle price may have changed
|
// 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 {
|
if err != nil {
|
||||||
log.Error("Failed to calculate L1 data fee", "err", err, "tx", tx)
|
log.Error("Failed to calculate L1 data fee", "err", err, "tx", tx)
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -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
|
// Not yet the searched for transaction, execute on top of the current state
|
||||||
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
|
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
|
||||||
statedb.SetTxContext(tx.Hash(), idx)
|
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 {
|
if err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, err
|
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(),
|
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 {
|
if err != nil {
|
||||||
// though it's not a "tracing error", we still need to put it here
|
// though it's not a "tracing error", we still need to put it here
|
||||||
task.results[i] = &txTraceResult{Error: err.Error()}
|
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)
|
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 {
|
if err != nil {
|
||||||
log.Warn("Tracing intermediate roots did not complete due to fees.CalculateL1DataFee", "txindex", i, "txhash", tx.Hash(), "err", err)
|
log.Warn("Tracing intermediate roots did not complete due to fees.CalculateL1DataFee", "txindex", i, "txhash", tx.Hash(), "err", err)
|
||||||
return nil, 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(),
|
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 {
|
if err != nil {
|
||||||
// though it's not a "tracing error", we still need to put it here
|
// though it's not a "tracing error", we still need to put it here
|
||||||
results[task.index] = &txTraceResult{
|
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())
|
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
|
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 {
|
if err != nil {
|
||||||
failed = err
|
failed = err
|
||||||
break
|
break
|
||||||
|
|
@ -804,7 +804,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
// Execute the transaction and flush any traces to disk
|
// Execute the transaction and flush any traces to disk
|
||||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
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 {
|
if err == nil {
|
||||||
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee)
|
_, 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),
|
TxIndex: int(index),
|
||||||
TxHash: hash,
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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())
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
||||||
return msg, context, statedb, nil
|
return msg, context, statedb, nil
|
||||||
}
|
}
|
||||||
vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
|
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 {
|
if err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, err
|
return nil, vm.BlockContext{}, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to calculate l1DataFee: %v", err)
|
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})
|
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||||
snap := statedb.Snapshot()
|
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 {
|
if err != nil {
|
||||||
b.Fatalf("failed to calculate l1DataFee: %v", err)
|
b.Fatalf("failed to calculate l1DataFee: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -381,7 +381,7 @@ func TestZeroValueToNotExitCall(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("failed to calculate l1DataFee: %v", err)
|
t.Fatalf("failed to calculate l1DataFee: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
snap := statedb.Snapshot()
|
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 {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -51,7 +51,7 @@ require (
|
||||||
github.com/prometheus/tsdb v0.7.1
|
github.com/prometheus/tsdb v0.7.1
|
||||||
github.com/rjeczalik/notify v0.9.1
|
github.com/rjeczalik/notify v0.9.1
|
||||||
github.com/rs/cors v1.7.0
|
github.com/rs/cors v1.7.0
|
||||||
github.com/scroll-tech/da-codec v0.1.3-0.20250519114140-bfa7133d4ad1
|
github.com/scroll-tech/da-codec v0.1.3-0.20250626091118-58b899494da6
|
||||||
github.com/scroll-tech/zktrie v0.8.4
|
github.com/scroll-tech/zktrie v0.8.4
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
github.com/sourcegraph/conc v0.3.0
|
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 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/scroll-tech/da-codec v0.1.3-0.20250519114140-bfa7133d4ad1 h1:6aKqJSal+QVdB5HMWMs0JTbAIZ6/iAHJx9qizz0w9dU=
|
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.20250519114140-bfa7133d4ad1/go.mod h1:yhTS9OVC0xQGhg7DN5iV5KZJvnSIlFWAxDdp+6jxQtY=
|
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 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE=
|
||||||
github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
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=
|
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)
|
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) {
|
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
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
signer := types.MakeSigner(b.ChainConfig(), header.Number, header.Time)
|
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 {
|
if err != nil {
|
||||||
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
|
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{})
|
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
signer := types.MakeSigner(config, header.Number, header.Time)
|
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)
|
result, _ := core.ApplyMessage(vmenv, msg, gp, l1DataFee)
|
||||||
res = append(res, result.Return()...)
|
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})
|
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true})
|
||||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
signer := types.MakeSigner(config, header.Number, header.Time)
|
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)
|
result, _ := core.ApplyMessage(vmenv, msg, gp, l1DataFee)
|
||||||
if state.Error() == nil {
|
if state.Error() == nil {
|
||||||
res = append(res, result.Return()...)
|
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
|
// Not yet the searched for transaction, execute on top of the current state
|
||||||
vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{})
|
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 {
|
if err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
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})
|
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
|
||||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
signer := types.MakeSigner(config, header.Number, header.Time)
|
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)
|
result, _ := core.ApplyMessage(vmenv, msg, gp, l1DataFee)
|
||||||
res = append(res, result.Return()...)
|
res = append(res, result.Return()...)
|
||||||
if st.Error() != nil {
|
if st.Error() != nil {
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ type TxPool struct {
|
||||||
shanghai bool // Fork indicator whether we are in the shanghai stage.
|
shanghai bool // Fork indicator whether we are in the shanghai stage.
|
||||||
|
|
||||||
currentHead *big.Int // Current blockchain head
|
currentHead *big.Int // Current blockchain head
|
||||||
|
currentTime uint64 // Current blockchain head time
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxRelayBackend provides an interface to the mechanism that forwards transacions
|
// 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.shanghai = pool.config.IsShanghai(next)
|
||||||
|
|
||||||
pool.currentHead = next
|
pool.currentHead = next
|
||||||
|
pool.currentTime = head.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop stops the light transaction pool
|
// 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.
|
// 2. If FeeVault is enabled, perform an additional check for L1 data fees.
|
||||||
if pool.config.Scroll.FeeVaultEnabled() {
|
if pool.config.Scroll.FeeVaultEnabled() {
|
||||||
// Get L1 data fee in current state
|
// 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 {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to calculate L1 data fee, err: %w", err)
|
return fmt.Errorf("failed to calculate L1 data fee, err: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,17 @@ package fees
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
"github.com/scroll-tech/da-codec/encoding"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
"github.com/scroll-tech/go-ethereum/core/types"
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
"github.com/scroll-tech/go-ethereum/crypto"
|
"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/params"
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
||||||
)
|
)
|
||||||
|
|
@ -54,15 +57,17 @@ type StateDB interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type gpoState struct {
|
type gpoState struct {
|
||||||
l1BaseFee *big.Int
|
l1BaseFee *big.Int
|
||||||
overhead *big.Int
|
overhead *big.Int
|
||||||
scalar *big.Int
|
scalar *big.Int
|
||||||
l1BlobBaseFee *big.Int
|
l1BlobBaseFee *big.Int
|
||||||
commitScalar *big.Int
|
commitScalar *big.Int
|
||||||
blobScalar *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() {
|
if msg.IsL1MessageTx() {
|
||||||
return big.NewInt(0), nil
|
return big.NewInt(0), nil
|
||||||
}
|
}
|
||||||
|
|
@ -74,22 +79,7 @@ func EstimateL1DataFeeForMessage(msg Message, baseFee *big.Int, config *params.C
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
raw, err := tx.MarshalBinary()
|
return CalculateL1DataFee(tx, state, config, blockNumber, blockTime)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// asUnsignedTx turns a Message into a types.Transaction
|
// 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.l1BlobBaseFee = state.GetState(addr, rcfg.L1BlobBaseFeeSlot).Big()
|
||||||
gpoState.commitScalar = state.GetState(addr, rcfg.CommitScalarSlot).Big()
|
gpoState.commitScalar = state.GetState(addr, rcfg.CommitScalarSlot).Big()
|
||||||
gpoState.blobScalar = state.GetState(addr, rcfg.BlobScalarSlot).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
|
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
|
// calculateEncodedL1DataFee computes the L1 fee for an RLP-encoded tx
|
||||||
func calculateEncodedL1DataFee(data []byte, overhead, l1BaseFee *big.Int, scalar *big.Int) *big.Int {
|
func calculateEncodedL1DataFee(data []byte, overhead, l1BaseFee *big.Int, scalar *big.Int) *big.Int {
|
||||||
l1GasUsed := calculateL1GasUsed(data, overhead)
|
l1GasUsed := calculateL1GasUsed(data, overhead)
|
||||||
|
|
@ -200,6 +239,51 @@ func calculateEncodedL1DataFeeCurie(data []byte, l1BaseFee *big.Int, l1BlobBaseF
|
||||||
return l1DataFee
|
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
|
// calculateL1GasUsed computes the L1 gas used based on the calldata and
|
||||||
// constant sized overhead. The overhead can be decreased as the cost of the
|
// constant sized overhead. The overhead can be decreased as the cost of the
|
||||||
// batch submission goes down via contract optimizations. This will not overflow
|
// 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)
|
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() {
|
if tx.IsL1MessageTx() {
|
||||||
return big.NewInt(0), nil
|
return big.NewInt(0), nil
|
||||||
}
|
}
|
||||||
|
|
@ -249,8 +333,26 @@ func CalculateL1DataFee(tx *types.Transaction, state StateDB, config *params.Cha
|
||||||
|
|
||||||
if !config.IsCurie(blockNumber) {
|
if !config.IsCurie(blockNumber) {
|
||||||
l1DataFee = calculateEncodedL1DataFee(raw, gpoState.overhead, gpoState.l1BaseFee, gpoState.scalar)
|
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)
|
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
|
// ensure l1DataFee fits into uint64 for circuit compatibility
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestL1DataFeeBeforeCurie(t *testing.T) {
|
func TestL1DataFeeBeforeCurie(t *testing.T) {
|
||||||
|
|
@ -31,3 +33,109 @@ func TestL1DataFeeAfterCurie(t *testing.T) {
|
||||||
actual := calculateEncodedL1DataFeeCurie(data, l1BaseFee, l1BlobBaseFee, commitScalar, blobScalar)
|
actual := calculateEncodedL1DataFeeCurie(data, l1BaseFee, l1BlobBaseFee, commitScalar, blobScalar)
|
||||||
assert.Equal(t, expected, actual)
|
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ func (env *TraceEnv) GetBlockTrace(block *types.Block) (*types.BlockTrace, error
|
||||||
msg, _ := tx.AsMessage(env.signer, block.BaseFee())
|
msg, _ := tx.AsMessage(env.signer, block.BaseFee())
|
||||||
env.state.SetTxContext(tx.Hash(), i)
|
env.state.SetTxContext(tx.Hash(), i)
|
||||||
vmenv := vm.NewEVM(env.blockCtx, core.NewEVMTxContext(msg), env.state, env.chainConfig, vm.Config{})
|
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 {
|
if err != nil {
|
||||||
failed = err
|
failed = err
|
||||||
break
|
break
|
||||||
|
|
@ -342,7 +342,7 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B
|
||||||
state.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
state.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||||
|
|
||||||
// Computes the new state by applying the given message.
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
gaspool := new(core.GasPool)
|
gaspool := new(core.GasPool)
|
||||||
gaspool.AddGas(block.GasLimit())
|
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 {
|
if err != nil {
|
||||||
return nil, nil, common.Hash{}, err
|
return nil, nil, common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue