Skip to content

Commit

Permalink
feat: publish block body separately (AztecProtocol#4118)
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan authored Jan 19, 2024
1 parent af2be87 commit a04e1e3
Show file tree
Hide file tree
Showing 24 changed files with 287 additions and 67 deletions.
26 changes: 10 additions & 16 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity >=0.8.18;

// Interfaces
import {IRollup} from "./interfaces/IRollup.sol";
import {IAvailabilityOracle} from "./interfaces/IAvailabilityOracle.sol";
import {IInbox} from "./interfaces/messagebridge/IInbox.sol";
import {IOutbox} from "./interfaces/messagebridge/IOutbox.sol";
import {IRegistry} from "./interfaces/messagebridge/IRegistry.sol";
Expand All @@ -16,7 +17,6 @@ import {Errors} from "./libraries/Errors.sol";

// Contracts
import {MockVerifier} from "../mock/MockVerifier.sol";
import {AvailabilityOracle} from "./availability_oracle/AvailabilityOracle.sol";

/**
* @title Rollup
Expand All @@ -27,58 +27,52 @@ import {AvailabilityOracle} from "./availability_oracle/AvailabilityOracle.sol";
contract Rollup is IRollup {
MockVerifier public immutable VERIFIER;
IRegistry public immutable REGISTRY;
IAvailabilityOracle public immutable AVAILABILITY_ORACLE;
uint256 public immutable VERSION;
AvailabilityOracle public immutable AVAILABILITY_ORACLE;

bytes32 public archive; // Root of the archive tree
uint256 public lastBlockTs;
// Tracks the last time time was warped on L2 ("warp" is the testing cheatcode).
// See https://github.com/AztecProtocol/aztec-packages/issues/1614
uint256 public lastWarpedBlockTs;

constructor(IRegistry _registry) {
constructor(IRegistry _registry, IAvailabilityOracle _availabilityOracle) {
VERIFIER = new MockVerifier();
AVAILABILITY_ORACLE = new AvailabilityOracle();
REGISTRY = _registry;
AVAILABILITY_ORACLE = _availabilityOracle;
VERSION = 1;
}

/**
* @notice Process an incoming L2 block and progress the state
* @param _header - The L2 block header
* @param _archive - A root of the archive tree after the L2 block is applied
* @param _txsHash - Transactions hash.
* @param _body - The L2 block body
* @param _proof - The proof of correct execution
*/
function process(
bytes calldata _header,
bytes32 _archive,
bytes calldata _body, // TODO(#3944): this will be replaced with _txsHash once the separation is finished.
bytes32 _txsHash, // TODO(#3938) Update this to be actual txs hash and not the old block calldata hash.
bytes calldata _body, // TODO(#3938) Update this to pass in only th messages and not the whole body.
bytes memory _proof
) external override(IRollup) {
// Decode and validate header
HeaderLib.Header memory header = HeaderLib.decode(_header);
HeaderLib.validate(header, VERSION, lastBlockTs, archive);

// Check if the data is available using availability oracle (change availability oracle if you want a different DA layer)
bytes32 txsHash;
{
// @todo @LHerskind Hack such that the node is unchanged for now.
// should be removed when we have a proper block publication.
txsHash = AVAILABILITY_ORACLE.publish(_body);
}

if (!AVAILABILITY_ORACLE.isAvailable(txsHash)) {
// @todo @LHerskind Impossible to hit with above hack.
revert Errors.Rollup__UnavailableTxs(txsHash);
if (!AVAILABILITY_ORACLE.isAvailable(_txsHash)) {
revert Errors.Rollup__UnavailableTxs(_txsHash);
}

// Decode the cross-chain messages
(bytes32 inHash,, bytes32[] memory l1ToL2Msgs, bytes32[] memory l2ToL1Msgs) =
MessagesDecoder.decode(_body);

bytes32[] memory publicInputs = new bytes32[](1);
publicInputs[0] = _computePublicInputHash(_header, txsHash, inHash);
publicInputs[0] = _computePublicInputHash(_header, _txsHash, inHash);

// @todo @benesjan We will need `nextAvailableLeafIndex` of archive to verify the proof. This value is equal to
// current block number which is stored in the header (header.globalVariables.blockNumber).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ contract AvailabilityOracle is IAvailabilityOracle {

/**
* @notice Publishes transactions and marks its commitment, the TxsHash, as available
* @param _body - The L1 calldata
* @param _body - The block body
* @return txsHash - The TxsHash
*/
function publish(bytes calldata _body) external override(IAvailabilityOracle) returns (bytes32) {
bytes32 _txsHash = TxsDecoder.decode(_body);
isAvailable[_txsHash] = true;

emit TxsPublished(_txsHash);

return _txsHash;
}
}
2 changes: 2 additions & 0 deletions l1-contracts/src/core/interfaces/IAvailabilityOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
pragma solidity >=0.8.18;

interface IAvailabilityOracle {
event TxsPublished(bytes32 txsHash);

function publish(bytes calldata _body) external returns (bytes32);

function isAvailable(bytes32 _txsHash) external view returns (bool);
Expand Down
1 change: 1 addition & 0 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface IRollup {
function process(
bytes calldata _header,
bytes32 _archive,
bytes32 _txsHash,
bytes calldata _body,
bytes memory _proof
) external;
Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/src/core/libraries/HeaderLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ library HeaderLib {
revert Errors.Rollup__TimestampTooOld();
}

// @todo @LHerskind Proper genesis state. If the state is empty, we allow anything for now.
// TODO(#4148) Proper genesis state. If the state is empty, we allow anything for now.
if (_archive != bytes32(0) && _archive != _header.lastArchive.root) {
revert Errors.Rollup__InvalidArchive(_archive, _header.lastArchive.root);
}
Expand Down
25 changes: 19 additions & 6 deletions l1-contracts/test/Rollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {Inbox} from "../src/core/messagebridge/Inbox.sol";
import {Outbox} from "../src/core/messagebridge/Outbox.sol";
import {Errors} from "../src/core/libraries/Errors.sol";
import {Rollup} from "../src/core/Rollup.sol";
import {AvailabilityOracle} from "../src/core/availability_oracle/AvailabilityOracle.sol";

/**
* Blocks are generated using the `integration_l1_publisher.test.ts` tests.
Expand All @@ -27,14 +28,16 @@ contract RollupTest is DecoderBase {
Inbox internal inbox;
Outbox internal outbox;
Rollup internal rollup;
AvailabilityOracle internal availabilityOracle;

function setUp() public virtual {
helper = new DecoderHelper();

registry = new Registry();
inbox = new Inbox(address(registry));
outbox = new Outbox(address(registry));
rollup = new Rollup(registry);
availabilityOracle = new AvailabilityOracle();
rollup = new Rollup(registry, availabilityOracle);

registry.upgrade(address(rollup), address(inbox), address(outbox));
}
Expand Down Expand Up @@ -67,8 +70,10 @@ contract RollupTest is DecoderBase {
mstore(add(header, 0x20), 0x420)
}

bytes32 txsHash = availabilityOracle.publish(body);

vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidChainId.selector, 0x420, 31337));
rollup.process(header, archive, body, bytes(""));
rollup.process(header, archive, txsHash, body, bytes(""));
}

function testRevertInvalidVersion() public {
Expand All @@ -81,8 +86,10 @@ contract RollupTest is DecoderBase {
mstore(add(header, 0x40), 0x420)
}

bytes32 txsHash = availabilityOracle.publish(body);

vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, 0x420, 1));
rollup.process(header, archive, body, bytes(""));
rollup.process(header, archive, txsHash, body, bytes(""));
}

function testRevertTimestampInFuture() public {
Expand All @@ -96,8 +103,10 @@ contract RollupTest is DecoderBase {
mstore(add(header, 0x80), ts)
}

bytes32 txsHash = availabilityOracle.publish(body);

vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampInFuture.selector));
rollup.process(header, archive, body, bytes(""));
rollup.process(header, archive, txsHash, body, bytes(""));
}

function testRevertTimestampTooOld() public {
Expand All @@ -109,8 +118,10 @@ contract RollupTest is DecoderBase {
// Overwrite in the rollup contract
vm.store(address(rollup), bytes32(uint256(1)), bytes32(uint256(block.timestamp)));

bytes32 txsHash = availabilityOracle.publish(body);

vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampTooOld.selector));
rollup.process(header, archive, body, bytes(""));
rollup.process(header, archive, txsHash, body, bytes(""));
}

function _testBlock(string memory name) public {
Expand All @@ -131,8 +142,10 @@ contract RollupTest is DecoderBase {
assertTrue(inbox.contains(full.messages.l1ToL2Messages[i]), "msg not in inbox");
}

bytes32 txsHash = availabilityOracle.publish(body);

vm.record();
rollup.process(header, archive, body, bytes(""));
rollup.process(header, archive, txsHash, body, bytes(""));

(, bytes32[] memory inboxWrites) = vm.accesses(address(inbox));
(, bytes32[] memory outboxWrites) = vm.accesses(address(outbox));
Expand Down
3 changes: 2 additions & 1 deletion l1-contracts/test/portals/TokenPortal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "forge-std/Test.sol";

// Rollup Processor
import {Rollup} from "../../src/core/Rollup.sol";
import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol";
import {Inbox} from "../../src/core/messagebridge/Inbox.sol";
import {Registry} from "../../src/core/messagebridge/Registry.sol";
import {Outbox} from "../../src/core/messagebridge/Outbox.sol";
Expand Down Expand Up @@ -64,7 +65,7 @@ contract TokenPortalTest is Test {
registry = new Registry();
inbox = new Inbox(address(registry));
outbox = new Outbox(address(registry));
rollup = new Rollup(registry);
rollup = new Rollup(registry, new AvailabilityOracle());

registry.upgrade(address(rollup), address(inbox), address(outbox));

Expand Down
3 changes: 2 additions & 1 deletion l1-contracts/test/portals/UniswapPortal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "forge-std/Test.sol";

// Rollup Processor
import {Rollup} from "../../src/core/Rollup.sol";
import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol";
import {Inbox} from "../../src/core/messagebridge/Inbox.sol";
import {Registry} from "../../src/core/messagebridge/Registry.sol";
import {Outbox} from "../../src/core/messagebridge/Outbox.sol";
Expand Down Expand Up @@ -51,7 +52,7 @@ contract UniswapPortalTest is Test {
Registry registry = new Registry();
inbox = new Inbox(address(registry));
outbox = new Outbox(address(registry));
rollup = new Rollup(registry);
rollup = new Rollup(registry, new AvailabilityOracle());
registry.upgrade(address(rollup), address(inbox), address(outbox));

daiTokenPortal = new TokenPortal();
Expand Down
7 changes: 6 additions & 1 deletion yarn-project/archiver/src/archiver/archiver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,13 @@ function makeL1ToL2MessageCancelledEvents(l1BlockNum: bigint, entryKeys: string[
function makeRollupTx(l2Block: L2Block) {
const header = toHex(l2Block.header.toBuffer());
const archive = toHex(l2Block.archive.root.toBuffer());
const txsHash = toHex(l2Block.getCalldataHash());
const body = toHex(l2Block.bodyToBuffer());
const proof = `0x`;
const input = encodeFunctionData({ abi: RollupAbi, functionName: 'process', args: [header, archive, body, proof] });
const input = encodeFunctionData({
abi: RollupAbi,
functionName: 'process',
args: [header, archive, txsHash, body, proof],
});
return { input } as Transaction<bigint, number>;
}
4 changes: 4 additions & 0 deletions yarn-project/archiver/src/archiver/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export function getConfigEnvVars(): ArchiverConfig {
ETHEREUM_HOST,
ARCHIVER_POLLING_INTERVAL_MS,
ARCHIVER_VIEM_POLLING_INTERVAL_MS,
AVAILABILITY_ORACLE_CONTRACT_ADDRESS,
ROLLUP_CONTRACT_ADDRESS,
CONTRACT_DEPLOYMENT_EMITTER_ADDRESS,
API_KEY,
Expand All @@ -66,6 +67,9 @@ export function getConfigEnvVars(): ArchiverConfig {
} = process.env;
// Populate the relevant addresses for use by the archiver.
const addresses: L1ContractAddresses = {
availabilityOracleAddress: AVAILABILITY_ORACLE_CONTRACT_ADDRESS
? EthAddress.fromString(AVAILABILITY_ORACLE_CONTRACT_ADDRESS)
: EthAddress.ZERO,
rollupAddress: ROLLUP_CONTRACT_ADDRESS ? EthAddress.fromString(ROLLUP_CONTRACT_ADDRESS) : EthAddress.ZERO,
registryAddress: REGISTRY_CONTRACT_ADDRESS ? EthAddress.fromString(REGISTRY_CONTRACT_ADDRESS) : EthAddress.ZERO,
inboxAddress: INBOX_CONTRACT_ADDRESS ? EthAddress.fromString(INBOX_CONTRACT_ADDRESS) : EthAddress.ZERO,
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/archiver/src/archiver/eth_log_handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ async function getBlockFromCallData(
if (functionName !== 'process') {
throw new Error(`Unexpected method called ${functionName}`);
}
const [headerHex, archiveRootHex, bodyHex] = args! as [Hex, Hex, Hex, Hex];
const [headerHex, archiveRootHex, , bodyHex] = args! as [Hex, Hex, Hex, Hex, Hex];
const blockBuffer = Buffer.concat([
Buffer.from(hexToBytes(headerHex)),
Buffer.from(hexToBytes(archiveRootHex)), // L2Block.archive.root
Expand Down
6 changes: 6 additions & 0 deletions yarn-project/aztec-sandbox/src/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
import { createDebugLogger } from '@aztec/foundation/log';
import { retryUntil } from '@aztec/foundation/retry';
import {
AvailabilityOracleAbi,
AvailabilityOracleBytecode,
ContractDeploymentEmitterAbi,
ContractDeploymentEmitterBytecode,
InboxAbi,
Expand Down Expand Up @@ -90,6 +92,10 @@ export async function deployContractsToL1(aztecNodeConfig: AztecNodeConfig, hdAc
contractAbi: OutboxAbi,
contractBytecode: OutboxBytecode,
},
availabilityOracle: {
contractAbi: AvailabilityOracleAbi,
contractBytecode: AvailabilityOracleBytecode,
},
rollup: {
contractAbi: RollupAbi,
contractBytecode: RollupBytecode,
Expand Down
1 change: 1 addition & 0 deletions yarn-project/aztec.js/src/contract/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ describe('Contract Class', () => {
const mockTxReceipt = { type: 'TxReceipt' } as any as TxReceipt;
const mockViewResultValue = 1;
const l1Addresses: L1ContractAddresses = {
availabilityOracleAddress: EthAddress.random(),
rollupAddress: EthAddress.random(),
registryAddress: EthAddress.random(),
inboxAddress: EthAddress.random(),
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/cli/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { type L1ContractArtifactsForDeployment } from '@aztec/aztec.js/ethereum'
import { type PXE } from '@aztec/aztec.js/interfaces/pxe';
import { DebugLogger, LogFn } from '@aztec/foundation/log';
import { NoirPackageConfig } from '@aztec/foundation/noir';
import { AvailabilityOracleAbi, AvailabilityOracleBytecode } from '@aztec/l1-artifacts';

import TOML from '@iarna/toml';
import { CommanderError, InvalidArgumentError } from 'commander';
Expand Down Expand Up @@ -80,6 +81,10 @@ export async function deployAztecContracts(
contractAbi: OutboxAbi,
contractBytecode: OutboxBytecode,
},
availabilityOracle: {
contractAbi: AvailabilityOracleAbi,
contractBytecode: AvailabilityOracleBytecode,
},
rollup: {
contractAbi: RollupAbi,
contractBytecode: RollupBytecode,
Expand Down
13 changes: 7 additions & 6 deletions yarn-project/end-to-end/src/fixtures/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
waitForPXE,
} from '@aztec/aztec.js';
import {
AvailabilityOracleAbi,
AvailabilityOracleBytecode,
ContractDeploymentEmitterAbi,
ContractDeploymentEmitterBytecode,
InboxAbi,
Expand Down Expand Up @@ -87,6 +89,10 @@ export const setupL1Contracts = async (
contractAbi: OutboxAbi,
contractBytecode: OutboxBytecode,
},
availabilityOracle: {
contractAbi: AvailabilityOracleAbi,
contractBytecode: AvailabilityOracleBytecode,
},
rollup: {
contractAbi: RollupAbi,
contractBytecode: RollupBytecode,
Expand Down Expand Up @@ -279,12 +285,7 @@ export async function setup(
opts.deployL1ContractsValues ?? (await setupL1Contracts(config.rpcUrl, hdAccount, logger));

config.publisherPrivateKey = `0x${publisherPrivKey!.toString('hex')}`;
config.l1Contracts.rollupAddress = deployL1ContractsValues.l1ContractAddresses.rollupAddress;
config.l1Contracts.registryAddress = deployL1ContractsValues.l1ContractAddresses.registryAddress;
config.l1Contracts.contractDeploymentEmitterAddress =
deployL1ContractsValues.l1ContractAddresses.contractDeploymentEmitterAddress;
config.l1Contracts.inboxAddress = deployL1ContractsValues.l1ContractAddresses.inboxAddress;
config.l1Contracts.outboxAddress = deployL1ContractsValues.l1ContractAddresses.outboxAddress;
config.l1Contracts = deployL1ContractsValues.l1ContractAddresses;

logger('Creating and synching an aztec node...');
const aztecNode = await AztecNodeService.createAndSync(config);
Expand Down
2 changes: 2 additions & 0 deletions yarn-project/end-to-end/src/integration_l1_publisher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ describe('L1Publisher integration', () => {
args: [
`0x${block.header.toBuffer().toString('hex')}`,
`0x${block.archive.root.toBuffer().toString('hex')}`,
`0x${block.getCalldataHash().toString('hex')}`,
`0x${block.bodyToBuffer().toString('hex')}`,
`0x${l2Proof.toString('hex')}`,
],
Expand Down Expand Up @@ -475,6 +476,7 @@ describe('L1Publisher integration', () => {
args: [
`0x${block.header.toBuffer().toString('hex')}`,
`0x${block.archive.root.toBuffer().toString('hex')}`,
`0x${block.getCalldataHash().toString('hex')}`,
`0x${block.bodyToBuffer().toString('hex')}`,
`0x${l2Proof.toString('hex')}`,
],
Expand Down
Loading

0 comments on commit a04e1e3

Please sign in to comment.