Skip to content
Open
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
2 changes: 2 additions & 0 deletions changelog/gligneul-nit-4120.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
### Ignored
- Improve inline comments in retryable precompile
27 changes: 19 additions & 8 deletions precompiles/ArbRetryableTx.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,13 @@ func (con ArbRetryableTx) Redeem(c ctx, evm mech, ticketId bytes32) (bytes32, er
// that amount based on the storage read/write mix used by ShrinkBacklog().
backlogUpdateCost := c.State.L2PricingState().BacklogUpdateCost()

// futureGasCosts contains gas that wasn't charged yet but will be before the end of the transaction.
futureGasCosts := eventCost + gasCostToReturnResult + backlogUpdateCost
if c.GasLeft() < futureGasCosts {
return hash{}, c.Burn(multigas.ResourceKindComputation, futureGasCosts) // this will error
}

// gasToDonate is the remaining gas that will be donated to the retryable execution.
gasToDonate := c.GasLeft() - futureGasCosts
if gasToDonate < params.TxGas {
return hash{}, errors.New("not enough gas to run redeem attempt")
Expand All @@ -126,24 +129,32 @@ func (con ArbRetryableTx) Redeem(c ctx, evm mech, ticketId bytes32) (bytes32, er

// To prepare for the enqueued retry event, we burn gas here, adding it back to the pool right before retrying.
// The gas payer for this tx will get a credit for the wei they paid for this gas when retrying.
// We burn as much gas as we can, leaving only enough to pay for copying out the return data.
if err := c.Burn(multigas.ResourceKindComputation, gasToDonate); err != nil {
// We burn as much compute gas as we can, leaving only enough to pay for copying out the return data.
const donationResource = multigas.ResourceKindComputation
if err := c.Burn(donationResource, gasToDonate); err != nil {
return hash{}, err
}

// Add the gasToDonate back to the gas pool: the retryable attempt will then consume it.
// This ensures that the gas pool has enough gas to run the retryable attempt.
// Starting from ArbosVersion_MultiGasConstraintsVersion, don't charge gas for the ShrinkBacklog call.
stopChargingGas := c.State.L2PricingState().ArbosVersion >= params.ArbosVersion_MultiGasConstraintsVersion
if stopChargingGas {
// Starting from ArbosVersion_MultiGasConstraintsVersion, charge a fixed amount of gas for the ShrinkBacklog
// call because multi-gas constraints may have multiple backlogs and it would be too expensive to the user.
// Since these backlogs are manipulated by the system in every transaction, they are already fresh in cache and
// we don't need to penalize the user.
chargeFixedAmount := c.State.L2PricingState().ArbosVersion >= params.ArbosVersion_MultiGasConstraintsVersion
if chargeFixedAmount {
// Manually charge the fixed amount.
if err := c.Burn(multigas.ResourceKindComputation, l2pricing.MultiConstraintStaticBacklogUpdateCost); err != nil {
return hash{}, err
}

// Disable metering from now own, turning it back at the end of the function.
c.SetUnmeteredGasAccounting(true)
defer c.SetUnmeteredGasAccounting(false)
}
return retryTxHash, c.State.L2PricingState().ShrinkBacklog(gasToDonate, multigas.ComputationGas(gasToDonate))

// Shrink the computation backlog because the transaction didn't use these resources.
// Later, the retryable attempt will use this gas and increase the resource-backlogs it actually uses.
// This ensures we don't increase the L2 base fee unnecessarily.
return retryTxHash, c.State.L2PricingState().ShrinkBacklog(gasToDonate, multigas.NewMultiGas(donationResource, gasToDonate))
}

// GetLifetime gets the default lifetime period a retryable has at creation
Expand Down
Loading