Skip to content

Commit a663b2b

Browse files
committed
fix: fee related overflows
1 parent f4675e8 commit a663b2b

File tree

3 files changed

+353
-7
lines changed

3 files changed

+353
-7
lines changed

l1-contracts/src/core/libraries/compressed-data/fees/FeeStructs.sol

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pragma solidity >=0.8.27;
44

55
import {CompressedSlot} from "@aztec/shared/libraries/CompressedTimeMath.sol";
6+
import {Math} from "@oz/utils/math/Math.sol";
67
import {SafeCast} from "@oz/utils/math/SafeCast.sol";
78

89
// We are using a type instead of a struct as we don't want to throw away a full 8 bits
@@ -104,11 +105,11 @@ library FeeHeaderLib {
104105
value |= uint256(_feeHeader.manaUsed.toUint32());
105106
value |= uint256(_feeHeader.excessMana.toUint48()) << 32;
106107
value |= uint256(_feeHeader.ethPerFeeAsset.toUint48()) << 80;
107-
value |= uint256(_feeHeader.congestionCost.toUint64()) << 128;
108-
109-
uint256 proverCost = uint256(_feeHeader.proverCost.toUint64());
110-
require(proverCost == proverCost & MASK_63_BITS);
111-
value |= proverCost << 192;
108+
// Cap congestionCost to uint64 max to prevent overflow during compression.
109+
// The uncapped value is still used for fee validation; this only affects storage.
110+
value |= Math.min(_feeHeader.congestionCost, MASK_64_BITS) << 128;
111+
// Cap proverCost to uint63 max to prevent overflow during compression.
112+
value |= Math.min(_feeHeader.proverCost, MASK_63_BITS) << 192;
112113

113114
// Preheat
114115
value |= 1 << 255;

l1-contracts/src/core/libraries/rollup/FeeLib.sol

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,11 @@ library FeeLib {
309309

310310
function congestionMultiplier(uint256 _numerator) internal view returns (uint256) {
311311
FeeStore storage feeStore = getStorage();
312-
return fakeExponential(MINIMUM_CONGESTION_MULTIPLIER, _numerator, feeStore.config.getCongestionUpdateFraction());
312+
uint256 denominator = feeStore.config.getCongestionUpdateFraction();
313+
// Cap the exponent to prevent overflow in the Taylor series.
314+
// At e^100, the multiplier is ~2.69e43 * MINIMUM_CONGESTION_MULTIPLIER, more than enough
315+
uint256 cappedNumerator = Math.min(_numerator, denominator * 100);
316+
return fakeExponential(MINIMUM_CONGESTION_MULTIPLIER, cappedNumerator, denominator);
313317
}
314318

315319
function computeManaLimit(uint256 _manaTarget) internal pure returns (uint256) {
@@ -342,7 +346,12 @@ library FeeLib {
342346
}
343347

344348
function summedMinFee(ManaMinFeeComponents memory _components) internal pure returns (uint256) {
345-
return _components.sequencerCost + _components.proverCost + _components.congestionCost;
349+
// Cap at uint128 max to ensure the fee can always be represented in the proposal header's
350+
// feePerL2Gas field (uint128). Without this cap, extreme congestion or parameter combinations
351+
// could produce fees that no valid header can represent, causing a liveness failure.
352+
return Math.min(
353+
_components.sequencerCost + _components.proverCost + _components.congestionCost, type(uint128).max
354+
);
346355
}
347356

348357
function getStorage() internal pure returns (FeeStore storage storageStruct) {

0 commit comments

Comments
 (0)