Skip to content

Commit

Permalink
fix: L1Cost subtracted repeatedly && test cast
Browse files Browse the repository at this point in the history
  • Loading branch information
PinelliaC committed Jul 18, 2024
1 parent e21f841 commit efd1e22
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 106 deletions.
33 changes: 5 additions & 28 deletions core/txpool/txpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if err != nil {
return ErrInvalidSender
}
// Drop non-local transactions under our own minimal accepted gas price or tip

if tx.GasTipCapIntCmp(pool.gasPrice) < 0 {
return ErrUnderpriced
}
Expand All @@ -689,10 +689,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// Transactor should have enough funds to cover the costs
// cost == V + GP * GL
cost := tx.Cost()
var l1Cost *big.Int
if l1Cost = pool.l1CostFn(tx.RollupDataGas(), tx.IsDepositTx(), tx.To()); l1Cost != nil { // add rollup cost
cost = cost.Add(cost, l1Cost)
}

metaTxParams, err := types.DecodeAndVerifyMetaTxParams(tx,
pool.chainconfig.IsMetaTxV2(pool.chain.CurrentBlock().Time),
Expand Down Expand Up @@ -734,17 +730,13 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
userBalance = new(big.Int).Add(userBalance, sponsorCostSum)
sum := new(big.Int).Add(cost, list.totalcost)
if repl := list.txs.Get(tx.Nonce()); repl != nil {
// Deduct the cost of a transaction replaced by this
replCost := repl.Cost()
if replL1Cost := pool.l1CostFn(repl.RollupDataGas(), repl.IsDepositTx(), repl.To()); replL1Cost != nil { // add rollup cost
replCost = replCost.Add(replCost, replL1Cost)
}
replMetaTxParams, err := types.DecodeAndVerifyMetaTxParams(repl,
pool.chainconfig.IsMetaTxV2(pool.chain.CurrentBlock().Time),
pool.chainconfig.IsMetaTxV3(pool.chain.CurrentBlock().Time))
if err != nil {
return err
}
replCost := repl.Cost()
if replMetaTxParams != nil {
replTxGasCost := new(big.Int).Sub(repl.Cost(), repl.Value())
sponsorAmount, _ := types.CalculateSponsorPercentAmount(replMetaTxParams, replTxGasCost)
Expand All @@ -771,6 +763,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {

gasRemaining := big.NewInt(int64(tx.Gas() - intrGas*tokenRatio))
baseFee := pool.chain.CurrentBlock().BaseFee
l1Cost := pool.l1CostFn(tx.RollupDataGas(), tx.IsDepositTx(), tx.To())

if tx.Type() == types.LegacyTxType {
if tx.GasPrice().Cmp(baseFee) < 0 {
Expand Down Expand Up @@ -1544,10 +1537,6 @@ func (pool *TxPool) validateMetaTxList(list *list) ([]*types.Transaction, *big.I
continue
}
txGasCost := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))
l1Cost := pool.l1CostFn(tx.RollupDataGas(), tx.IsDepositTx(), tx.To())
if l1Cost != nil {
txGasCost = new(big.Int).Add(txGasCost, l1Cost) // gas fee sponsor must sponsor additional l1Cost fee
}
sponsorAmount, _ := types.CalculateSponsorPercentAmount(metaTxParams, txGasCost)
var sponsorAmountAccumulated *big.Int
sponsorAmountAccumulated, ok := sponsorCostSumPerSponsor[metaTxParams.GasFeeSponsor]
Expand Down Expand Up @@ -1595,13 +1584,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
log.Trace("Removed invalid queued meta transaction", "count", len(invalidMetaTxs))
balance := pool.currentState.GetBalance(addr)
balance = new(big.Int).Add(balance, sponsorCostSum)
if !list.Empty() {
// Reduce the cost-cap by L1 rollup cost of the first tx if necessary. Other txs will get filtered out afterwards.
el := list.txs.FirstElement()
if l1Cost := pool.l1CostFn(el.RollupDataGas(), el.IsDepositTx(), el.To()); l1Cost != nil {
balance = new(big.Int).Sub(balance, l1Cost) // negative big int is fine
}
}

// Drop all transactions that are too costly (low balance or out of gas)
drops, _ := list.Filter(balance, pool.currentMaxGas)
for _, tx := range drops {
Expand Down Expand Up @@ -1808,13 +1791,7 @@ func (pool *TxPool) demoteUnexecutables() {
}
balance := pool.currentState.GetBalance(addr)
balance = new(big.Int).Add(balance, sponsorCostSum)
if !list.Empty() {
// Reduce the cost-cap by L1 rollup cost of the first tx if necessary. Other txs will get filtered out afterwards.
el := list.txs.FirstElement()
if l1Cost := pool.l1CostFn(el.RollupDataGas(), el.IsDepositTx(), el.To()); l1Cost != nil {
balance = new(big.Int).Sub(balance, l1Cost) // negative big int is fine
}
}

// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
drops, invalids := list.Filter(balance, pool.currentMaxGas)
for _, tx := range drops {
Expand Down
91 changes: 13 additions & 78 deletions core/txpool/txpool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,22 @@ type testBlockChain struct {
gasLimit atomic.Uint64
statedb *state.StateDB
chainHeadFeed *event.Feed
basefee *big.Int
}

func newTestBlockChain(gasLimit uint64, statedb *state.StateDB, chainHeadFeed *event.Feed) *testBlockChain {
bc := testBlockChain{statedb: statedb, chainHeadFeed: new(event.Feed)}
bc.gasLimit.Store(gasLimit)
// Set a basefee of 1, avoiding nil pointer dereferences
bc.basefee = big.NewInt(1)
return &bc
}

func (bc *testBlockChain) CurrentBlock() *types.Header {
return &types.Header{
Number: new(big.Int),
GasLimit: bc.gasLimit.Load(),
BaseFee: bc.basefee,
}
}

Expand Down Expand Up @@ -300,6 +304,9 @@ func TestInvalidTransactions(t *testing.T) {

balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice()))
testAddBalance(pool, from, balance)

// set fake token ratio to 1
pool.currentState.SetState(types.GasOracleAddr, types.TokenRatioSlot, common.BigToHash(big.NewInt(1)))
if err := pool.AddRemote(tx); !errors.Is(err, core.ErrIntrinsicGas) {
t.Error("expected", core.ErrIntrinsicGas, "got", err)
}
Expand All @@ -316,8 +323,8 @@ func TestInvalidTransactions(t *testing.T) {
if err := pool.AddRemote(tx); err != ErrUnderpriced {
t.Error("expected", ErrUnderpriced, "got", err)
}
if err := pool.AddLocal(tx); err != nil {
t.Error("expected", nil, "got", err)
if err := pool.AddLocal(tx); err != ErrUnderpriced {
t.Error("expected", ErrUnderpriced, "got", err)
}
}

Expand Down Expand Up @@ -1418,20 +1425,6 @@ func TestRepricing(t *testing.T) {
if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// However we can add local underpriced transactions
tx := pricedTransaction(1, 100000, big.NewInt(1), keys[3])
if err := pool.AddLocal(tx); err != nil {
t.Fatalf("failed to add underpriced local transaction: %v", err)
}
if pending, _ = pool.Stats(); pending != 3 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
}
if err := validateEvents(events, 1); err != nil {
t.Fatalf("post-reprice local event firing failed: %v", err)
}
if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// And we can fill gaps with properly priced transactions
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[0])); err != nil {
t.Fatalf("failed to add pending transaction: %v", err)
Expand Down Expand Up @@ -1542,20 +1535,6 @@ func TestRepricingDynamicFee(t *testing.T) {
if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// However we can add local underpriced transactions
tx = dynamicFeeTx(1, 100000, big.NewInt(1), big.NewInt(1), keys[3])
if err := pool.AddLocal(tx); err != nil {
t.Fatalf("failed to add underpriced local transaction: %v", err)
}
if pending, _ = pool.Stats(); pending != 3 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
}
if err := validateEvents(events, 1); err != nil {
t.Fatalf("post-reprice local event firing failed: %v", err)
}
if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// And we can fill gaps with properly priced transactions
tx = pricedTransaction(1, 100000, big.NewInt(2), keys[0])
if err := pool.AddRemote(tx); err != nil {
Expand Down Expand Up @@ -1598,23 +1577,23 @@ func TestRepricingKeepsLocals(t *testing.T) {
// Create transaction (both pending and queued) with a linearly growing gasprice
for i := uint64(0); i < 500; i++ {
// Add pending transaction.
pendingTx := pricedTransaction(i, 100000, big.NewInt(int64(i)), keys[2])
pendingTx := pricedTransaction(i, 100000, big.NewInt(int64(i+1)), keys[2])
if err := pool.AddLocal(pendingTx); err != nil {
t.Fatal(err)
}
// Add queued transaction.
queuedTx := pricedTransaction(i+501, 100000, big.NewInt(int64(i)), keys[2])
queuedTx := pricedTransaction(i+501, 100000, big.NewInt(int64(i+1)), keys[2])
if err := pool.AddLocal(queuedTx); err != nil {
t.Fatal(err)
}

// Add pending dynamic fee transaction.
pendingTx = dynamicFeeTx(i, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i)), keys[1])
pendingTx = dynamicFeeTx(i, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i+1)), keys[1])
if err := pool.AddLocal(pendingTx); err != nil {
t.Fatal(err)
}
// Add queued dynamic fee transaction.
queuedTx = dynamicFeeTx(i+501, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i)), keys[1])
queuedTx = dynamicFeeTx(i+501, 100000, big.NewInt(int64(i)+1), big.NewInt(int64(i+1)), keys[1])
if err := pool.AddLocal(queuedTx); err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -1739,28 +1718,6 @@ func TestUnderpricing(t *testing.T) {
if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// Ensure that adding local transactions can push out even higher priced ones
ltx = pricedTransaction(1, 100000, big.NewInt(0), keys[2])
if err := pool.AddLocal(ltx); err != nil {
t.Fatalf("failed to append underpriced local transaction: %v", err)
}
ltx = pricedTransaction(0, 100000, big.NewInt(0), keys[3])
if err := pool.AddLocal(ltx); err != nil {
t.Fatalf("failed to add new underpriced local transaction: %v", err)
}
pending, queued = pool.Stats()
if pending != 3 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
}
if queued != 1 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
}
if err := validateEvents(events, 2); err != nil {
t.Fatalf("local event firing failed: %v", err)
}
if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
}

// Tests that more expensive transactions push out cheap ones from the pool, but
Expand Down Expand Up @@ -1916,28 +1873,6 @@ func TestUnderpricingDynamicFee(t *testing.T) {
if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// Ensure that adding local transactions can push out even higher priced ones
ltx = dynamicFeeTx(1, 100000, big.NewInt(0), big.NewInt(0), keys[2])
if err := pool.AddLocal(ltx); err != nil {
t.Fatalf("failed to append underpriced local transaction: %v", err)
}
ltx = dynamicFeeTx(0, 100000, big.NewInt(0), big.NewInt(0), keys[3])
if err := pool.AddLocal(ltx); err != nil {
t.Fatalf("failed to add new underpriced local transaction: %v", err)
}
pending, queued = pool.Stats()
if pending != 3 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3)
}
if queued != 1 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
}
if err := validateEvents(events, 2); err != nil {
t.Fatalf("local event firing failed: %v", err)
}
if err := validatePoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
}

// Tests whether highest fee cap transaction is retained after a batch of high effective
Expand Down

0 comments on commit efd1e22

Please sign in to comment.