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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pragma solidity >=0.8.27;

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

// We are using a type instead of a struct as we don't want to throw away a full 8 bits
Expand Down Expand Up @@ -102,13 +103,14 @@ library FeeHeaderLib {
function compress(FeeHeader memory _feeHeader) internal pure returns (CompressedFeeHeader) {
uint256 value = 0;
value |= uint256(_feeHeader.manaUsed.toUint32());
value |= uint256(_feeHeader.excessMana.toUint48()) << 32;
// Cap excessMana to uint48 max to prevent overflow during compression.
value |= Math.min(_feeHeader.excessMana, MASK_48_BITS) << 32;
value |= uint256(_feeHeader.ethPerFeeAsset.toUint48()) << 80;
value |= uint256(_feeHeader.congestionCost.toUint64()) << 128;

uint256 proverCost = uint256(_feeHeader.proverCost.toUint64());
require(proverCost == proverCost & MASK_63_BITS);
value |= proverCost << 192;
// Cap congestionCost to uint64 max to prevent overflow during compression.
// The uncapped value is still used for fee validation; this only affects storage.
value |= Math.min(_feeHeader.congestionCost, MASK_64_BITS) << 128;
// Cap proverCost to uint63 max to prevent overflow during compression.
value |= Math.min(_feeHeader.proverCost, MASK_63_BITS) << 192;

// Preheat
value |= 1 << 255;
Expand Down
11 changes: 9 additions & 2 deletions l1-contracts/src/core/libraries/rollup/FeeLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,11 @@ library FeeLib {

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

function computeManaLimit(uint256 _manaTarget) internal pure returns (uint256) {
Expand Down Expand Up @@ -342,7 +346,10 @@ library FeeLib {
}

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

function getStorage() internal pure returns (FeeStore storage storageStruct) {
Expand Down
Loading
Loading