mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
feat: VerifyFee for sendTx and txpool.add (#236)
* init * rework * handle `LesApiBackend` * fix tests * add L1fee even for 0 gasPrice * update comments
This commit is contained in:
parent
481ca91e34
commit
4588569b63
7 changed files with 119 additions and 24 deletions
|
|
@ -34,6 +34,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
"github.com/scroll-tech/go-ethereum/metrics"
|
"github.com/scroll-tech/go-ethereum/metrics"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -681,6 +682,14 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||||
// the sender is marked as local previously, treat it as the local transaction.
|
// the sender is marked as local previously, treat it as the local transaction.
|
||||||
isLocal := local || pool.locals.containsTx(tx)
|
isLocal := local || pool.locals.containsTx(tx)
|
||||||
|
|
||||||
|
if pool.chainconfig.UsingScroll {
|
||||||
|
if err := fees.VerifyFee(pool.signer, tx, pool.currentState); err != nil {
|
||||||
|
log.Trace("Discarding insufficient l1fee transaction", "hash", hash, "err", err)
|
||||||
|
invalidTxMeter.Mark(1)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the transaction fails basic validation, discard it
|
// If the transaction fails basic validation, discard it
|
||||||
if err := pool.validateTx(tx, isLocal); err != nil {
|
if err := pool.validateTx(tx, isLocal); err != nil {
|
||||||
log.Trace("Discarding invalid transaction", "hash", hash, "err", err)
|
log.Trace("Discarding invalid transaction", "hash", hash, "err", err)
|
||||||
|
|
|
||||||
|
|
@ -43,18 +43,32 @@ var (
|
||||||
// sideeffects used during testing.
|
// sideeffects used during testing.
|
||||||
testTxPoolConfig TxPoolConfig
|
testTxPoolConfig TxPoolConfig
|
||||||
|
|
||||||
|
// noL1feeConfig is a chain config without L1fee enabled.
|
||||||
|
noL1feeConfig *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.
|
||||||
|
eip1559NoL1feeConfig *params.ChainConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
testTxPoolConfig = DefaultTxPoolConfig
|
testTxPoolConfig = DefaultTxPoolConfig
|
||||||
testTxPoolConfig.Journal = ""
|
testTxPoolConfig.Journal = ""
|
||||||
|
|
||||||
cpy := *params.TestChainConfig
|
cpy0 := *params.TestNoL1feeChainConfig
|
||||||
eip1559Config = &cpy
|
noL1feeConfig = &cpy0
|
||||||
|
|
||||||
|
cpy1 := *params.TestChainConfig
|
||||||
|
eip1559Config = &cpy1
|
||||||
eip1559Config.BerlinBlock = common.Big0
|
eip1559Config.BerlinBlock = common.Big0
|
||||||
eip1559Config.LondonBlock = common.Big0
|
eip1559Config.LondonBlock = common.Big0
|
||||||
|
|
||||||
|
cpy2 := *params.TestNoL1feeChainConfig
|
||||||
|
eip1559NoL1feeConfig = &cpy2
|
||||||
|
eip1559NoL1feeConfig.BerlinBlock = common.Big0
|
||||||
|
eip1559NoL1feeConfig.LondonBlock = common.Big0
|
||||||
}
|
}
|
||||||
|
|
||||||
type testBlockChain struct {
|
type testBlockChain struct {
|
||||||
|
|
@ -276,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 := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
tx := transaction(0, 100, key)
|
tx := transaction(0, 100, key)
|
||||||
|
|
@ -313,7 +327,7 @@ func TestInvalidTransactions(t *testing.T) {
|
||||||
func TestTransactionQueue(t *testing.T) {
|
func TestTransactionQueue(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
tx := transaction(0, 100, key)
|
tx := transaction(0, 100, key)
|
||||||
|
|
@ -344,7 +358,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||||
func TestTransactionQueue2(t *testing.T) {
|
func TestTransactionQueue2(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
tx1 := transaction(0, 100, key)
|
tx1 := transaction(0, 100, key)
|
||||||
|
|
@ -370,7 +384,7 @@ func TestTransactionQueue2(t *testing.T) {
|
||||||
func TestTransactionNegativeValue(t *testing.T) {
|
func TestTransactionNegativeValue(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
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)
|
||||||
|
|
@ -384,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(eip1559Config)
|
pool, key := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
||||||
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)
|
||||||
|
|
@ -397,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(eip1559Config)
|
pool, key := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
veryBigNumber := big.NewInt(1)
|
veryBigNumber := big.NewInt(1)
|
||||||
|
|
@ -417,7 +431,7 @@ func TestTransactionVeryHighValues(t *testing.T) {
|
||||||
func TestTransactionChainFork(t *testing.T) {
|
func TestTransactionChainFork(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -446,7 +460,7 @@ func TestTransactionChainFork(t *testing.T) {
|
||||||
func TestTransactionDoubleNonce(t *testing.T) {
|
func TestTransactionDoubleNonce(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -497,7 +511,7 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||||
func TestTransactionMissingNonce(t *testing.T) {
|
func TestTransactionMissingNonce(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -521,7 +535,7 @@ func TestTransactionNonceRecovery(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
const n = 10
|
const n = 10
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -547,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 := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -765,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 := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -819,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 := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -1100,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 := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -1189,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 := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -1449,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(eip1559Config)
|
pool, _ := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
||||||
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
|
||||||
|
|
@ -1820,7 +1834,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
|
||||||
func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
|
func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, _ := setupTxPoolWithConfig(eip1559Config)
|
pool, _ := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
pool.config.GlobalSlots = 2
|
pool.config.GlobalSlots = 2
|
||||||
|
|
@ -1927,7 +1941,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) {
|
||||||
func TestDualHeapEviction(t *testing.T) {
|
func TestDualHeapEviction(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
pool, _ := setupTxPoolWithConfig(eip1559Config)
|
pool, _ := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
pool.config.GlobalSlots = 10
|
pool.config.GlobalSlots = 10
|
||||||
|
|
@ -2130,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(eip1559Config)
|
pool, key := setupTxPoolWithConfig(eip1559NoL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
|
testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
|
||||||
|
|
||||||
|
|
@ -2429,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 := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -2454,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 := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
@ -2482,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 := setupTxPool()
|
pool, key := setupTxPoolWithConfig(noL1feeConfig)
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,7 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||||
|
// will `VerifyFee` & `validateTx` in txPool.AddLocal
|
||||||
return b.eth.txPool.AddLocal(signedTx)
|
return b.eth.txPool.AddLocal(signedTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,7 @@ func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *sta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||||
|
// will `VerifyFee` & `validateTx` in txPool.Add
|
||||||
return b.eth.txPool.Add(ctx, signedTx)
|
return b.eth.txPool.Add(ctx, signedTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,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"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -400,6 +401,13 @@ func (pool *TxPool) add(ctx context.Context, tx *types.Transaction) error {
|
||||||
if pool.pending[hash] != nil {
|
if pool.pending[hash] != nil {
|
||||||
return fmt.Errorf("Known transaction (%x)", hash[:4])
|
return fmt.Errorf("Known transaction (%x)", hash[:4])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pool.config.UsingScroll {
|
||||||
|
if err := fees.VerifyFee(pool.signer, tx, pool.currentState(ctx)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := pool.validateTx(ctx, tx)
|
err := pool.validateTx(ctx, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,8 @@ var (
|
||||||
|
|
||||||
TestChainConfig = &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), nil, new(EthashConfig), nil, false, &common.Address{123}, true, true, nil, true}
|
TestChainConfig = &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), nil, new(EthashConfig), nil, false, &common.Address{123}, true, true, nil, true}
|
||||||
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), nil, new(EthashConfig), nil, false, &common.Address{123}, true, true, nil, false}
|
||||||
)
|
)
|
||||||
|
|
||||||
// TrustedCheckpoint represents a set of post-processed trie roots (CHT and
|
// TrustedCheckpoint represents a set of post-processed trie roots (CHT and
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package fees
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
|
@ -35,6 +36,7 @@ type Message interface {
|
||||||
// required to compute the L1 fee
|
// required to compute the L1 fee
|
||||||
type StateDB interface {
|
type StateDB interface {
|
||||||
GetState(common.Address, common.Hash) common.Hash
|
GetState(common.Address, common.Hash) common.Hash
|
||||||
|
GetBalance(addr common.Address) *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateL1MsgFee computes the L1 portion of the fee given
|
// CalculateL1MsgFee computes the L1 portion of the fee given
|
||||||
|
|
@ -138,3 +140,61 @@ func mulAndScale(x *big.Int, y *big.Int, precision *big.Int) *big.Int {
|
||||||
z := new(big.Int).Mul(x, y)
|
z := new(big.Int).Mul(x, y)
|
||||||
return new(big.Int).Quo(z, precision)
|
return new(big.Int).Quo(z, precision)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copyTransaction copies the transaction, removing the signature
|
||||||
|
func copyTransaction(tx *types.Transaction) *types.Transaction {
|
||||||
|
if tx.To() == 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 CalculateTotalFee(tx *types.Transaction, state StateDB) (*big.Int, error) {
|
||||||
|
unsigned := copyTransaction(tx)
|
||||||
|
raw, err := rlpEncode(unsigned)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
|
||||||
|
l1Fee := CalculateL1Fee(raw, overhead, l1BaseFee, scalar)
|
||||||
|
|
||||||
|
l2GasLimit := new(big.Int).SetUint64(tx.Gas())
|
||||||
|
l2Fee := new(big.Int).Mul(tx.GasPrice(), l2GasLimit)
|
||||||
|
fee := new(big.Int).Add(l1Fee, l2Fee)
|
||||||
|
return fee, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyFee(signer types.Signer, tx *types.Transaction, state StateDB) error {
|
||||||
|
fee, err := CalculateTotalFee(tx, state)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid transaction: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cost := tx.Value()
|
||||||
|
cost = cost.Add(cost, fee)
|
||||||
|
from, err := types.Sender(signer, tx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("invalid transaction: invalid sender")
|
||||||
|
}
|
||||||
|
if state.GetBalance(from).Cmp(cost) < 0 {
|
||||||
|
return errors.New("invalid transaction: insufficient funds for gas * price + value")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check GasPrice is in an expected range
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue