Skip to content

Commit

Permalink
Merge 4bb9957 into 2478d19
Browse files Browse the repository at this point in the history
  • Loading branch information
LHerskind authored Nov 27, 2024
2 parents 2478d19 + 4bb9957 commit a8efa40
Show file tree
Hide file tree
Showing 10 changed files with 378 additions and 142 deletions.
111 changes: 72 additions & 39 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
FeeHeader,
ManaBaseFeeComponents,
BlockLog,
L1FeeData
L1FeeData,
SubmitEpochRootProofArgs
} from "@aztec/core/interfaces/IRollup.sol";
import {IVerifier} from "@aztec/core/interfaces/IVerifier.sol";
import {IInbox} from "@aztec/core/interfaces/messagebridge/IInbox.sol";
Expand Down Expand Up @@ -51,6 +52,13 @@ struct Config {
uint256 aztecEpochProofClaimWindowInL2Slots;
}

struct SubmitEpochRootProofInterimValues {
uint256 previousBlockNumber;
uint256 endBlockNumber;
Epoch epochToProve;
Epoch startEpoch;
}

/**
* @title Rollup
* @author Aztec Labs
Expand All @@ -64,6 +72,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
using SafeERC20 for IERC20;
using ProposeLib for ProposeArgs;
using FeeMath for uint256;
using FeeMath for ManaBaseFeeComponents;

struct L1GasOracleValues {
L1FeeData pre;
Expand All @@ -81,6 +90,10 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
// for justification of CLAIM_DURATION_IN_L2_SLOTS.
uint256 public constant PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST = 1000;

// A Cuauhxicalli [kʷaːʍʃiˈkalːi] ("eagle gourd bowl") is a ceremonial Aztec vessel or altar used to hold offerings,
// such as sacrificial hearts, during rituals performed within temples.
address public constant CUAUHXICALLI = address(bytes20("CUAUHXICALLI"));

address public constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
bool public immutable IS_FOUNDRY_TEST;

Expand Down Expand Up @@ -154,7 +167,8 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
excessMana: 0,
feeAssetPriceNumerator: 0,
manaUsed: 0,
provingCostPerManaNumerator: 0
provingCostPerManaNumerator: 0,
congestionCost: 0
}),
archive: bytes32(Constants.GENESIS_ARCHIVE_ROOT),
blockHash: bytes32(0), // TODO(palla/prover): The first block does not have hash zero
Expand Down Expand Up @@ -263,55 +277,71 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
* @dev We provide the `_archive` and `_blockHash` even if it could be read from storage itself because it allow for
* better error messages. Without passing it, we would just have a proof verification failure.
*
* @param _epochSize - The size of the epoch (to be promoted to a constant)
* @param _args - Array of public inputs to the proof (previousArchive, endArchive, previousBlockHash, endBlockHash, endTimestamp, outHash, proverId)
* @param _fees - Array of recipient-value pairs with fees to be distributed for the epoch
* @param _aggregationObject - The aggregation object for the proof
* @param _proof - The proof to verify
* @param _args - The arguments to submit the epoch root proof:
* _epochSize - The size of the epoch (to be promoted to a constant)
* _args - Array of public inputs to the proof (previousArchive, endArchive, previousBlockHash, endBlockHash, endTimestamp, outHash, proverId)
* _fees - Array of recipient-value pairs with fees to be distributed for the epoch
* _aggregationObject - The aggregation object for the proof
* _proof - The proof to verify
*/
function submitEpochRootProof(
uint256 _epochSize,
bytes32[7] calldata _args,
bytes32[] calldata _fees,
bytes calldata _aggregationObject,
bytes calldata _proof
) external override(IRollup) {
function submitEpochRootProof(SubmitEpochRootProofArgs calldata _args) external override(IRollup) {
if (canPrune()) {
_prune();
}

uint256 previousBlockNumber = tips.provenBlockNumber;
uint256 endBlockNumber = previousBlockNumber + _epochSize;
SubmitEpochRootProofInterimValues memory interimValues;

interimValues.previousBlockNumber = tips.provenBlockNumber;
interimValues.endBlockNumber = interimValues.previousBlockNumber + _args.epochSize;

// @note The getEpochForBlock is expected to revert if the block is beyond pending.
// If this changes you are gonna get so rekt you won't believe it.
// I mean proving blocks that have been pruned rekt.
Epoch epochToProve = getEpochForBlock(endBlockNumber);
interimValues.epochToProve = getEpochForBlock(interimValues.endBlockNumber);
interimValues.startEpoch = getEpochForBlock(interimValues.previousBlockNumber + 1);

// Ensure that the proof is not across epochs
require(
interimValues.startEpoch == interimValues.epochToProve,
Errors.Rollup__InvalidEpoch(interimValues.startEpoch, interimValues.epochToProve)
);

bytes32[] memory publicInputs =
getEpochProofPublicInputs(_epochSize, _args, _fees, _aggregationObject);
getEpochProofPublicInputs(_args.epochSize, _args.args, _args.fees, _args.aggregationObject);

require(epochProofVerifier.verify(_args.proof, publicInputs), Errors.Rollup__InvalidProof());

require(epochProofVerifier.verify(_proof, publicInputs), Errors.Rollup__InvalidProof());
if (proofClaim.epochToProve == interimValues.epochToProve) {
PROOF_COMMITMENT_ESCROW.unstakeBond(proofClaim.bondProvider, proofClaim.bondAmount);
}

tips.provenBlockNumber = endBlockNumber;
tips.provenBlockNumber = interimValues.endBlockNumber;

// @note Only if the rollup is the canonical will it be able to meaningfully claim fees
// Otherwise, the fees are unbacked #7938.
bool isFeeCanonical = address(this) == FEE_JUICE_PORTAL.canonicalRollup();
bool isRewardDistributorCanonical = address(this) == REWARD_DISTRIBUTOR.canonicalRollup();

uint256 totalProverReward = 0;
uint256 totalBurn = 0;

if (isFeeCanonical || isRewardDistributorCanonical) {
for (uint256 i = 0; i < _epochSize; i++) {
for (uint256 i = 0; i < _args.epochSize; i++) {
address coinbase = address(uint160(uint256(publicInputs[9 + i * 2])));
uint256 reward = 0;
uint256 toProver = 0;
uint256 burn = 0;

if (isFeeCanonical) {
uint256 fees = uint256(publicInputs[10 + i * 2]);
if (fees > 0) {
reward += fees;
// This is insanely expensive, and will be fixed as part of the general storage cost reduction.
// See #9826.
FeeHeader storage feeHeader =
blocks[interimValues.previousBlockNumber + 1 + i].feeHeader;
burn += feeHeader.congestionCost * feeHeader.manaUsed;

reward += (fees - burn);
FEE_JUICE_PORTAL.distributeFees(address(this), fees);
}
}
Expand All @@ -335,6 +365,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
}

totalProverReward += toProver;
totalBurn += burn;
}

if (totalProverReward > 0) {
Expand All @@ -343,13 +374,13 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
proofClaim.bondProvider == address(0) ? msg.sender : proofClaim.bondProvider;
ASSET.safeTransfer(proofRewardRecipient, totalProverReward);
}
}

if (proofClaim.epochToProve == epochToProve) {
PROOF_COMMITMENT_ESCROW.unstakeBond(proofClaim.bondProvider, proofClaim.bondAmount);
if (totalBurn > 0) {
ASSET.safeTransfer(CUAUHXICALLI, totalBurn);
}
}

emit L2ProofVerified(endBlockNumber, _args[6]);
emit L2ProofVerified(interimValues.endBlockNumber, _args.args[6]);
}

function status(uint256 _myHeaderBlockNumber)
Expand Down Expand Up @@ -520,13 +551,13 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
// Decode and validate header
HeaderLib.Header memory header = HeaderLib.decode(_args.header);

bytes32 digest = _args.digest();
setupEpoch();
uint256 manaBaseFee = getManaBaseFee(true);
ManaBaseFeeComponents memory components = getManaBaseFeeComponents(true);
uint256 manaBaseFee = FeeMath.summedBaseFee(components);
_validateHeader({
_header: header,
_signatures: _signatures,
_digest: digest,
_digest: _args.digest(),
_currentTime: Timestamp.wrap(block.timestamp),
_manaBaseFee: manaBaseFee,
_txEffectsHash: txsEffectsHash,
Expand All @@ -553,17 +584,20 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
manaUsed: header.totalManaUsed,
provingCostPerManaNumerator: parentFeeHeader.provingCostPerManaNumerator.clampedAdd(
_args.oracleInput.provingCostModifier
)
),
congestionCost: components.congestionCost
})
});
}

// @note The block number here will always be >=1 as the genesis block is at 0
bytes32 inHash = INBOX.consume(blockNumber);
require(
header.contentCommitment.inHash == inHash,
Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash)
);
{
bytes32 inHash = INBOX.consume(blockNumber);
require(
header.contentCommitment.inHash == inHash,
Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash)
);
}

// TODO(#7218): Revert to fixed height tree for outbox, currently just providing min as interim
// Min size = smallest path of the rollup tree + 1
Expand Down Expand Up @@ -644,9 +678,8 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
* @return The mana base fee
*/
function getManaBaseFee(bool _inFeeAsset) public view override(IRollup) returns (uint256) {
ManaBaseFeeComponents memory components = manaBaseFeeComponents(_inFeeAsset);
return
components.dataCost + components.gasCost + components.provingCost + components.congestionCost;
ManaBaseFeeComponents memory components = getManaBaseFeeComponents(_inFeeAsset);
return components.summedBaseFee();
}

/**
Expand All @@ -661,7 +694,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
*
* @return The mana base fee components
*/
function manaBaseFeeComponents(bool _inFeeAsset)
function getManaBaseFeeComponents(bool _inFeeAsset)
public
view
override(ITestRollup)
Expand Down
28 changes: 12 additions & 16 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@ import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol";
import {SignatureLib} from "@aztec/core/libraries/crypto/SignatureLib.sol";
import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
import {EpochProofQuoteLib} from "@aztec/core/libraries/EpochProofQuoteLib.sol";
import {ManaBaseFeeComponents} from "@aztec/core/libraries/FeeMath.sol";
import {ProposeArgs} from "@aztec/core/libraries/ProposeLib.sol";
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";

struct SubmitEpochRootProofArgs {
uint256 epochSize;
bytes32[7] args;
bytes32[] fees;
bytes aggregationObject;
bytes proof;
}

struct FeeHeader {
uint256 excessMana;
uint256 feeAssetPriceNumerator;
uint256 manaUsed;
uint256 provingCostPerManaNumerator;
uint256 congestionCost;
}

struct BlockLog {
Expand All @@ -29,20 +39,12 @@ struct L1FeeData {
uint256 blobFee;
}

struct ManaBaseFeeComponents {
uint256 congestionCost;
uint256 congestionMultiplier;
uint256 dataCost;
uint256 gasCost;
uint256 provingCost;
}

interface ITestRollup {
function setEpochVerifier(address _verifier) external;
function setVkTreeRoot(bytes32 _vkTreeRoot) external;
function setProtocolContractTreeRoot(bytes32 _protocolContractTreeRoot) external;
function setAssumeProvenThroughBlockNumber(uint256 _blockNumber) external;
function manaBaseFeeComponents(bool _inFeeAsset)
function getManaBaseFeeComponents(bool _inFeeAsset)
external
view
returns (ManaBaseFeeComponents memory);
Expand Down Expand Up @@ -78,13 +80,7 @@ interface IRollup {
EpochProofQuoteLib.SignedEpochProofQuote calldata _quote
) external;

function submitEpochRootProof(
uint256 _epochSize,
bytes32[7] calldata _args,
bytes32[] calldata _fees,
bytes calldata _aggregationObject,
bytes calldata _proof
) external;
function submitEpochRootProof(SubmitEpochRootProofArgs calldata _args) external;

function canProposeAtTime(Timestamp _ts, bytes32 _archive) external view returns (Slot, uint256);

Expand Down
13 changes: 13 additions & 0 deletions l1-contracts/src/core/libraries/FeeMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ struct OracleInput {
int256 feeAssetPriceModifier;
}

struct ManaBaseFeeComponents {
uint256 congestionCost;
uint256 congestionMultiplier;
uint256 dataCost;
uint256 gasCost;
uint256 provingCost;
}

library FeeMath {
using Math for uint256;
using SafeCast for int256;
Expand Down Expand Up @@ -81,6 +89,11 @@ library FeeMath {
return fakeExponential(MINIMUM_CONGESTION_MULTIPLIER, _numerator, CONGESTION_UPDATE_FRACTION);
}

function summedBaseFee(ManaBaseFeeComponents memory _components) internal pure returns (uint256) {
return _components.dataCost + _components.gasCost + _components.provingCost
+ _components.congestionCost;
}

/**
* @notice An approximation of the exponential function: factor * e ** (numerator / denominator)
*
Expand Down
Loading

0 comments on commit a8efa40

Please sign in to comment.