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
2 changes: 1 addition & 1 deletion .github/workflows/devnet-deploys.yml
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ jobs:
# working-directory: ./yarn-project/aztec/terraform/pxe
# run: |
# set -eo pipefail
# docker run aztecprotocol/aztec:${{ env.DEPLOY_TAG }} set-proven-until \
# docker run aztecprotocol/aztec:${{ env.DEPLOY_TAG }} set-proven-through \
# --rpc-url https://api.aztec.network/${{ env.DEPLOY_TAG }}/aztec-pxe/${{ env.API_KEY }} \
# --l1-rpc-url https://${{ env.DEPLOY_TAG }}-mainnet-fork.aztec.network:8545/admin-${{ env.FORK_ADMIN_API_KEY }} \
# --l1-chain-id ${{ env.L1_CHAIN_ID }} \
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.provernet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ services:
SEQ_PUBLISHER_PRIVATE_KEY: "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a"
VALIDATOR_PRIVATE_KEY: "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a"
PROVER_REAL_PROOFS: "${PROVER_REAL_PROOFS:-false}"
ASSUME_PROVEN_UNTIL_BLOCK_NUMBER: "${ASSUME_PROVEN_UNTIL_BLOCK_NUMBER:-4}"
ASSUME_PROVEN_THROUGH_BLOCK_NUMBER: "${ASSUME_PROVEN_THROUGH_BLOCK_NUMBER:-4}"
P2P_ENABLED: false
IS_DEV_NET: true
volumes:
Expand Down Expand Up @@ -104,7 +104,7 @@ services:
PROVER_AGENT_ENABLED: false
PROVER_PUBLISHER_PRIVATE_KEY: "0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97"
PROVER_REAL_PROOFS: "${PROVER_REAL_PROOFS:-false}"
ASSUME_PROVEN_UNTIL_BLOCK_NUMBER: "${ASSUME_PROVEN_UNTIL_BLOCK_NUMBER:-4}"
ASSUME_PROVEN_THROUGH_BLOCK_NUMBER: "${ASSUME_PROVEN_THROUGH_BLOCK_NUMBER:-4}"
IS_DEV_NET: true
volumes:
- ./log/aztec-prover/:/usr/src/yarn-project/aztec/log:rw
Expand Down
114 changes: 61 additions & 53 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ import {Leonidas} from "./sequencer_selection/Leonidas.sol";
contract Rollup is Leonidas, IRollup, ITestRollup {
using SafeCast for uint256;

struct ChainTips {
uint256 pendingBlockNumber;
uint256 provenBlockNumber;
}

struct BlockLog {
bytes32 archive;
bytes32 blockHash;
Expand All @@ -52,11 +57,9 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
IOutbox public immutable OUTBOX;
uint256 public immutable VERSION;
IFeeJuicePortal public immutable FEE_JUICE_PORTAL;

IVerifier public verifier;

uint256 public pendingBlockCount;
uint256 public provenBlockCount;
ChainTips public tips;

// @todo Validate assumption:
// Currently we assume that the archive root following a block is specific to the block
Expand All @@ -67,9 +70,9 @@ contract Rollup is Leonidas, IRollup, ITestRollup {

bytes32 public vkTreeRoot;

// @note Assume that all blocks up to this value are automatically proven. Speeds up bootstrapping.
// @note Assume that all blocks up to this value (inclusive) are automatically proven. Speeds up bootstrapping.
// Testing only. This should be removed eventually.
uint256 private assumeProvenUntilBlockNumber;
uint256 private assumeProvenThroughBlockNumber;

constructor(
IRegistry _registry,
Expand All @@ -93,9 +96,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
blockHash: bytes32(0),
slotNumber: 0
});
pendingBlockCount = 1;
provenBlockCount = 1;

for (uint256 i = 0; i < _validators.length; i++) {
_addValidator(_validators[i]);
}
Expand All @@ -110,11 +110,11 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
* @dev While in devnet, this will be guarded behind an `onlyOwner`
*/
function prune() external override(IRollup) onlyOwner {
if (pendingBlockCount == provenBlockCount) {
if (tips.pendingBlockNumber == tips.provenBlockNumber) {
revert Errors.Rollup__NothingToPrune();
}

BlockLog storage firstPendingNotInProven = blocks[provenBlockCount];
BlockLog storage firstPendingNotInProven = blocks[tips.provenBlockNumber + 1];
uint256 prunableAtSlot =
uint256(firstPendingNotInProven.slotNumber) + TIMELINESS_PROVING_IN_SLOTS;
uint256 currentSlot = getCurrentSlot();
Expand All @@ -123,29 +123,30 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
revert Errors.Rollup__NotReadyToPrune(currentSlot, prunableAtSlot);
}

// @note We are not deleting the blocks, but we are "winding back" the pendingBlockCount
// to the last block that was proven.
// The reason we can do this, is that any new block proposed will overwrite a previous block
// so no values should "survive". It it is however slightly odd for people reading
// the chain separately from the contract without using pendingBlockCount as a boundary.
pendingBlockCount = provenBlockCount;
uint256 pending = tips.pendingBlockNumber;

emit PrunedPending(provenBlockCount, pendingBlockCount);
// @note We are not deleting the blocks, but we are "winding back" the pendingTip to the last block that was proven.
// We can do because any new block proposed will overwrite a previous block in the block log,
// so no values should "survive".
// People must therefore read the chain using the pendingTip as a boundary.
tips.pendingBlockNumber = tips.provenBlockNumber;

emit PrunedPending(tips.provenBlockNumber, pending);
}

/**
* Sets the assumeProvenUntilBlockNumber. Only the contract deployer can set it.
* Sets the assumeProvenThroughBlockNumber. Only the contract deployer can set it.
* @param blockNumber - New value.
*/
function setAssumeProvenUntilBlockNumber(uint256 blockNumber)
function setAssumeProvenThroughBlockNumber(uint256 blockNumber)
external
override(ITestRollup)
onlyOwner
{
if (blockNumber > provenBlockCount && blockNumber <= pendingBlockCount) {
provenBlockCount = blockNumber;
if (blockNumber > tips.provenBlockNumber && blockNumber <= tips.pendingBlockNumber) {
tips.provenBlockNumber = blockNumber;
}
assumeProvenUntilBlockNumber = blockNumber;
assumeProvenThroughBlockNumber = blockNumber;
}

/**
Expand All @@ -170,15 +171,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
vkTreeRoot = _vkTreeRoot;
}

function computeTxsEffectsHash(bytes calldata _body)
external
pure
override(IRollup)
returns (bytes32)
{
return TxsDecoder.decode(_body);
}

/**
* @notice Publishes the body and propose the block
* @dev `eth_log_handlers` rely on this function
Expand Down Expand Up @@ -213,14 +205,16 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
_flags: DataStructures.ExecutionFlags({ignoreDA: false, ignoreSignatures: false})
});

blocks[pendingBlockCount++] = BlockLog({
uint256 blockNumber = ++tips.pendingBlockNumber;

blocks[blockNumber] = BlockLog({
archive: _archive,
blockHash: _blockHash,
slotNumber: header.globalVariables.slotNumber.toUint128()
});

// @note The block number here will always be >=1 as the genesis block is at 0
bytes32 inHash = INBOX.consume(header.globalVariables.blockNumber);
bytes32 inHash = INBOX.consume(blockNumber);
if (header.contentCommitment.inHash != inHash) {
revert Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash);
}
Expand All @@ -229,15 +223,13 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
// Min size = smallest path of the rollup tree + 1
(uint256 min,) = MerkleLib.computeMinMaxPathLength(header.contentCommitment.numTxs);
uint256 l2ToL1TreeMinHeight = min + 1;
OUTBOX.insert(
header.globalVariables.blockNumber, header.contentCommitment.outHash, l2ToL1TreeMinHeight
);
OUTBOX.insert(blockNumber, header.contentCommitment.outHash, l2ToL1TreeMinHeight);

emit L2BlockProposed(header.globalVariables.blockNumber);
emit L2BlockProposed(blockNumber);

// Automatically flag the block as proven if we have cheated and set assumeProvenUntilBlockNumber.
if (header.globalVariables.blockNumber < assumeProvenUntilBlockNumber) {
provenBlockCount += 1;
// Automatically flag the block as proven if we have cheated and set assumeProvenThroughBlockNumber.
if (blockNumber <= assumeProvenThroughBlockNumber) {
tips.provenBlockNumber = blockNumber;

if (header.globalVariables.coinbase != address(0) && header.totalFees > 0) {
// @note This will currently fail if there are insufficient funds in the bridge
Expand All @@ -246,7 +238,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
FEE_JUICE_PORTAL.distributeFees(header.globalVariables.coinbase, header.totalFees);
}

emit L2ProofVerified(header.globalVariables.blockNumber, "CHEAT");
emit L2ProofVerified(blockNumber, "CHEAT");
}
}

Expand Down Expand Up @@ -283,20 +275,19 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
) external override(IRollup) {
HeaderLib.Header memory header = HeaderLib.decode(_header);

if (header.globalVariables.blockNumber >= pendingBlockCount) {
if (header.globalVariables.blockNumber > tips.pendingBlockNumber) {
revert Errors.Rollup__TryingToProveNonExistingBlock();
}

// @note This implicitly also ensures that we have not already proven, since
// the value `provenBlockCount` is incremented at the end of this function
if (header.globalVariables.blockNumber != provenBlockCount) {
// the value `tips.provenBlockNumber` is incremented at the end of this function
if (header.globalVariables.blockNumber != tips.provenBlockNumber + 1) {
revert Errors.Rollup__NonSequentialProving();
}

bytes32 expectedLastArchive = blocks[header.globalVariables.blockNumber - 1].archive;
// We do it this way to provide better error messages than passing along the storage values
// TODO(#4148) Proper genesis state. If the state is empty, we allow anything for now.
if (expectedLastArchive != bytes32(0) && header.lastArchive.root != expectedLastArchive) {
if (header.lastArchive.root != expectedLastArchive) {
revert Errors.Rollup__InvalidArchive(expectedLastArchive, header.lastArchive.root);
}

Expand Down Expand Up @@ -375,7 +366,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
revert Errors.Rollup__InvalidProof();
}

provenBlockCount += 1;
tips.provenBlockNumber = header.globalVariables.blockNumber;

for (uint256 i = 0; i < 32; i++) {
address coinbase = address(uint160(uint256(publicInputs[25 + i * 2])));
Expand Down Expand Up @@ -419,7 +410,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
{
uint256 slot = getSlotAt(_ts);

uint256 lastSlot = uint256(blocks[pendingBlockCount - 1].slotNumber);
uint256 lastSlot = uint256(blocks[tips.pendingBlockNumber].slotNumber);
if (slot <= lastSlot) {
revert Errors.Rollup__SlotAlreadyInChain(lastSlot, slot);
}
Expand All @@ -435,7 +426,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
DataStructures.ExecutionFlags({ignoreDA: true, ignoreSignatures: true});
_validateLeonidas(slot, sigs, _archive, flags);

return (slot, pendingBlockCount);
return (slot, tips.pendingBlockNumber + 1);
}

/**
Expand All @@ -462,13 +453,30 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
_validateHeader(header, _signatures, _digest, _currentTime, _txsEffectsHash, _flags);
}

function computeTxsEffectsHash(bytes calldata _body)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get my linter to stop yelling at me with respect to ordering of external vs external pure

external
pure
override(IRollup)
returns (bytes32)
{
return TxsDecoder.decode(_body);
}

/**
* @notice Get the current archive root
*
* @return bytes32 - The current archive root
*/
function archive() public view override(IRollup) returns (bytes32) {
return blocks[pendingBlockCount - 1].archive;
return blocks[tips.pendingBlockNumber].archive;
}

function getProvenBlockNumber() public view override(IRollup) returns (uint256) {
return tips.provenBlockNumber;
}

function getPendingBlockNumber() public view override(IRollup) returns (uint256) {
return tips.pendingBlockNumber;
}

/**
Expand Down Expand Up @@ -569,9 +577,9 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
revert Errors.Rollup__InvalidVersion(VERSION, _header.globalVariables.version);
}

if (_header.globalVariables.blockNumber != pendingBlockCount) {
if (_header.globalVariables.blockNumber != tips.pendingBlockNumber + 1) {
revert Errors.Rollup__InvalidBlockNumber(
pendingBlockCount, _header.globalVariables.blockNumber
tips.pendingBlockNumber + 1, _header.globalVariables.blockNumber
);
}

Expand All @@ -585,7 +593,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
revert Errors.Rollup__SlotValueTooLarge(slot);
}

uint256 lastSlot = uint256(blocks[pendingBlockCount - 1].slotNumber);
uint256 lastSlot = uint256(blocks[tips.pendingBlockNumber].slotNumber);
if (slot <= lastSlot) {
revert Errors.Rollup__SlotAlreadyInChain(lastSlot, slot);
}
Expand Down
38 changes: 20 additions & 18 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,16 @@ import {DataStructures} from "../libraries/DataStructures.sol";
interface ITestRollup {
function setVerifier(address _verifier) external;
function setVkTreeRoot(bytes32 _vkTreeRoot) external;
function setAssumeProvenUntilBlockNumber(uint256 blockNumber) external;
function setAssumeProvenThroughBlockNumber(uint256 blockNumber) external;
}

interface IRollup {
event L2BlockProposed(uint256 indexed blockNumber);
event L2ProofVerified(uint256 indexed blockNumber, bytes32 indexed proverId);
event PrunedPending(uint256 provenBlockCount, uint256 pendingBlockCount);

function canProposeAtTime(uint256 _ts, bytes32 _archive) external view returns (uint256, uint256);
function validateHeader(
bytes calldata _header,
SignatureLib.Signature[] memory _signatures,
bytes32 _digest,
uint256 _currentTime,
bytes32 _txsEffecstHash,
DataStructures.ExecutionFlags memory _flags
) external view;
event PrunedPending(uint256 provenBlockNumber, uint256 pendingBlockNumber);

function prune() external;

function INBOX() external view returns (IInbox);

function OUTBOX() external view returns (IOutbox);

function L1_BLOCK_AT_GENESIS() external view returns (uint256);

function propose(
bytes calldata _header,
bytes32 _archive,
Expand All @@ -54,6 +38,22 @@ interface IRollup {
bytes calldata _proof
) external;

function canProposeAtTime(uint256 _ts, bytes32 _archive) external view returns (uint256, uint256);
function validateHeader(
bytes calldata _header,
SignatureLib.Signature[] memory _signatures,
bytes32 _digest,
uint256 _currentTime,
bytes32 _txsEffecstHash,
DataStructures.ExecutionFlags memory _flags
) external view;

function INBOX() external view returns (IInbox);

function OUTBOX() external view returns (IOutbox);

function L1_BLOCK_AT_GENESIS() external view returns (uint256);

// TODO(#7346): Integrate batch rollups
// function submitRootProof(
// bytes32 _previousArchive,
Expand All @@ -68,5 +68,7 @@ interface IRollup {

function archive() external view returns (bytes32);
function archiveAt(uint256 _blockNumber) external view returns (bytes32);
function getProvenBlockNumber() external view returns (uint256);
function getPendingBlockNumber() external view returns (uint256);
function computeTxsEffectsHash(bytes calldata _body) external pure returns (bytes32);
}
4 changes: 2 additions & 2 deletions l1-contracts/src/core/messagebridge/Outbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ contract Outbox is IOutbox {
uint256 _leafIndex,
bytes32[] calldata _path
) external override(IOutbox) {
if (_l2BlockNumber >= ROLLUP.provenBlockCount()) {
if (_l2BlockNumber > ROLLUP.getProvenBlockNumber()) {
revert Errors.Outbox__BlockNotProven(_l2BlockNumber);
}

Expand Down Expand Up @@ -157,7 +157,7 @@ contract Outbox is IOutbox {
override(IOutbox)
returns (bytes32 root, uint256 minHeight)
{
if (_l2BlockNumber >= ROLLUP.provenBlockCount()) {
if (_l2BlockNumber > ROLLUP.getProvenBlockNumber()) {
return (bytes32(0), 0);
}
RootData storage rootData = roots[_l2BlockNumber];
Expand Down
Loading