mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
feat: update l1fee calculation (#351)
This commit is contained in:
parent
4e0daeb300
commit
f055f50f9d
25 changed files with 341 additions and 198 deletions
|
|
@ -42,6 +42,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/event"
|
"github.com/scroll-tech/go-ethereum/event"
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"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/fees"
|
||||||
"github.com/scroll-tech/go-ethereum/rpc"
|
"github.com/scroll-tech/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -638,8 +639,13 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
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)
|
||||||
|
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, head.BaseFee, b.blockchain.Config().ChainID, signer, stateDB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb()
|
return core.NewStateTransition(vmEnv, msg, gasPool, l1DataFee).TransitionDb()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTransaction updates the pending block to include the given transaction.
|
// SendTransaction updates the pending block to include the given transaction.
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"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/rlp"
|
"github.com/scroll-tech/go-ethereum/rlp"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
"github.com/scroll-tech/go-ethereum/trie"
|
"github.com/scroll-tech/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -166,8 +167,15 @@ 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)
|
||||||
|
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()})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// (ret []byte, usedGas uint64, failed bool, err error)
|
// (ret []byte, usedGas uint64, failed bool, err error)
|
||||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
msgResult, err := core.ApplyMessage(evm, msg, gaspool, l1DataFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
|
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/consensus"
|
"github.com/scroll-tech/go-ethereum/consensus"
|
||||||
|
|
@ -24,6 +25,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/core/types"
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
"github.com/scroll-tech/go-ethereum/core/vm"
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
)
|
)
|
||||||
|
|
||||||
// statePrefetcher is a basic Prefetcher, which blindly executes a block on top
|
// statePrefetcher is a basic Prefetcher, which blindly executes a block on top
|
||||||
|
|
@ -68,7 +70,13 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||||
return // Also invalid block, bail out
|
return // Also invalid block, bail out
|
||||||
}
|
}
|
||||||
statedb.Prepare(tx.Hash(), i)
|
statedb.Prepare(tx.Hash(), i)
|
||||||
if err := precacheTransaction(msg, p.config, gaspool, statedb, header, evm); err != nil {
|
|
||||||
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = precacheTransaction(msg, p.config, gaspool, statedb, header, evm, l1DataFee); err != nil {
|
||||||
return // Ugh, something went horribly wrong, bail out
|
return // Ugh, something went horribly wrong, bail out
|
||||||
}
|
}
|
||||||
// If we're pre-byzantium, pre-load trie nodes for the intermediate root
|
// If we're pre-byzantium, pre-load trie nodes for the intermediate root
|
||||||
|
|
@ -85,10 +93,10 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||||
// precacheTransaction attempts to apply a transaction to the given state database
|
// precacheTransaction attempts to apply a transaction to the given state database
|
||||||
// and uses the input parameters for its environment. The goal is not to execute
|
// and uses the input parameters for its environment. The goal is not to execute
|
||||||
// the transaction successfully, rather to warm up touched data slots.
|
// the transaction successfully, rather to warm up touched data slots.
|
||||||
func precacheTransaction(msg types.Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
|
func precacheTransaction(msg types.Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM, l1DataFee *big.Int) error {
|
||||||
// Update the evm with the new transaction context.
|
// Update the evm with the new transaction context.
|
||||||
evm.Reset(NewEVMTxContext(msg), statedb)
|
evm.Reset(NewEVMTxContext(msg), statedb)
|
||||||
// Add addresses to access list if applicable
|
// Add addresses to access list if applicable
|
||||||
_, err := ApplyMessage(evm, msg, gaspool)
|
_, err := ApplyMessage(evm, msg, gaspool, l1DataFee)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/core/vm"
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
"github.com/scroll-tech/go-ethereum/crypto"
|
"github.com/scroll-tech/go-ethereum/crypto"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StateProcessor is a basic Processor, which takes care of transitioning
|
// StateProcessor is a basic Processor, which takes care of transitioning
|
||||||
|
|
@ -97,8 +98,13 @@ 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)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Apply the transaction to the current state (included in the env).
|
// Apply the transaction to the current state (included in the env).
|
||||||
result, err := ApplyMessage(evm, msg, gp)
|
result, err := ApplyMessage(evm, msg, gp, l1DataFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +145,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
|
||||||
receipt.BlockHash = blockHash
|
receipt.BlockHash = blockHash
|
||||||
receipt.BlockNumber = blockNumber
|
receipt.BlockNumber = blockNumber
|
||||||
receipt.TransactionIndex = uint(statedb.TxIndex())
|
receipt.TransactionIndex = uint(statedb.TxIndex())
|
||||||
receipt.L1Fee = result.L1Fee
|
receipt.L1Fee = result.L1DataFee
|
||||||
return receipt, err
|
return receipt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/crypto/codehash"
|
"github.com/scroll-tech/go-ethereum/crypto/codehash"
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"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/fees"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var emptyKeccakCodeHash = codehash.EmptyKeccakCodeHash
|
var emptyKeccakCodeHash = codehash.EmptyKeccakCodeHash
|
||||||
|
|
@ -63,8 +62,7 @@ type StateTransition struct {
|
||||||
state vm.StateDB
|
state vm.StateDB
|
||||||
evm *vm.EVM
|
evm *vm.EVM
|
||||||
|
|
||||||
// l1 rollup fee
|
l1DataFee *big.Int
|
||||||
l1Fee *big.Int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message represents a message sent to a contract.
|
// Message represents a message sent to a contract.
|
||||||
|
|
@ -88,7 +86,7 @@ type Message interface {
|
||||||
// ExecutionResult includes all output after executing given evm
|
// ExecutionResult includes all output after executing given evm
|
||||||
// message no matter the execution itself is successful or not.
|
// message no matter the execution itself is successful or not.
|
||||||
type ExecutionResult struct {
|
type ExecutionResult struct {
|
||||||
L1Fee *big.Int
|
L1DataFee *big.Int
|
||||||
UsedGas uint64 // Total used gas but include the refunded gas
|
UsedGas uint64 // Total used gas but include the refunded gas
|
||||||
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
|
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
|
||||||
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
|
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
|
||||||
|
|
@ -181,12 +179,7 @@ func toWordSize(size uint64) uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateTransition initialises and returns a new state transition object.
|
// NewStateTransition initialises and returns a new state transition object.
|
||||||
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
|
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool, l1DataFee *big.Int) *StateTransition {
|
||||||
l1Fee := new(big.Int)
|
|
||||||
if evm.ChainConfig().Scroll.FeeVaultEnabled() {
|
|
||||||
l1Fee, _ = fees.CalculateL1MsgFee(msg, evm.StateDB)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &StateTransition{
|
return &StateTransition{
|
||||||
gp: gp,
|
gp: gp,
|
||||||
evm: evm,
|
evm: evm,
|
||||||
|
|
@ -197,7 +190,7 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
||||||
value: msg.Value(),
|
value: msg.Value(),
|
||||||
data: msg.Data(),
|
data: msg.Data(),
|
||||||
state: evm.StateDB,
|
state: evm.StateDB,
|
||||||
l1Fee: l1Fee,
|
l1DataFee: l1DataFee,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,8 +201,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
||||||
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
||||||
// indicates a core error meaning that the message would always fail for that particular
|
// indicates a core error meaning that the message would always fail for that particular
|
||||||
// state and would never be accepted within a block.
|
// state and would never be accepted within a block.
|
||||||
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
|
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool, l1DataFee *big.Int) (*ExecutionResult, error) {
|
||||||
return NewStateTransition(evm, msg, gp).TransitionDb()
|
return NewStateTransition(evm, msg, gp, l1DataFee).TransitionDb()
|
||||||
}
|
}
|
||||||
|
|
||||||
// to returns the recipient of the message.
|
// to returns the recipient of the message.
|
||||||
|
|
@ -225,9 +218,12 @@ func (st *StateTransition) buyGas() error {
|
||||||
mgval = mgval.Mul(mgval, st.gasPrice)
|
mgval = mgval.Mul(mgval, st.gasPrice)
|
||||||
|
|
||||||
if st.evm.ChainConfig().Scroll.FeeVaultEnabled() {
|
if st.evm.ChainConfig().Scroll.FeeVaultEnabled() {
|
||||||
// always add l1fee, because all tx are L2-to-L1 ATM
|
// should be fine to add st.l1DataFee even without `L1MessageTx` check, since L1MessageTx will come with 0 l1DataFee,
|
||||||
log.Debug("Adding L1 fee", "l1_fee", st.l1Fee)
|
// but double check to make sure
|
||||||
mgval = mgval.Add(mgval, st.l1Fee)
|
if !st.msg.IsL1MessageTx() {
|
||||||
|
log.Debug("Adding L1DataFee", "l1DataFee", st.l1DataFee)
|
||||||
|
mgval = mgval.Add(mgval, st.l1DataFee)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
balanceCheck := mgval
|
balanceCheck := mgval
|
||||||
|
|
@ -236,8 +232,11 @@ func (st *StateTransition) buyGas() error {
|
||||||
balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap)
|
balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap)
|
||||||
balanceCheck.Add(balanceCheck, st.value)
|
balanceCheck.Add(balanceCheck, st.value)
|
||||||
if st.evm.ChainConfig().Scroll.FeeVaultEnabled() {
|
if st.evm.ChainConfig().Scroll.FeeVaultEnabled() {
|
||||||
// always add l1fee, because all tx are L2-to-L1 ATM
|
// should be fine to add st.l1DataFee even without `L1MessageTx` check, since L1MessageTx will come with 0 l1DataFee,
|
||||||
balanceCheck.Add(balanceCheck, st.l1Fee)
|
// but double check to make sure
|
||||||
|
if !st.msg.IsL1MessageTx() {
|
||||||
|
balanceCheck.Add(balanceCheck, st.l1DataFee)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
|
if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
|
||||||
|
|
@ -391,7 +390,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
// no refunds for l1 messages
|
// no refunds for l1 messages
|
||||||
if st.msg.IsL1MessageTx() {
|
if st.msg.IsL1MessageTx() {
|
||||||
return &ExecutionResult{
|
return &ExecutionResult{
|
||||||
L1Fee: big.NewInt(0),
|
L1DataFee: big.NewInt(0),
|
||||||
UsedGas: st.gasUsed(),
|
UsedGas: st.gasUsed(),
|
||||||
Err: vmerr,
|
Err: vmerr,
|
||||||
ReturnData: ret,
|
ReturnData: ret,
|
||||||
|
|
@ -416,17 +415,17 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
|
|
||||||
if st.evm.ChainConfig().Scroll.FeeVaultEnabled() {
|
if st.evm.ChainConfig().Scroll.FeeVaultEnabled() {
|
||||||
// The L2 Fee is the same as the fee that is charged in the normal geth
|
// The L2 Fee is the same as the fee that is charged in the normal geth
|
||||||
// codepath. Add the L1 fee to the L2 fee for the total fee that is sent
|
// codepath. Add the L1DataFee to the L2 fee for the total fee that is sent
|
||||||
// to the sequencer.
|
// to the sequencer.
|
||||||
l2Fee := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)
|
l2Fee := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)
|
||||||
fee := new(big.Int).Add(st.l1Fee, l2Fee)
|
fee := new(big.Int).Add(st.l1DataFee, l2Fee)
|
||||||
st.state.AddBalance(st.evm.FeeRecipient(), fee)
|
st.state.AddBalance(st.evm.FeeRecipient(), fee)
|
||||||
} else {
|
} else {
|
||||||
st.state.AddBalance(st.evm.FeeRecipient(), new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip))
|
st.state.AddBalance(st.evm.FeeRecipient(), new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ExecutionResult{
|
return &ExecutionResult{
|
||||||
L1Fee: st.l1Fee,
|
L1DataFee: st.l1DataFee,
|
||||||
UsedGas: st.gasUsed(),
|
UsedGas: st.gasUsed(),
|
||||||
Err: vmerr,
|
Err: vmerr,
|
||||||
ReturnData: ret,
|
ReturnData: ret,
|
||||||
|
|
|
||||||
|
|
@ -695,7 +695,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||||
|
|
||||||
if pool.chainconfig.Scroll.FeeVaultEnabled() {
|
if pool.chainconfig.Scroll.FeeVaultEnabled() {
|
||||||
if err := fees.VerifyFee(pool.signer, tx, pool.currentState); err != nil {
|
if err := fees.VerifyFee(pool.signer, tx, pool.currentState); err != nil {
|
||||||
log.Trace("Discarding insufficient l1fee transaction", "hash", hash, "err", err)
|
log.Trace("Discarding insufficient l1DataFee transaction", "hash", hash, "err", err)
|
||||||
invalidTxMeter.Mark(1)
|
invalidTxMeter.Mark(1)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,32 +43,32 @@ var (
|
||||||
// sideeffects used during testing.
|
// sideeffects used during testing.
|
||||||
testTxPoolConfig TxPoolConfig
|
testTxPoolConfig TxPoolConfig
|
||||||
|
|
||||||
// noL1feeConfig is a chain config without L1fee enabled.
|
// noL1DataFeeConfig is a chain config without L1DataFee enabled.
|
||||||
noL1feeConfig *params.ChainConfig
|
noL1DataFeeConfig *params.ChainConfig
|
||||||
|
|
||||||
// eip1559Config is a chain config with EIP-1559 enabled at block 0.
|
// eip1559Config is a chain config with EIP-1559 enabled at block 0.
|
||||||
eip1559Config *params.ChainConfig
|
eip1559Config *params.ChainConfig
|
||||||
|
|
||||||
// eip1559NoL1feeConfig is a chain config with EIP-1559 enabled at block 0 but not enabling L1fee.
|
// eip1559NoL1DataFeeConfig is a chain config with EIP-1559 enabled at block 0 but not enabling L1DataFee.
|
||||||
eip1559NoL1feeConfig *params.ChainConfig
|
eip1559NoL1DataFeeConfig *params.ChainConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
testTxPoolConfig = DefaultTxPoolConfig
|
testTxPoolConfig = DefaultTxPoolConfig
|
||||||
testTxPoolConfig.Journal = ""
|
testTxPoolConfig.Journal = ""
|
||||||
|
|
||||||
cpy0 := *params.TestNoL1feeChainConfig
|
cpy0 := *params.TestNoL1DataFeeChainConfig
|
||||||
noL1feeConfig = &cpy0
|
noL1DataFeeConfig = &cpy0
|
||||||
|
|
||||||
cpy1 := *params.TestChainConfig
|
cpy1 := *params.TestChainConfig
|
||||||
eip1559Config = &cpy1
|
eip1559Config = &cpy1
|
||||||
eip1559Config.BerlinBlock = common.Big0
|
eip1559Config.BerlinBlock = common.Big0
|
||||||
eip1559Config.LondonBlock = common.Big0
|
eip1559Config.LondonBlock = common.Big0
|
||||||
|
|
||||||
cpy2 := *params.TestNoL1feeChainConfig
|
cpy2 := *params.TestNoL1DataFeeChainConfig
|
||||||
eip1559NoL1feeConfig = &cpy2
|
eip1559NoL1DataFeeConfig = &cpy2
|
||||||
eip1559NoL1feeConfig.BerlinBlock = common.Big0
|
eip1559NoL1DataFeeConfig.BerlinBlock = common.Big0
|
||||||
eip1559NoL1feeConfig.LondonBlock = common.Big0
|
eip1559NoL1DataFeeConfig.LondonBlock = common.Big0
|
||||||
}
|
}
|
||||||
|
|
||||||
type testBlockChain struct {
|
type testBlockChain struct {
|
||||||
|
|
@ -290,7 +290,7 @@ func testSetNonce(pool *TxPool, addr common.Address, nonce uint64) {
|
||||||
func TestInvalidTransactions(t *testing.T) {
|
func TestInvalidTransactions(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
tx := transaction(0, 100, key)
|
tx := transaction(0, 100, key)
|
||||||
|
|
@ -327,7 +327,7 @@ func TestInvalidTransactions(t *testing.T) {
|
||||||
func TestTransactionQueue(t *testing.T) {
|
func TestTransactionQueue(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
tx := transaction(0, 100, key)
|
tx := transaction(0, 100, key)
|
||||||
|
|
@ -358,7 +358,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||||
func TestTransactionQueue2(t *testing.T) {
|
func TestTransactionQueue2(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
tx1 := transaction(0, 100, key)
|
tx1 := transaction(0, 100, key)
|
||||||
|
|
@ -384,7 +384,7 @@ func TestTransactionQueue2(t *testing.T) {
|
||||||
func TestTransactionNegativeValue(t *testing.T) {
|
func TestTransactionNegativeValue(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key)
|
tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key)
|
||||||
|
|
@ -398,7 +398,7 @@ func TestTransactionNegativeValue(t *testing.T) {
|
||||||
func TestTransactionTipAboveFeeCap(t *testing.T) {
|
func TestTransactionTipAboveFeeCap(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
pool, key := setupTxPoolWithConfig(eip1559NoL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key)
|
tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key)
|
||||||
|
|
@ -411,7 +411,7 @@ func TestTransactionTipAboveFeeCap(t *testing.T) {
|
||||||
func TestTransactionVeryHighValues(t *testing.T) {
|
func TestTransactionVeryHighValues(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
pool, key := setupTxPoolWithConfig(eip1559NoL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
veryBigNumber := big.NewInt(1)
|
veryBigNumber := big.NewInt(1)
|
||||||
|
|
@ -431,7 +431,7 @@ func TestTransactionVeryHighValues(t *testing.T) {
|
||||||
func TestTransactionChainFork(t *testing.T) {
|
func TestTransactionChainFork(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -460,7 +460,7 @@ func TestTransactionChainFork(t *testing.T) {
|
||||||
func TestTransactionDoubleNonce(t *testing.T) {
|
func TestTransactionDoubleNonce(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -511,7 +511,7 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||||
func TestTransactionMissingNonce(t *testing.T) {
|
func TestTransactionMissingNonce(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -535,7 +535,7 @@ func TestTransactionNonceRecovery(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
const n = 10
|
const n = 10
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -561,7 +561,7 @@ func TestTransactionDropping(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -779,7 +779,7 @@ func TestTransactionGapFilling(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -833,7 +833,7 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -1114,7 +1114,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -1203,7 +1203,7 @@ func TestTransactionAllowedTxSize(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -1463,7 +1463,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
pool, _ := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
pool, _ := setupTxPoolWithConfig(eip1559NoL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
// Keep track of transaction events to ensure all executables get announced
|
// Keep track of transaction events to ensure all executables get announced
|
||||||
|
|
@ -1834,7 +1834,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
|
||||||
func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
|
func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, _ := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
pool, _ := setupTxPoolWithConfig(eip1559NoL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
pool.config.GlobalSlots = 2
|
pool.config.GlobalSlots = 2
|
||||||
|
|
@ -1941,7 +1941,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
|
||||||
func TestDualHeapEviction(t *testing.T) {
|
func TestDualHeapEviction(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, _ := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
pool, _ := setupTxPoolWithConfig(eip1559NoL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
pool.config.GlobalSlots = 10
|
pool.config.GlobalSlots = 10
|
||||||
|
|
@ -2144,7 +2144,7 @@ func TestTransactionReplacementDynamicFee(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// Create the pool to test the pricing enforcement with
|
||||||
pool, key := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
pool, key := setupTxPoolWithConfig(eip1559NoL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
|
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
|
||||||
|
|
||||||
|
|
@ -2443,7 +2443,7 @@ func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 1
|
||||||
|
|
||||||
func benchmarkPendingDemotion(b *testing.B, size int) {
|
func benchmarkPendingDemotion(b *testing.B, size int) {
|
||||||
// Add a batch of transactions to a pool one by one
|
// Add a batch of transactions to a pool one by one
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -2468,7 +2468,7 @@ func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 1
|
||||||
|
|
||||||
func benchmarkFuturePromotion(b *testing.B, size int) {
|
func benchmarkFuturePromotion(b *testing.B, size int) {
|
||||||
// Add a batch of transactions to a pool one by one
|
// Add a batch of transactions to a pool one by one
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -2496,7 +2496,7 @@ func BenchmarkPoolBatchLocalInsert10000(b *testing.B) { benchmarkPoolBatchInsert
|
||||||
|
|
||||||
func benchmarkPoolBatchInsert(b *testing.B, size int, local bool) {
|
func benchmarkPoolBatchInsert(b *testing.B, size int, local bool) {
|
||||||
// Generate a batch of transactions to enqueue into the pool
|
// Generate a batch of transactions to enqueue into the pool
|
||||||
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
pool, key := setupTxPoolWithConfig(noL1DataFeeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ type StorageTrace struct {
|
||||||
// while replaying a transaction in debug mode as well as transaction
|
// while replaying a transaction in debug mode as well as transaction
|
||||||
// execution status, the amount of gas used and the return value
|
// execution status, the amount of gas used and the return value
|
||||||
type ExecutionResult struct {
|
type ExecutionResult struct {
|
||||||
L1Fee *hexutil.Big `json:"l1Fee,omitempty"`
|
L1DataFee *hexutil.Big `json:"l1DataFee,omitempty"`
|
||||||
Gas uint64 `json:"gas"`
|
Gas uint64 `json:"gas"`
|
||||||
Failed bool `json:"failed"`
|
Failed bool `json:"failed"`
|
||||||
ReturnValue string `json:"returnValue"`
|
ReturnValue string `json:"returnValue"`
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/core/types"
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
"github.com/scroll-tech/go-ethereum/core/vm"
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
"github.com/scroll-tech/go-ethereum/trie"
|
"github.com/scroll-tech/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -191,7 +192,11 @@ 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.Prepare(tx.Hash(), idx)
|
statedb.Prepare(tx.Hash(), idx)
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, vm.BlockContext{}, nil, err
|
||||||
|
}
|
||||||
|
if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), l1DataFee); 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)
|
||||||
}
|
}
|
||||||
// Ensure any modifications are committed to the state
|
// Ensure any modifications are committed to the state
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,16 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
|
||||||
TxIndex: i,
|
TxIndex: i,
|
||||||
TxHash: tx.Hash(),
|
TxHash: tx.Hash(),
|
||||||
}
|
}
|
||||||
res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config)
|
|
||||||
|
l1DataFee, err := fees.CalculateL1DataFee(tx, task.statedb)
|
||||||
|
if err != nil {
|
||||||
|
// though it's not a "tracing error", we still need to put it here
|
||||||
|
task.results[i] = &txTraceResult{Error: err.Error()}
|
||||||
|
log.Warn("CalculateL1DataFee failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config, l1DataFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
task.results[i] = &txTraceResult{Error: err.Error()}
|
task.results[i] = &txTraceResult{Error: err.Error()}
|
||||||
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
|
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
|
||||||
|
|
@ -534,7 +543,14 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
||||||
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
|
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
|
||||||
)
|
)
|
||||||
statedb.Prepare(tx.Hash(), i)
|
statedb.Prepare(tx.Hash(), i)
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
|
|
||||||
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee); err != nil {
|
||||||
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
||||||
// We intentionally don't return the error here: if we do, then the RPC server will not
|
// We intentionally don't return the error here: if we do, then the RPC server will not
|
||||||
// return the roots. Most likely, the caller already knows that a certain transaction fails to
|
// return the roots. Most likely, the caller already knows that a certain transaction fails to
|
||||||
|
|
@ -608,7 +624,14 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||||
TxIndex: task.index,
|
TxIndex: task.index,
|
||||||
TxHash: txs[task.index].Hash(),
|
TxHash: txs[task.index].Hash(),
|
||||||
}
|
}
|
||||||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
|
|
||||||
|
l1DataFee, err := fees.CalculateL1DataFee(txs[task.index], task.statedb)
|
||||||
|
if err != nil {
|
||||||
|
// though it's not a "tracing error", we still need to put it here
|
||||||
|
results[task.index] = &txTraceResult{Error: err.Error()}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config, l1DataFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
results[task.index] = &txTraceResult{Error: err.Error()}
|
results[task.index] = &txTraceResult{Error: err.Error()}
|
||||||
continue
|
continue
|
||||||
|
|
@ -627,7 +650,12 @@ 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.Prepare(tx.Hash(), i)
|
statedb.Prepare(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{})
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
failed = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee); err != nil {
|
||||||
failed = err
|
failed = err
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -740,7 +768,10 @@ 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.Prepare(tx.Hash(), i)
|
statedb.Prepare(tx.Hash(), i)
|
||||||
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err == nil {
|
||||||
|
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee)
|
||||||
|
}
|
||||||
if writer != nil {
|
if writer != nil {
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
}
|
}
|
||||||
|
|
@ -777,7 +808,7 @@ func containsTx(block *types.Block, hash common.Hash) bool {
|
||||||
// TraceTransaction returns the structured logs created during the execution of EVM
|
// TraceTransaction returns the structured logs created during the execution of EVM
|
||||||
// and returns them as a JSON object.
|
// and returns them as a JSON object.
|
||||||
func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
|
func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
|
||||||
_, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
|
tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -802,7 +833,11 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
|
||||||
TxIndex: int(index),
|
TxIndex: int(index),
|
||||||
TxHash: hash,
|
TxHash: hash,
|
||||||
}
|
}
|
||||||
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config, l1DataFee)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TraceCall lets you trace a given eth_call. It collects the structured logs
|
// TraceCall lets you trace a given eth_call. It collects the structured logs
|
||||||
|
|
@ -856,13 +891,20 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
||||||
Reexec: config.Reexec,
|
Reexec: config.Reexec,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
|
|
||||||
|
signer := types.MakeSigner(api.backend.ChainConfig(), block.Number())
|
||||||
|
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, block.BaseFee(), api.backend.ChainConfig().ChainID, signer, statedb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig, l1DataFee)
|
||||||
}
|
}
|
||||||
|
|
||||||
// traceTx configures a new tracer according to the provided configuration, and
|
// traceTx configures a new tracer according to the provided configuration, and
|
||||||
// executes the given message in the provided environment. The return value will
|
// executes the given message in the provided environment. The return value will
|
||||||
// be tracer dependent.
|
// be tracer dependent.
|
||||||
func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig, l1DataFee *big.Int) (interface{}, error) {
|
||||||
// Assemble the structured logger or the JavaScript tracer
|
// Assemble the structured logger or the JavaScript tracer
|
||||||
var (
|
var (
|
||||||
tracer vm.EVMLogger
|
tracer vm.EVMLogger
|
||||||
|
|
@ -899,20 +941,15 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex
|
||||||
// Run the transaction with tracing enabled.
|
// Run the transaction with tracing enabled.
|
||||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
|
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
|
||||||
|
|
||||||
// If gasPrice is 0, make sure that the account has sufficient balance to cover `l1Fee`.
|
// If gasPrice is 0, make sure that the account has sufficient balance to cover `l1DataFee`.
|
||||||
if api.backend.ChainConfig().Scroll.FeeVaultEnabled() && message.GasPrice().Cmp(big.NewInt(0)) == 0 {
|
if message.GasPrice().Cmp(big.NewInt(0)) == 0 {
|
||||||
l1Fee, err := fees.CalculateL1MsgFee(message, vmenv.StateDB)
|
statedb.AddBalance(message.From(), l1DataFee)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
statedb.AddBalance(message.From(), l1Fee)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call Prepare to clear out the statedb access list
|
// Call Prepare to clear out the statedb access list
|
||||||
statedb.Prepare(txctx.TxHash, txctx.TxIndex)
|
statedb.Prepare(txctx.TxHash, txctx.TxIndex)
|
||||||
|
|
||||||
result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
|
result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), l1DataFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tracing failed: %w", err)
|
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -930,7 +967,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex
|
||||||
Failed: result.Failed(),
|
Failed: result.Failed(),
|
||||||
ReturnValue: returnVal,
|
ReturnValue: returnVal,
|
||||||
StructLogs: vm.FormatLogs(tracer.StructLogs()),
|
StructLogs: vm.FormatLogs(tracer.StructLogs()),
|
||||||
L1Fee: (*hexutil.Big)(result.L1Fee),
|
L1DataFee: (*hexutil.Big)(result.L1DataFee),
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
case Tracer:
|
case Tracer:
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/core/vm"
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"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/fees"
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/withdrawtrie"
|
"github.com/scroll-tech/go-ethereum/rollup/withdrawtrie"
|
||||||
"github.com/scroll-tech/go-ethereum/rpc"
|
"github.com/scroll-tech/go-ethereum/rpc"
|
||||||
|
|
@ -182,7 +183,12 @@ func (api *API) getBlockTrace(block *types.Block, env *traceEnv) (*types.BlockTr
|
||||||
msg, _ := tx.AsMessage(env.signer, block.BaseFee())
|
msg, _ := tx.AsMessage(env.signer, block.BaseFee())
|
||||||
env.state.Prepare(tx.Hash(), i)
|
env.state.Prepare(tx.Hash(), i)
|
||||||
vmenv := vm.NewEVM(env.blockCtx, core.NewEVMTxContext(msg), env.state, api.backend.ChainConfig(), vm.Config{})
|
vmenv := vm.NewEVM(env.blockCtx, core.NewEVMTxContext(msg), env.state, api.backend.ChainConfig(), vm.Config{})
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
|
l1DataFee, err := fees.CalculateL1DataFee(tx, env.state)
|
||||||
|
if err != nil {
|
||||||
|
failed = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee); err != nil {
|
||||||
failed = err
|
failed = err
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -258,7 +264,11 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
|
||||||
state.Prepare(txctx.TxHash, txctx.TxIndex)
|
state.Prepare(txctx.TxHash, txctx.TxIndex)
|
||||||
|
|
||||||
// Computes the new state by applying the given message.
|
// Computes the new state by applying the given message.
|
||||||
result, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
l1DataFee, err := fees.CalculateL1DataFee(tx, state)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("tracing failed: %w", err)
|
||||||
|
}
|
||||||
|
result, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("tracing failed: %w", err)
|
return fmt.Errorf("tracing failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -389,7 +399,7 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
|
||||||
To: receiver,
|
To: receiver,
|
||||||
AccountCreated: createdAcc,
|
AccountCreated: createdAcc,
|
||||||
AccountsAfter: after,
|
AccountsAfter: after,
|
||||||
L1Fee: (*hexutil.Big)(result.L1Fee),
|
L1DataFee: (*hexutil.Big)(result.L1DataFee),
|
||||||
Gas: result.UsedGas,
|
Gas: result.UsedGas,
|
||||||
Failed: result.Failed(),
|
Failed: result.Failed(),
|
||||||
ReturnValue: fmt.Sprintf("%x", returnVal),
|
ReturnValue: fmt.Sprintf("%x", returnVal),
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ func checkStructLogs(t *testing.T, expect []*txTraceResult, actual []*types.Exec
|
||||||
assert.Equal(t, len(expect), len(actual))
|
assert.Equal(t, len(expect), len(actual))
|
||||||
for i, val := range expect {
|
for i, val := range expect {
|
||||||
trace1, trace2 := val.Result.(*types.ExecutionResult), actual[i]
|
trace1, trace2 := val.Result.(*types.ExecutionResult), actual[i]
|
||||||
assert.Equal(t, trace1.L1Fee, trace2.L1Fee)
|
assert.Equal(t, trace1.L1DataFee, trace2.L1DataFee)
|
||||||
assert.Equal(t, trace1.Failed, trace2.Failed)
|
assert.Equal(t, trace1.Failed, trace2.Failed)
|
||||||
assert.Equal(t, trace1.Gas, trace2.Gas)
|
assert.Equal(t, trace1.Gas, trace2.Gas)
|
||||||
assert.Equal(t, trace1.ReturnValue, trace2.ReturnValue)
|
assert.Equal(t, trace1.ReturnValue, trace2.ReturnValue)
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||||
"github.com/scroll-tech/go-ethereum/internal/ethapi"
|
"github.com/scroll-tech/go-ethereum/internal/ethapi"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
"github.com/scroll-tech/go-ethereum/rpc"
|
"github.com/scroll-tech/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -172,7 +173,11 @@ 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{})
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, vm.BlockContext{}, nil, err
|
||||||
|
}
|
||||||
|
if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), l1DataFee); 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)
|
||||||
}
|
}
|
||||||
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
|
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
|
||||||
|
|
@ -218,7 +223,7 @@ func TestTraceCall(t *testing.T) {
|
||||||
config: nil,
|
config: nil,
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
expect: &types.ExecutionResult{
|
expect: &types.ExecutionResult{
|
||||||
L1Fee: (*hexutil.Big)(big.NewInt(0)),
|
L1DataFee: (*hexutil.Big)(big.NewInt(0)),
|
||||||
Gas: params.TxGas,
|
Gas: params.TxGas,
|
||||||
Failed: false,
|
Failed: false,
|
||||||
ReturnValue: "",
|
ReturnValue: "",
|
||||||
|
|
@ -236,7 +241,7 @@ func TestTraceCall(t *testing.T) {
|
||||||
config: nil,
|
config: nil,
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
expect: &types.ExecutionResult{
|
expect: &types.ExecutionResult{
|
||||||
L1Fee: (*hexutil.Big)(big.NewInt(0)),
|
L1DataFee: (*hexutil.Big)(big.NewInt(0)),
|
||||||
Gas: params.TxGas,
|
Gas: params.TxGas,
|
||||||
Failed: false,
|
Failed: false,
|
||||||
ReturnValue: "",
|
ReturnValue: "",
|
||||||
|
|
@ -266,7 +271,7 @@ func TestTraceCall(t *testing.T) {
|
||||||
config: nil,
|
config: nil,
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
expect: &types.ExecutionResult{
|
expect: &types.ExecutionResult{
|
||||||
L1Fee: (*hexutil.Big)(big.NewInt(0)),
|
L1DataFee: (*hexutil.Big)(big.NewInt(0)),
|
||||||
Gas: params.TxGas,
|
Gas: params.TxGas,
|
||||||
Failed: false,
|
Failed: false,
|
||||||
ReturnValue: "",
|
ReturnValue: "",
|
||||||
|
|
@ -284,7 +289,7 @@ func TestTraceCall(t *testing.T) {
|
||||||
config: nil,
|
config: nil,
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
expect: &types.ExecutionResult{
|
expect: &types.ExecutionResult{
|
||||||
L1Fee: (*hexutil.Big)(big.NewInt(0)),
|
L1DataFee: (*hexutil.Big)(big.NewInt(0)),
|
||||||
Gas: params.TxGas,
|
Gas: params.TxGas,
|
||||||
Failed: false,
|
Failed: false,
|
||||||
ReturnValue: "",
|
ReturnValue: "",
|
||||||
|
|
@ -338,7 +343,7 @@ func TestTraceTransaction(t *testing.T) {
|
||||||
t.Errorf("Failed to trace transaction %v", err)
|
t.Errorf("Failed to trace transaction %v", err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(result, &types.ExecutionResult{
|
if !reflect.DeepEqual(result, &types.ExecutionResult{
|
||||||
L1Fee: (*hexutil.Big)(big.NewInt(0)),
|
L1DataFee: (*hexutil.Big)(big.NewInt(0)),
|
||||||
Gas: params.TxGas,
|
Gas: params.TxGas,
|
||||||
Failed: false,
|
Failed: false,
|
||||||
ReturnValue: "",
|
ReturnValue: "",
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/eth/tracers"
|
"github.com/scroll-tech/go-ethereum/eth/tracers"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
"github.com/scroll-tech/go-ethereum/rlp"
|
"github.com/scroll-tech/go-ethereum/rlp"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
"github.com/scroll-tech/go-ethereum/tests"
|
"github.com/scroll-tech/go-ethereum/tests"
|
||||||
|
|
||||||
// Force-load native and js pacakges, to trigger registration
|
// Force-load native and js pacakges, to trigger registration
|
||||||
|
|
@ -192,7 +193,11 @@ 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)
|
||||||
}
|
}
|
||||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to calculate l1DataFee: %v", err)
|
||||||
|
}
|
||||||
|
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()), l1DataFee)
|
||||||
if _, err = st.TransitionDb(); err != nil {
|
if _, err = st.TransitionDb(); err != nil {
|
||||||
t.Fatalf("failed to execute transaction: %v", err)
|
t.Fatalf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -303,7 +308,11 @@ 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()
|
||||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("failed to calculate l1DataFee: %v", err)
|
||||||
|
}
|
||||||
|
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()), l1DataFee)
|
||||||
if _, err = st.TransitionDb(); err != nil {
|
if _, err = st.TransitionDb(); err != nil {
|
||||||
b.Fatalf("failed to execute transaction: %v", err)
|
b.Fatalf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -372,7 +381,11 @@ 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)
|
||||||
}
|
}
|
||||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to calculate l1DataFee: %v", err)
|
||||||
|
}
|
||||||
|
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()), l1DataFee)
|
||||||
if _, err = st.TransitionDb(); err != nil {
|
if _, err = st.TransitionDb(); err != nil {
|
||||||
t.Fatalf("failed to execute transaction: %v", err)
|
t.Fatalf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/core/vm"
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
"github.com/scroll-tech/go-ethereum/crypto"
|
"github.com/scroll-tech/go-ethereum/crypto"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
"github.com/scroll-tech/go-ethereum/tests"
|
"github.com/scroll-tech/go-ethereum/tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -111,7 +112,11 @@ 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()
|
||||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()), l1DataFee)
|
||||||
_, err = st.TransitionDb()
|
_, err = st.TransitionDb()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,7 @@ func testCallContractNoGas(t *testing.T, client *rpc.Client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this would fail with `insufficient funds for gas * price + value`
|
// this would fail with `insufficient funds for gas * price + value`
|
||||||
// before we started considering l1fee for 0 gas calls.
|
// before we started considering l1DataFee for 0 gas calls.
|
||||||
if _, err := ec.CallContract(context.Background(), msg, big.NewInt(0), nil); err != nil {
|
if _, err := ec.CallContract(context.Background(), msg, big.NewInt(0), nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -907,7 +907,7 @@ func newRPCBalance(balance *big.Int) **hexutil.Big {
|
||||||
return &rpcBalance
|
return &rpcBalance
|
||||||
}
|
}
|
||||||
|
|
||||||
func CalculateL1MsgFee(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64, config *params.ChainConfig) (*big.Int, error) {
|
func EstimateL1MsgFee(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64, config *params.ChainConfig) (*big.Int, error) {
|
||||||
if !config.Scroll.FeeVaultEnabled() {
|
if !config.Scroll.FeeVaultEnabled() {
|
||||||
return big.NewInt(0), nil
|
return big.NewInt(0), nil
|
||||||
}
|
}
|
||||||
|
|
@ -947,7 +947,8 @@ func CalculateL1MsgFee(ctx context.Context, b Backend, args TransactionArgs, blo
|
||||||
evm.Cancel()
|
evm.Cancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return fees.CalculateL1MsgFee(msg, evm.StateDB)
|
signer := types.MakeSigner(config, header.Number)
|
||||||
|
return fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config.ChainID, signer, evm.StateDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
|
@ -990,7 +991,14 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
||||||
|
|
||||||
// Execute the message.
|
// Execute the message.
|
||||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
result, err := core.ApplyMessage(evm, msg, gp)
|
|
||||||
|
signer := types.MakeSigner(b.ChainConfig(), header.Number)
|
||||||
|
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, b.ChainConfig().ChainID, signer, state)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := core.ApplyMessage(evm, msg, gp, l1DataFee)
|
||||||
if err := vmError(); err != nil {
|
if err := vmError(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1043,7 +1051,7 @@ func (e *revertError) ErrorData() interface{} {
|
||||||
// useful to execute and retrieve values.
|
// useful to execute and retrieve values.
|
||||||
func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) {
|
func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) {
|
||||||
// If gasPrice is 0 and no state override is set, make sure
|
// If gasPrice is 0 and no state override is set, make sure
|
||||||
// that the account has sufficient balance to cover `l1Fee`.
|
// that the account has sufficient balance to cover `l1DataFee`.
|
||||||
isGasPriceZero := args.GasPrice == nil || args.GasPrice.ToInt().Cmp(big.NewInt(0)) == 0
|
isGasPriceZero := args.GasPrice == nil || args.GasPrice.ToInt().Cmp(big.NewInt(0)) == 0
|
||||||
|
|
||||||
if overrides == nil {
|
if overrides == nil {
|
||||||
|
|
@ -1052,13 +1060,13 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, bl
|
||||||
_, isOverrideSet := (*overrides)[args.from()]
|
_, isOverrideSet := (*overrides)[args.from()]
|
||||||
|
|
||||||
if isGasPriceZero && !isOverrideSet {
|
if isGasPriceZero && !isOverrideSet {
|
||||||
l1Fee, err := CalculateL1MsgFee(ctx, s.b, args, blockNrOrHash, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap(), s.b.ChainConfig())
|
l1DataFee, err := EstimateL1MsgFee(ctx, s.b, args, blockNrOrHash, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap(), s.b.ChainConfig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
(*overrides)[args.from()] = OverrideAccount{
|
(*overrides)[args.from()] = OverrideAccount{
|
||||||
BalanceAdd: newRPCBalance(l1Fee),
|
BalanceAdd: newRPCBalance(l1DataFee),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1127,14 +1135,14 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
||||||
}
|
}
|
||||||
|
|
||||||
// account for l1 fee
|
// account for l1 fee
|
||||||
l1Fee, err := CalculateL1MsgFee(ctx, b, args, blockNrOrHash, nil, 0, gasCap, b.ChainConfig())
|
l1DataFee, err := EstimateL1MsgFee(ctx, b, args, blockNrOrHash, nil, 0, gasCap, b.ChainConfig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if l1Fee.Cmp(available) >= 0 {
|
if l1DataFee.Cmp(available) >= 0 {
|
||||||
return 0, errors.New("insufficient funds for l1 fee")
|
return 0, errors.New("insufficient funds for l1 fee")
|
||||||
}
|
}
|
||||||
available.Sub(available, l1Fee)
|
available.Sub(available, l1DataFee)
|
||||||
|
|
||||||
allowance := new(big.Int).Div(available, feeCap)
|
allowance := new(big.Int).Div(available, feeCap)
|
||||||
|
|
||||||
|
|
@ -1501,7 +1509,12 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, err
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
signer := types.MakeSigner(b.ChainConfig(), header.Number)
|
||||||
|
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, b.ChainConfig().ChainID, signer, statedb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
|
||||||
|
}
|
||||||
|
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/light"
|
"github.com/scroll-tech/go-ethereum/light"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
"github.com/scroll-tech/go-ethereum/rlp"
|
"github.com/scroll-tech/go-ethereum/rlp"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
)
|
)
|
||||||
|
|
||||||
type odrTestFn func(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
|
type odrTestFn func(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
|
||||||
|
|
@ -143,7 +144,9 @@ 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)
|
||||||
result, _ := core.ApplyMessage(vmenv, msg, gp)
|
signer := types.MakeSigner(config, header.Number)
|
||||||
|
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config.ChainID, signer, statedb)
|
||||||
|
result, _ := core.ApplyMessage(vmenv, msg, gp, l1DataFee)
|
||||||
res = append(res, result.Return()...)
|
res = append(res, result.Return()...)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -155,7 +158,9 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
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)
|
||||||
result, _ := core.ApplyMessage(vmenv, msg, gp)
|
signer := types.MakeSigner(config, header.Number)
|
||||||
|
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config.ChainID, signer, state)
|
||||||
|
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()...)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/core/types"
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
"github.com/scroll-tech/go-ethereum/core/vm"
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
"github.com/scroll-tech/go-ethereum/light"
|
"github.com/scroll-tech/go-ethereum/light"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
)
|
)
|
||||||
|
|
||||||
// stateAtBlock retrieves the state database associated with a certain block.
|
// stateAtBlock retrieves the state database associated with a certain block.
|
||||||
|
|
@ -64,7 +65,11 @@ 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{})
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
l1DataFee, err := fees.CalculateL1DataFee(tx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||||
|
}
|
||||||
|
if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), l1DataFee); 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)
|
||||||
}
|
}
|
||||||
// Ensure any modifications are committed to the state
|
// Ensure any modifications are committed to the state
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
"github.com/scroll-tech/go-ethereum/rlp"
|
"github.com/scroll-tech/go-ethereum/rlp"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
"github.com/scroll-tech/go-ethereum/trie"
|
"github.com/scroll-tech/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -199,7 +200,9 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
||||||
context := core.NewEVMBlockContext(header, chain, nil)
|
context := core.NewEVMBlockContext(header, chain, nil)
|
||||||
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)
|
||||||
result, _ := core.ApplyMessage(vmenv, msg, gp)
|
signer := types.MakeSigner(config, header.Number)
|
||||||
|
l1DataFee, _ := fees.EstimateL1DataFeeForMessage(msg, header.BaseFee, config.ChainID, signer, st)
|
||||||
|
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 {
|
||||||
return res, st.Error()
|
return res, st.Error()
|
||||||
|
|
|
||||||
|
|
@ -340,7 +340,7 @@ var (
|
||||||
}}
|
}}
|
||||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||||
|
|
||||||
TestNoL1feeChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil,
|
TestNoL1DataFeeChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil,
|
||||||
ScrollConfig{
|
ScrollConfig{
|
||||||
UseZktrie: false,
|
UseZktrie: false,
|
||||||
FeeVaultAddress: nil,
|
FeeVaultAddress: nil,
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VersionMajor = 4 // Major version component of the current release
|
VersionMajor = 4 // Major version component of the current release
|
||||||
VersionMinor = 1 // Minor version component of the current release
|
VersionMinor = 2 // Minor version component of the current release
|
||||||
VersionPatch = 1 // Patch version component of the current release
|
VersionPatch = 0 // Patch version component of the current release
|
||||||
VersionMeta = "sepolia" // Version metadata to append to the version string
|
VersionMeta = "sepolia" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,24 +8,17 @@ import (
|
||||||
|
|
||||||
"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/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// errTransactionSigned represents the error case of passing in a signed
|
|
||||||
// transaction to the L1 fee calculation routine. The signature is accounted
|
|
||||||
// for externally
|
|
||||||
errTransactionSigned = errors.New("transaction is signed")
|
|
||||||
|
|
||||||
// txExtraDataBytes is the number of bytes that we commit to L1 in addition
|
// txExtraDataBytes is the number of bytes that we commit to L1 in addition
|
||||||
// to the RLP-encoded unsigned transaction. Note that these are all assumed
|
// to the RLP-encoded signed transaction. Note that these are all assumed
|
||||||
// to be non-zero.
|
// to be non-zero.
|
||||||
// - tx length prefix: 4 bytes
|
// - tx length prefix: 4 bytes
|
||||||
// - sig.r: 32 bytes + 1 byte rlp prefix
|
txExtraDataBytes = uint64(4)
|
||||||
// - sig.s: 32 bytes + 1 byte rlp prefix
|
|
||||||
// - sig.v: 3 bytes + 1 byte rlp prefix
|
|
||||||
txExtraDataBytes = uint64(74)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Message represents the interface of a message.
|
// Message represents the interface of a message.
|
||||||
|
|
@ -36,9 +29,13 @@ type Message interface {
|
||||||
To() *common.Address
|
To() *common.Address
|
||||||
GasPrice() *big.Int
|
GasPrice() *big.Int
|
||||||
Gas() uint64
|
Gas() uint64
|
||||||
|
GasFeeCap() *big.Int
|
||||||
|
GasTipCap() *big.Int
|
||||||
Value() *big.Int
|
Value() *big.Int
|
||||||
Nonce() uint64
|
Nonce() uint64
|
||||||
Data() []byte
|
Data() []byte
|
||||||
|
AccessList() types.AccessList
|
||||||
|
IsL1MessageTx() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateDB represents the StateDB interface
|
// StateDB represents the StateDB interface
|
||||||
|
|
@ -48,59 +45,87 @@ type StateDB interface {
|
||||||
GetBalance(addr common.Address) *big.Int
|
GetBalance(addr common.Address) *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateL1MsgFee computes the L1 portion of the fee given
|
func EstimateL1DataFeeForMessage(msg Message, baseFee, chainID *big.Int, signer types.Signer, state StateDB) (*big.Int, error) {
|
||||||
// a Message and a StateDB
|
if msg.IsL1MessageTx() {
|
||||||
// Reference: https://github.com/ethereum-optimism/optimism/blob/develop/l2geth/rollup/fees/rollup_fee.go
|
return big.NewInt(0), nil
|
||||||
func CalculateL1MsgFee(msg Message, state StateDB) (*big.Int, error) {
|
}
|
||||||
tx := asTransaction(msg)
|
|
||||||
|
unsigned := asUnsignedTx(msg, baseFee, chainID)
|
||||||
|
// with v=1
|
||||||
|
tx, err := unsigned.WithSignature(signer, append(bytes.Repeat([]byte{0xff}, crypto.SignatureLength-1), 0x01))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
raw, err := rlpEncode(tx)
|
raw, err := rlpEncode(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
|
l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
|
||||||
l1Fee := CalculateL1Fee(raw, overhead, l1BaseFee, scalar)
|
l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar)
|
||||||
return l1Fee, nil
|
return l1DataFee, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// asTransaction turns a Message into a types.Transaction
|
// asUnsignedTx turns a Message into a types.Transaction
|
||||||
func asTransaction(msg Message) *types.Transaction {
|
func asUnsignedTx(msg Message, baseFee, chainID *big.Int) *types.Transaction {
|
||||||
if msg.To() == nil {
|
if baseFee == nil {
|
||||||
return types.NewContractCreation(
|
if msg.AccessList() == nil {
|
||||||
msg.Nonce(),
|
return asUnsignedLegacyTx(msg)
|
||||||
msg.Value(),
|
}
|
||||||
msg.Gas(),
|
|
||||||
msg.GasPrice(),
|
return asUnsignedAccessListTx(msg, chainID)
|
||||||
msg.Data(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return types.NewTransaction(
|
|
||||||
msg.Nonce(),
|
return asUnsignedDynamicTx(msg, chainID)
|
||||||
*msg.To(),
|
}
|
||||||
msg.Value(),
|
|
||||||
msg.Gas(),
|
func asUnsignedLegacyTx(msg Message) *types.Transaction {
|
||||||
msg.GasPrice(),
|
return types.NewTx(&types.LegacyTx{
|
||||||
msg.Data(),
|
Nonce: msg.Nonce(),
|
||||||
)
|
To: msg.To(),
|
||||||
|
Value: msg.Value(),
|
||||||
|
Gas: msg.Gas(),
|
||||||
|
GasPrice: msg.GasPrice(),
|
||||||
|
Data: msg.Data(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func asUnsignedAccessListTx(msg Message, chainID *big.Int) *types.Transaction {
|
||||||
|
return types.NewTx(&types.AccessListTx{
|
||||||
|
Nonce: msg.Nonce(),
|
||||||
|
To: msg.To(),
|
||||||
|
Value: msg.Value(),
|
||||||
|
Gas: msg.Gas(),
|
||||||
|
GasPrice: msg.GasPrice(),
|
||||||
|
Data: msg.Data(),
|
||||||
|
AccessList: msg.AccessList(),
|
||||||
|
ChainID: chainID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func asUnsignedDynamicTx(msg Message, chainID *big.Int) *types.Transaction {
|
||||||
|
return types.NewTx(&types.DynamicFeeTx{
|
||||||
|
Nonce: msg.Nonce(),
|
||||||
|
To: msg.To(),
|
||||||
|
Value: msg.Value(),
|
||||||
|
Gas: msg.Gas(),
|
||||||
|
GasFeeCap: msg.GasFeeCap(),
|
||||||
|
GasTipCap: msg.GasTipCap(),
|
||||||
|
Data: msg.Data(),
|
||||||
|
AccessList: msg.AccessList(),
|
||||||
|
ChainID: chainID,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// rlpEncode RLP encodes the transaction into bytes
|
// rlpEncode RLP encodes the transaction into bytes
|
||||||
// When a signature is not included, set pad to true to
|
|
||||||
// fill in a dummy signature full on non 0 bytes
|
|
||||||
func rlpEncode(tx *types.Transaction) ([]byte, error) {
|
func rlpEncode(tx *types.Transaction) ([]byte, error) {
|
||||||
raw := new(bytes.Buffer)
|
raw := new(bytes.Buffer)
|
||||||
if err := tx.EncodeRLP(raw); err != nil {
|
if err := tx.EncodeRLP(raw); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r, v, s := tx.RawSignatureValues()
|
return raw.Bytes(), nil
|
||||||
if r.Cmp(common.Big0) != 0 || v.Cmp(common.Big0) != 0 || s.Cmp(common.Big0) != 0 {
|
|
||||||
return nil, errTransactionSigned
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice off the 0 bytes representing the signature
|
|
||||||
b := raw.Bytes()
|
|
||||||
return b[:len(b)-3], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readGPOStorageSlots(addr common.Address, state StateDB) (*big.Int, *big.Int, *big.Int) {
|
func readGPOStorageSlots(addr common.Address, state StateDB) (*big.Int, *big.Int, *big.Int) {
|
||||||
|
|
@ -110,11 +135,11 @@ func readGPOStorageSlots(addr common.Address, state StateDB) (*big.Int, *big.Int
|
||||||
return l1BaseFee.Big(), overhead.Big(), scalar.Big()
|
return l1BaseFee.Big(), overhead.Big(), scalar.Big()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateL1Fee computes the L1 fee
|
// calculateEncodedL1DataFee computes the L1 fee for an RLP-encoded tx
|
||||||
func CalculateL1Fee(data []byte, overhead, l1GasPrice *big.Int, scalar *big.Int) *big.Int {
|
func calculateEncodedL1DataFee(data []byte, overhead, l1GasPrice *big.Int, scalar *big.Int) *big.Int {
|
||||||
l1GasUsed := CalculateL1GasUsed(data, overhead)
|
l1GasUsed := CalculateL1GasUsed(data, overhead)
|
||||||
l1Fee := new(big.Int).Mul(l1GasUsed, l1GasPrice)
|
l1DataFee := new(big.Int).Mul(l1GasUsed, l1GasPrice)
|
||||||
return mulAndScale(l1Fee, scalar, rcfg.Precision)
|
return mulAndScale(l1DataFee, scalar, rcfg.Precision)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateL1GasUsed computes the L1 gas used based on the calldata and
|
// CalculateL1GasUsed computes the L1 gas used based on the calldata and
|
||||||
|
|
@ -150,41 +175,24 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyTransaction copies the transaction, removing the signature
|
func CalculateL1DataFee(tx *types.Transaction, state StateDB) (*big.Int, error) {
|
||||||
func copyTransaction(tx *types.Transaction) *types.Transaction {
|
if tx.IsL1MessageTx() {
|
||||||
if tx.To() == nil {
|
return big.NewInt(0), nil
|
||||||
return types.NewContractCreation(
|
|
||||||
tx.Nonce(),
|
|
||||||
tx.Value(),
|
|
||||||
tx.Gas(),
|
|
||||||
tx.GasPrice(),
|
|
||||||
tx.Data(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return types.NewTransaction(
|
|
||||||
tx.Nonce(),
|
|
||||||
*tx.To(),
|
|
||||||
tx.Value(),
|
|
||||||
tx.Gas(),
|
|
||||||
tx.GasPrice(),
|
|
||||||
tx.Data(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CalculateFees(tx *types.Transaction, state StateDB) (*big.Int, *big.Int, *big.Int, error) {
|
raw, err := rlpEncode(tx)
|
||||||
unsigned := copyTransaction(tx)
|
|
||||||
raw, err := rlpEncode(unsigned)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
|
l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
|
||||||
l1Fee := CalculateL1Fee(raw, overhead, l1BaseFee, scalar)
|
l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar)
|
||||||
|
return l1DataFee, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateL2Fee(tx *types.Transaction) *big.Int {
|
||||||
l2GasLimit := new(big.Int).SetUint64(tx.Gas())
|
l2GasLimit := new(big.Int).SetUint64(tx.Gas())
|
||||||
l2Fee := new(big.Int).Mul(tx.GasPrice(), l2GasLimit)
|
return new(big.Int).Mul(tx.GasPrice(), l2GasLimit)
|
||||||
fee := new(big.Int).Add(l1Fee, l2Fee)
|
|
||||||
return l1Fee, l2Fee, fee, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyFee(signer types.Signer, tx *types.Transaction, state StateDB) error {
|
func VerifyFee(signer types.Signer, tx *types.Transaction, state StateDB) error {
|
||||||
|
|
@ -194,8 +202,8 @@ func VerifyFee(signer types.Signer, tx *types.Transaction, state StateDB) error
|
||||||
}
|
}
|
||||||
|
|
||||||
balance := state.GetBalance(from)
|
balance := state.GetBalance(from)
|
||||||
|
l2Fee := calculateL2Fee(tx)
|
||||||
l1Fee, l2Fee, _, err := CalculateFees(tx, state)
|
l1DataFee, err := CalculateL1DataFee(tx, state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid transaction: %w", err)
|
return fmt.Errorf("invalid transaction: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -206,7 +214,7 @@ func VerifyFee(signer types.Signer, tx *types.Transaction, state StateDB) error
|
||||||
return errors.New("invalid transaction: insufficient funds for gas * price + value")
|
return errors.New("invalid transaction: insufficient funds for gas * price + value")
|
||||||
}
|
}
|
||||||
|
|
||||||
cost = cost.Add(cost, l1Fee)
|
cost = cost.Add(cost, l1DataFee)
|
||||||
if balance.Cmp(cost) < 0 {
|
if balance.Cmp(cost) < 0 {
|
||||||
return errors.New("invalid transaction: insufficient funds for l1fee + gas * price + value")
|
return errors.New("invalid transaction: insufficient funds for l1fee + gas * price + value")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCalculateL1Fee(t *testing.T) {
|
func TestCalculateEncodedL1DataFee(t *testing.T) {
|
||||||
l1BaseFee := new(big.Int).SetUint64(15000000)
|
l1BaseFee := new(big.Int).SetUint64(15000000)
|
||||||
|
|
||||||
data := []byte{0, 10, 1, 0}
|
data := []byte{0, 10, 1, 0}
|
||||||
|
|
@ -15,6 +15,6 @@ func TestCalculateL1Fee(t *testing.T) {
|
||||||
scalar := new(big.Int).SetUint64(10)
|
scalar := new(big.Int).SetUint64(10)
|
||||||
|
|
||||||
expected := new(big.Int).SetUint64(184) // 184.2
|
expected := new(big.Int).SetUint64(184) // 184.2
|
||||||
actual := CalculateL1Fee(data, overhead, l1BaseFee, scalar)
|
actual := calculateEncodedL1DataFee(data, overhead, l1BaseFee, scalar)
|
||||||
assert.Equal(t, expected, actual)
|
assert.Equal(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
"github.com/scroll-tech/go-ethereum/rlp"
|
"github.com/scroll-tech/go-ethereum/rlp"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StateTest checks transaction processing without block context.
|
// StateTest checks transaction processing without block context.
|
||||||
|
|
@ -201,9 +202,9 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
return nil, nil, common.Hash{}, err
|
return nil, nil, common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ttx types.Transaction
|
||||||
// Try to recover tx with current signer
|
// Try to recover tx with current signer
|
||||||
if len(post.TxBytes) != 0 {
|
if len(post.TxBytes) != 0 {
|
||||||
var ttx types.Transaction
|
|
||||||
err := ttx.UnmarshalBinary(post.TxBytes)
|
err := ttx.UnmarshalBinary(post.TxBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, common.Hash{}, err
|
return nil, nil, common.Hash{}, err
|
||||||
|
|
@ -225,7 +226,13 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
snapshot := statedb.Snapshot()
|
snapshot := statedb.Snapshot()
|
||||||
gaspool := new(core.GasPool)
|
gaspool := new(core.GasPool)
|
||||||
gaspool.AddGas(block.GasLimit())
|
gaspool.AddGas(block.GasLimit())
|
||||||
if _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
|
|
||||||
|
l1DataFee, err := fees.CalculateL1DataFee(&ttx, statedb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, common.Hash{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = core.ApplyMessage(evm, msg, gaspool, l1DataFee); err != nil {
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue