Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions arbos/l1pricing/l1pricing.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ func (ps *L1PricingState) SetAggregatorCompressionRatio(aggregator common.Addres
func (ps *L1PricingState) AddPosterInfo(tx *types.Transaction, sender, poster common.Address) {

tx.PosterCost = big.NewInt(0)
tx.PosterIsReimbursable = false

aggregator, perr := ps.ReimbursableAggregatorForSender(sender)
txBytes, merr := tx.MarshalBinary()
Expand All @@ -259,19 +258,18 @@ func (ps *L1PricingState) AddPosterInfo(tx *types.Transaction, sender, poster co
ratio, _ := ps.AggregatorCompressionRatio(poster)
adjustedL1Fee := arbmath.BigMulByBips(l1Fee, ratio)

tx.PosterIsReimbursable = true
tx.PosterCost = adjustedL1Fee
}

const TxFixedCost = 140 // assumed maximum size in bytes of a typical RLP-encoded tx, not including its calldata

func (ps *L1PricingState) PosterDataCost(message core.Message, sender, poster common.Address) (*big.Int, bool) {
func (ps *L1PricingState) PosterDataCost(message core.Message, sender, poster common.Address) *big.Int {

if tx := message.UnderlyingTransaction(); tx != nil {
if tx.PosterCost == nil {
ps.AddPosterInfo(tx, sender, poster)
}
return tx.PosterCost, tx.PosterIsReimbursable
return tx.PosterCost
}

if message.RunMode() == types.MessageGasEstimationMode {
Expand All @@ -281,14 +279,14 @@ func (ps *L1PricingState) PosterDataCost(message core.Message, sender, poster co
poster = *aggregator
} else {
// assume the user will use the delayed inbox since there's no reimbursable party
return big.NewInt(0), false
return big.NewInt(0)
}
}

byteCount, err := byteCountAfterBrotli0(message.Data())
if err != nil {
log.Error("failed to compress tx", "err", err)
return big.NewInt(0), false
return big.NewInt(0)
}

// Approximate the l1 fee charged for posting this tx's calldata
Expand All @@ -299,7 +297,7 @@ func (ps *L1PricingState) PosterDataCost(message core.Message, sender, poster co

// Adjust the price paid by the aggregator's reported improvements due to batching
ratio, _ := ps.AggregatorCompressionRatio(poster)
return arbmath.BigMulByBips(l1Fee, ratio), true
return arbmath.BigMulByBips(l1Fee, ratio)
}

func byteCountAfterBrotli0(input []byte) (uint64, error) {
Expand Down
20 changes: 4 additions & 16 deletions arbos/tx_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ func (p *TxProcessor) PopCaller() {
p.Callers = p.Callers[:len(p.Callers)-1]
}

func (p *TxProcessor) DropTip() bool {
return p.state.FormatVersion() >= 2
}

func (p *TxProcessor) StartTxHook() (endTxNow bool, gasUsed uint64, err error, returnData []byte) {
// This hook is called before gas charging and will end the state transition if endTxNow is set to true
// Hence, we must charge for any l2 resources if endTxNow is returned true
Expand Down Expand Up @@ -246,15 +242,15 @@ func (p *TxProcessor) StartTxHook() (endTxNow bool, gasUsed uint64, err error, r
return false, 0, nil, nil
}

func (p *TxProcessor) GasChargingHook(gasRemaining *uint64) (*common.Address, error) {
func (p *TxProcessor) GasChargingHook(gasRemaining *uint64) error {
// Because a user pays a 1-dimensional gas price, we must re-express poster L1 calldata costs
// as if the user was buying an equivalent amount of L2 compute gas. This hook determines what
// that cost looks like, ensuring the user can pay and saving the result for later reference.

var gasNeededToStartEVM uint64
gasPrice := p.evm.Context.BaseFee
coinbase := p.evm.Context.Coinbase
posterCost, reimburse := p.state.L1PricingState().PosterDataCost(p.msg, p.msg.From(), coinbase)
posterCost := p.state.L1PricingState().PosterDataCost(p.msg, p.msg.From(), coinbase)

if p.msg.RunMode() == types.MessageGasEstimationMode {
// Suggest the amount of gas needed for a given amount of ETH is higher in case of congestion.
Expand Down Expand Up @@ -282,16 +278,9 @@ func (p *TxProcessor) GasChargingHook(gasRemaining *uint64) (*common.Address, er
gasNeededToStartEVM = p.posterGas
}

// Most users shouldn't set a tip, but if specified only give it to the poster if they're reimbursable
tipRecipient := &coinbase
if !reimburse {
networkFeeAccount, _ := p.state.NetworkFeeAccount()
tipRecipient = &networkFeeAccount
}

if *gasRemaining < gasNeededToStartEVM {
// the user couldn't pay for call data, so give up
return tipRecipient, core.ErrIntrinsicGas
return core.ErrIntrinsicGas
}
*gasRemaining -= gasNeededToStartEVM

Expand All @@ -304,8 +293,7 @@ func (p *TxProcessor) GasChargingHook(gasRemaining *uint64) (*common.Address, er
*gasRemaining = gasAvailable
}
}

return tipRecipient, nil
return nil
}

func (p *TxProcessor) NonrefundableGas() uint64 {
Expand Down
7 changes: 1 addition & 6 deletions docs/arbos/Gas.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,7 @@ Though subject to change when batch-compression pricing is fully implemented, [t
[drop_l1_link]: https://github.com/OffchainLabs/nitro/blob/2ba6d1aa45abcc46c28f3d4f560691ce5a396af8/arbos/l1pricing/l1pricing.go#L232

## Tips in L2
While tips are not advised for those using the sequencer, which prioritizes transactions on a first-come first-served basis, 3rd-party aggregators may choose to order txes based on tips. A user specifies a tip by setting a gas price in excess of the basefee and will [pay that difference][pay_difference_link] on the amount of gas the tx uses.

A poster receives the tip only when the user has set them as their [preferred aggregator](Precompiles.md#ArbAggregator). Otherwise the tip [goes to the network fee collector][goes_to_network_link]. This disincentives unpreferred aggregators from racing to post txes with large tips.

[pay_difference_link]: https://github.com/OffchainLabs/go-ethereum/blob/edf6a19157606070b6a6660c8decc513e2408cb7/core/state_transition.go#L358
[goes_to_network_link]: https://github.com/OffchainLabs/nitro/blob/c93c806a5cfe99f92a534d3c952a83c3c8b3088c/arbos/tx_processor.go#L262
The sequencer prioritizes transactions on a first-come first-served basis. Because tips do not make sense in this model, they are ignored. Arbitrum users always just pay the basefee regardless of the tip they choose.

## Gas Estimating Retryables
When a transaction schedules another, the subsequent tx's execution [will be included][estimation_inclusion_link] when estimating gas via the node's RPC. A tx's gas estimate, then, can only be found if all the txes succeed at a given gas limit. This is especially important when working with retryables and scheduling redeem attempts.
Expand Down
2 changes: 1 addition & 1 deletion go-ethereum
2 changes: 1 addition & 1 deletion nodeInterface/virtual-contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func init() {
// if gas is free or there's no reimbursable poster, the user won't pay for L1 data costs
return
}
posterCost, _ := state.L1PricingState().PosterDataCost(msg, msg.From(), *poster)
posterCost := state.L1PricingState().PosterDataCost(msg, msg.From(), *poster)
posterCostInL2Gas := arbmath.BigToUintSaturating(arbmath.BigDiv(posterCost, header.BaseFee))
*gascap = arbmath.SaturatingUAdd(*gascap, posterCostInL2Gas)
}
Expand Down