From 77edf6ade93649e09081d5d76ec33e8e6cd5430b Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 10 Sep 2024 16:51:53 +0000 Subject: [PATCH] refactor: remove unneeded propose and da oracle --- .github/workflows/devnet-deploys.yml | 1 - docker-compose.yml | 1 - .../overview.md | 4 +- .../l1-smart-contracts/index.md | 40 +--- .../files/config/config-prover-env.sh | 2 - .../files/config/config-validator-env.sh | 2 - .../deploy-contracts.config-map.yaml | 2 - l1-contracts/src/core/Rollup.sol | 177 +++++++----------- .../AvailabilityOracle.sol | 32 ---- .../core/interfaces/IAvailabilityOracle.sol | 11 -- l1-contracts/src/core/interfaces/IRollup.sol | 15 +- l1-contracts/src/core/libraries/MerkleLib.sol | 10 +- l1-contracts/terraform/main.tf | 9 - l1-contracts/test/Rollup.t.sol | 38 +--- l1-contracts/test/portals/TokenPortal.t.sol | 11 +- l1-contracts/test/portals/UniswapPortal.t.sol | 11 +- l1-contracts/test/sparta/Sparta.t.sol | 19 +- .../archiver/src/archiver/archiver.test.ts | 55 +----- .../archiver/src/archiver/archiver.ts | 128 ++++--------- .../archiver/src/archiver/data_retrieval.ts | 70 ++----- .../archiver/src/archiver/eth_log_handlers.ts | 134 ++----------- yarn-project/archiver/src/index.ts | 3 +- .../aztec-node/src/aztec-node/server.test.ts | 1 - .../aztec-node/src/aztec-node/server.ts | 3 +- .../aztec.js/src/contract/contract.test.ts | 1 - .../aztec/src/cli/aztec_start_options.ts | 6 - yarn-project/aztec/src/sandbox.ts | 6 - yarn-project/aztec/terraform/node/main.tf | 4 - .../aztec/terraform/prover-node/main.tf | 1 - yarn-project/circuit-types/src/body.ts | 2 +- .../cli/src/cmds/l1/deploy_l1_contracts.ts | 1 - .../cli/src/cmds/pxe/get_node_info.ts | 1 - yarn-project/cli/src/utils/aztec.ts | 7 +- .../composed/integration_l1_publisher.test.ts | 61 ++---- .../src/fixtures/setup_l1_contracts.ts | 6 - yarn-project/end-to-end/src/fixtures/utils.ts | 6 - .../ethereum/src/deploy_l1_contracts.ts | 9 - .../ethereum/src/l1_contract_addresses.ts | 6 - yarn-project/foundation/src/config/env_var.ts | 1 - .../scripts/generate-artifacts.sh | 1 - .../src/pxe_service/test/pxe_service.test.ts | 1 - .../src/publisher/l1-publisher.test.ts | 46 ----- .../src/publisher/l1-publisher.ts | 86 ++------- .../serialization/bytecode_serialization.ts | 2 +- 44 files changed, 205 insertions(+), 828 deletions(-) delete mode 100644 l1-contracts/src/core/availability_oracle/AvailabilityOracle.sol delete mode 100644 l1-contracts/src/core/interfaces/IAvailabilityOracle.sol diff --git a/.github/workflows/devnet-deploys.yml b/.github/workflows/devnet-deploys.yml index 496f4f72833..75d0431dfda 100644 --- a/.github/workflows/devnet-deploys.yml +++ b/.github/workflows/devnet-deploys.yml @@ -546,7 +546,6 @@ jobs: echo "TF_VAR_REGISTRY_CONTRACT_ADDRESS=$(extract registryAddress)" >>$GITHUB_ENV echo "TF_VAR_INBOX_CONTRACT_ADDRESS=$(extract inboxAddress)" >>$GITHUB_ENV echo "TF_VAR_OUTBOX_CONTRACT_ADDRESS=$(extract outboxAddress)" >>$GITHUB_ENV - echo "TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$(extract availabilityOracleAddress)" >>$GITHUB_ENV echo "TF_VAR_FEE_JUICE_CONTRACT_ADDRESS=$(extract feeJuiceAddress)" >>$GITHUB_ENV echo "TF_VAR_FEE_JUICE_PORTAL_CONTRACT_ADDRESS=$(extract feeJuicePortalAddress)" >>$GITHUB_ENV diff --git a/docker-compose.yml b/docker-compose.yml index 9106ee66811..18ca3c48335 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,7 +50,6 @@ services: REGISTRY_CONTRACT_ADDRESS: "0x589a9634c1d00c62e47b3b7a790c8dc986b3d40d" INBOX_CONTRACT_ADDRESS: "0x12d9b5effc69bf5c0c29c8258c6b6fa95a08de74" OUTBOX_CONTRACT_ADDRESS: "0x3ec4b6c68a8c2ce4c78cdd465b3019b11a568d1d" - AVAILABILITY_ORACLE_CONTRACT_ADDRESS: "0x98a4089127f3f5d555656f1c9b1801342c9d6bce" FEE_JUICE_CONTRACT_ADDRESS: "0x73c43b919973711e096bfc04c9d4b3be511ffc0b" FEE_JUICE_PORTAL_CONTRACT_ADDRESS: "0xdf25b0a34dbee9f25518f7a4d63bab8b3bb3e496" ETHEREUM_HOST: diff --git a/docs/docs/protocol-specs/data-publication-and-availability/overview.md b/docs/docs/protocol-specs/data-publication-and-availability/overview.md index ca46010fc15..c8bcc533217 100644 --- a/docs/docs/protocol-specs/data-publication-and-availability/overview.md +++ b/docs/docs/protocol-specs/data-publication-and-availability/overview.md @@ -13,7 +13,7 @@ As for that, we highly recommend reading [this very nice post](https://dba.xyz/d Essentially Data Publication $\subset$ Data Availability, since if it is available, it must also have been published. This difference might be small but becomes important in a few moments. -Progressing the state of the validating light node requires that we can convince it (and therefore the [availability oracle](./index.md#availability-oracle)) that the data was published - as it needs to compute the public inputs for the proof. +Progressing the state of the validating light node requires that we can convince it that the data was published - as it needs to compute the public inputs for the proof. The exact method of computing these public inputs can vary depending on the data layer, but generally, it could be by providing the data directly or by using data availability sampling or a data availability committee. The exact mechanism greatly impacts the security and cost of the system, and will be discussed in the following sections. @@ -246,7 +246,7 @@ Assuming that this is a decent guess, and we can estimate the data requirements Using the values from just above for transaction data requirements, we can get a ball park estimate of what we can expect to require at different throughput levels. -|Throughput | Everyone | Someone | Total | +|Throughput | Everyone | Someone | Total | |:-----:|:-----:|:-----:|:-----:| | 1 TPS | $512 \dfrac{byte}{s}$ | $1036 \dfrac{byte}{s}$ | $1548 \dfrac{byte}{s}$ | | 10 TPS | $5120 \dfrac{byte}{s}$ | $10360 \dfrac{byte}{s}$ | $15480 \dfrac{byte}{s}$ | diff --git a/docs/docs/protocol-specs/l1-smart-contracts/index.md b/docs/docs/protocol-specs/l1-smart-contracts/index.md index 19dc8f05140..845c77e36aa 100644 --- a/docs/docs/protocol-specs/l1-smart-contracts/index.md +++ b/docs/docs/protocol-specs/l1-smart-contracts/index.md @@ -21,7 +21,7 @@ When presented with a new [`ProvenBlock`](../rollup-circuits/root-rollup.md) and The `archive` used as public input is the archive after the new header is inserted (see [root rollup](./../rollup-circuits/root-rollup.md)). ```python -def process(block: ProvenBlock, proof: Proof): +def propose(block: ProvenBlock, proof: Proof): header = block.header block_number = header.global_variables.block_number @@ -57,6 +57,8 @@ Namely, we need the cross-chain messages to be published to L1, but the rest of :::info Validium or Rollup If a different data availability layer than Ethereum is used for the block body, we are effectively building a Validium. If we use Ethereum for the block body, we are building a Rollup. + +For more information around the requirements we have for the availability, see [Data Availability](../data-publication-and-availability/index.md). ::: Using the data structures defined throughout the [rollup circuits](./../rollup-circuits/index.md) section, we can outline the validating light node structure as follows: @@ -64,12 +66,6 @@ Using the data structures defined throughout the [rollup circuits](./../rollup-c ```mermaid classDiagram -class AvailabilityOracle { - available: Map[Fr => bool] - mut publish(effects: TxEffect[]): Fr - is_available(txs_hash: Fr): bool -} - class Inbox { consume(): bytes32 } @@ -84,9 +80,8 @@ class Verifier { class StateTransitioner { archive: Snapshot - process(header: Header, archive: Fr, proof: Proof) + propose(header: Header, archive: Fr, proof: Proof, body: Body) } -StateTransitioner --> AvailabilityOracle: is_available() StateTransitioner --> Inbox: consume() StateTransitioner --> Outbox: insert() StateTransitioner --> Verifier: verify() @@ -110,7 +105,6 @@ class StateTransitioner: slot_number: uint128 VERIFIER: immutable(IVerifier) - AVAILABILITY_ORACLE: immutable(IAvailabilityOracle) INBOX: immutable(IInbox) OUTBOX: immutable(IOutbox) VERSION: immutable(uint256) @@ -126,13 +120,14 @@ class StateTransitioner: self.blocks.append(BlockLog({archive: bytes32(0), slot_number: 0})) self.GENESIS_TIME = block.timestamp - def process( + def propose( self, header: Header, archive: Fr, - proof: Proof + proof: Proof, + body: Body ): - assert self.AVAILABILITY_ORACLE.is_available(header.content_commitment.txs_hash) + assert body.compute_commitment() == header.content_commitment assert self.validate_header(header) assert VERIFIER.verify(header, archive, proof) assert self.INBOX.consume() == header.content_commitment.in_hash @@ -162,25 +157,6 @@ class StateTransitioner: return True ``` -### Availability Oracle - -The state transitioner should be connected to an oracle which addresses the availability condition. - -For the case of a rollup, this "oracle" will be deriving the `TxsHash` from calldata and blobs. -For a validium it should be connected to a bridge that it can use to verify that the data is available on the other chain. - -For a generic DA that publishes data commitments to Ethereum, the oracle could be a snark proof that opens the data commitment from the bridge and computes the `TxsHash` from it. - -By having the availability oracle be independent from state progression we can even do multi-transaction blocks, e.g., use multiple transactions or commitments from other DA layers to construct the `TxsHash` for a large block. - -For more information around the requirements we have for the availability oracle, see [Data Availability](../data-publication-and-availability/index.md). - -An interesting observation around the availability oracle is that the `OutHash` and `InHash` don't need to be explicitly proven available through it. -The `InHash` is already proven as part of the L1 inbox, as we will see in a second. -And the `OutHash` consists entirely of a subset of the contents of the `TxsHash`, which is already proven available. - - - ### Registry To keep one location where all the core rollup contracts can be found, we have a registry contract. diff --git a/helm-charts/aztec-network/files/config/config-prover-env.sh b/helm-charts/aztec-network/files/config/config-prover-env.sh index a4bd508a111..125ee8dca11 100644 --- a/helm-charts/aztec-network/files/config/config-prover-env.sh +++ b/helm-charts/aztec-network/files/config/config-prover-env.sh @@ -14,7 +14,6 @@ rollup_address=$(echo "$output" | grep -oP 'Rollup Address: \K0x[a-fA-F0-9]{40}' registry_address=$(echo "$output" | grep -oP 'Registry Address: \K0x[a-fA-F0-9]{40}') inbox_address=$(echo "$output" | grep -oP 'L1 -> L2 Inbox Address: \K0x[a-fA-F0-9]{40}') outbox_address=$(echo "$output" | grep -oP 'L2 -> L1 Outbox Address: \K0x[a-fA-F0-9]{40}') -availability_oracle_address=$(echo "$output" | grep -oP 'Availability Oracle Address: \K0x[a-fA-F0-9]{40}') fee_juice_address=$(echo "$output" | grep -oP 'Fee Juice Address: \K0x[a-fA-F0-9]{40}') fee_juice_portal_address=$(echo "$output" | grep -oP 'Fee Juice Portal Address: \K0x[a-fA-F0-9]{40}') @@ -26,7 +25,6 @@ export ROLLUP_CONTRACT_ADDRESS=$rollup_address export REGISTRY_CONTRACT_ADDRESS=$registry_address export INBOX_CONTRACT_ADDRESS=$inbox_address export OUTBOX_CONTRACT_ADDRESS=$outbox_address -export AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$availability_oracle_address export FEE_JUICE_CONTRACT_ADDRESS=$fee_juice_address export FEE_JUICE_PORTAL_CONTRACT_ADDRESS=$fee_juice_portal_address EOF diff --git a/helm-charts/aztec-network/files/config/config-validator-env.sh b/helm-charts/aztec-network/files/config/config-validator-env.sh index e2b29694bc7..f25834ad54d 100644 --- a/helm-charts/aztec-network/files/config/config-validator-env.sh +++ b/helm-charts/aztec-network/files/config/config-validator-env.sh @@ -14,7 +14,6 @@ rollup_address=$(echo "$output" | grep -oP 'Rollup Address: \K0x[a-fA-F0-9]{40}' registry_address=$(echo "$output" | grep -oP 'Registry Address: \K0x[a-fA-F0-9]{40}') inbox_address=$(echo "$output" | grep -oP 'L1 -> L2 Inbox Address: \K0x[a-fA-F0-9]{40}') outbox_address=$(echo "$output" | grep -oP 'L2 -> L1 Outbox Address: \K0x[a-fA-F0-9]{40}') -availability_oracle_address=$(echo "$output" | grep -oP 'Availability Oracle Address: \K0x[a-fA-F0-9]{40}') fee_juice_address=$(echo "$output" | grep -oP 'Fee Juice Address: \K0x[a-fA-F0-9]{40}') fee_juice_portal_address=$(echo "$output" | grep -oP 'Fee Juice Portal Address: \K0x[a-fA-F0-9]{40}') @@ -37,7 +36,6 @@ export ROLLUP_CONTRACT_ADDRESS=$rollup_address export REGISTRY_CONTRACT_ADDRESS=$registry_address export INBOX_CONTRACT_ADDRESS=$inbox_address export OUTBOX_CONTRACT_ADDRESS=$outbox_address -export AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$availability_oracle_address export FEE_JUICE_CONTRACT_ADDRESS=$fee_juice_address export FEE_JUICE_PORTAL_CONTRACT_ADDRESS=$fee_juice_portal_address export VALIDATOR_PRIVATE_KEY=$private_key diff --git a/helm-charts/aztec-network/templates/deploy-contracts.config-map.yaml b/helm-charts/aztec-network/templates/deploy-contracts.config-map.yaml index 157cb822dbd..7191a38b78f 100644 --- a/helm-charts/aztec-network/templates/deploy-contracts.config-map.yaml +++ b/helm-charts/aztec-network/templates/deploy-contracts.config-map.yaml @@ -19,7 +19,6 @@ data: registry_address=$(echo "$output" | grep -oP 'Registry Address: \K0x[a-fA-F0-9]{40}') inbox_address=$(echo "$output" | grep -oP 'L1 -> L2 Inbox Address: \K0x[a-fA-F0-9]{40}') outbox_address=$(echo "$output" | grep -oP 'L2 -> L1 Outbox Address: \K0x[a-fA-F0-9]{40}') - availability_oracle_address=$(echo "$output" | grep -oP 'Availability Oracle Address: \K0x[a-fA-F0-9]{40}') fee_juice_address=$(echo "$output" | grep -oP 'Fee Juice Address: \K0x[a-fA-F0-9]{40}') fee_juice_portal_address=$(echo "$output" | grep -oP 'Fee Juice Portal Address: \K0x[a-fA-F0-9]{40}') @@ -29,7 +28,6 @@ data: export REGISTRY_CONTRACT_ADDRESS=$registry_address export INBOX_CONTRACT_ADDRESS=$inbox_address export OUTBOX_CONTRACT_ADDRESS=$outbox_address - export AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$availability_oracle_address export FEE_JUICE_CONTRACT_ADDRESS=$fee_juice_address export FEE_JUICE_PORTAL_CONTRACT_ADDRESS=$fee_juice_portal_address EOF diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 4d7efa4ee38..0a21a2c5d29 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.18; // Interfaces import {IRollup, ITestRollup} 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"; @@ -19,6 +18,7 @@ import {MerkleLib} from "./libraries/MerkleLib.sol"; import {SignatureLib} from "./sequencer_selection/SignatureLib.sol"; import {SafeCast} from "@oz/utils/math/SafeCast.sol"; import {DataStructures} from "./libraries/DataStructures.sol"; +import {TxsDecoder} from "./libraries/decoders/TxsDecoder.sol"; // Contracts import {MockVerifier} from "../mock/MockVerifier.sol"; @@ -47,7 +47,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup { uint256 public constant TIMELINESS_PROVING_IN_SLOTS = 100; IRegistry public immutable REGISTRY; - IAvailabilityOracle public immutable AVAILABILITY_ORACLE; IInbox public immutable INBOX; IOutbox public immutable OUTBOX; uint256 public immutable VERSION; @@ -73,7 +72,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup { constructor( IRegistry _registry, - IAvailabilityOracle _availabilityOracle, IFeeJuicePortal _fpcJuicePortal, bytes32 _vkTreeRoot, address _ares, @@ -81,7 +79,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup { ) Leonidas(_ares) { verifier = new MockVerifier(); REGISTRY = _registry; - AVAILABILITY_ORACLE = _availabilityOracle; FEE_JUICE_PORTAL = _fpcJuicePortal; INBOX = new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT); OUTBOX = new Outbox(address(this)); @@ -171,9 +168,17 @@ contract Rollup is Leonidas, IRollup, ITestRollup { vkTreeRoot = _vkTreeRoot; } + function computeTxsEffectsHash(bytes calldata _body) + external + view + override(IRollup) + returns (bytes32) + { + return TxsDecoder.decode(_body); + } + /** - * @notice Published the body and propose the block - * @dev This should likely be purged in the future as it is a convenience method + * @notice Publishes the body and propose the block * @dev `eth_log_handlers` rely on this function * * @param _header - The L2 block header @@ -189,27 +194,55 @@ contract Rollup is Leonidas, IRollup, ITestRollup { SignatureLib.Signature[] memory _signatures, bytes calldata _body ) external override(IRollup) { - AVAILABILITY_ORACLE.publish(_body); - propose(_header, _archive, _blockHash, _signatures); - } + bytes32 txsEffectsHash = TxsDecoder.decode(_body); - /** - * @notice Published the body and propose the block - * @dev This should likely be purged in the future as it is a convenience method - * @dev `eth_log_handlers` rely on this function - * @param _header - The L2 block header - * @param _archive - A root of the archive tree after the L2 block is applied - * @param _blockHash - The poseidon2 hash of the header added to the archive tree in the rollup circuit - * @param _body - The body of the L2 block - */ - function propose( - bytes calldata _header, - bytes32 _archive, - bytes32 _blockHash, - bytes calldata _body - ) external override(IRollup) { - AVAILABILITY_ORACLE.publish(_body); - propose(_header, _archive, _blockHash); + // Decode and validate header + HeaderLib.Header memory header = HeaderLib.decode(_header); + setupEpoch(); + _validateHeader({ + _header: header, + _signatures: _signatures, + _digest: _archive, + _currentTime: block.timestamp, + _txEffectsHash: txsEffectsHash, + _flags: DataStructures.ExecutionFlags({ignoreDA: false, ignoreSignatures: false}) + }); + + blocks[pendingBlockCount++] = 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); + if (header.contentCommitment.inHash != inHash) { + revert 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 + (uint256 min,) = MerkleLib.computeMinMaxPathLength(header.contentCommitment.numTxs); + uint256 l2ToL1TreeMinHeight = min + 1; + OUTBOX.insert( + header.globalVariables.blockNumber, header.contentCommitment.outHash, l2ToL1TreeMinHeight + ); + + emit L2BlockProposed(header.globalVariables.blockNumber); + + // Automatically flag the block as proven if we have cheated and set assumeProvenUntilBlockNumber. + if (header.globalVariables.blockNumber < assumeProvenUntilBlockNumber) { + provenBlockCount += 1; + + if (header.globalVariables.coinbase != address(0) && header.totalFees > 0) { + // @note This will currently fail if there are insufficient funds in the bridge + // which WILL happen for the old version after an upgrade where the bridge follow. + // Consider allowing a failure. See #7938. + FEE_JUICE_PORTAL.distributeFees(header.globalVariables.coinbase, header.totalFees); + } + + emit L2ProofVerified(header.globalVariables.blockNumber, "CHEAT"); + } } /** @@ -416,87 +449,11 @@ contract Rollup is Leonidas, IRollup, ITestRollup { SignatureLib.Signature[] memory _signatures, bytes32 _digest, uint256 _currentTime, + bytes32 _txsEffectsHash, DataStructures.ExecutionFlags memory _flags ) external view override(IRollup) { HeaderLib.Header memory header = HeaderLib.decode(_header); - _validateHeader(header, _signatures, _digest, _currentTime, _flags); - } - - /** - * @notice propose an incoming L2 block with signatures - * - * @param _header - The L2 block header - * @param _archive - A root of the archive tree after the L2 block is applied - * @param _blockHash - The poseidon2 hash of the header added to the archive tree in the rollup circuit - * @param _signatures - Signatures from the validators - */ - function propose( - bytes calldata _header, - bytes32 _archive, - bytes32 _blockHash, - SignatureLib.Signature[] memory _signatures - ) public override(IRollup) { - // Decode and validate header - HeaderLib.Header memory header = HeaderLib.decode(_header); - setupEpoch(); - _validateHeader({ - _header: header, - _signatures: _signatures, - _digest: _archive, - _currentTime: block.timestamp, - _flags: DataStructures.ExecutionFlags({ignoreDA: false, ignoreSignatures: false}) - }); - - blocks[pendingBlockCount++] = 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); - if (header.contentCommitment.inHash != inHash) { - revert 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 - (uint256 min,) = MerkleLib.computeMinMaxPathLength(header.contentCommitment.numTxs); - uint256 l2ToL1TreeMinHeight = min + 1; - OUTBOX.insert( - header.globalVariables.blockNumber, header.contentCommitment.outHash, l2ToL1TreeMinHeight - ); - - emit L2BlockProposed(header.globalVariables.blockNumber); - - // Automatically flag the block as proven if we have cheated and set assumeProvenUntilBlockNumber. - if (header.globalVariables.blockNumber < assumeProvenUntilBlockNumber) { - provenBlockCount += 1; - - if (header.globalVariables.coinbase != address(0) && header.totalFees > 0) { - // @note This will currently fail if there are insufficient funds in the bridge - // which WILL happen for the old version after an upgrade where the bridge follow. - // Consider allowing a failure. See #7938. - FEE_JUICE_PORTAL.distributeFees(header.globalVariables.coinbase, header.totalFees); - } - - emit L2ProofVerified(header.globalVariables.blockNumber, "CHEAT"); - } - } - - /** - * @notice Propose a L2 block without signatures - * - * @param _header - The L2 block header - * @param _archive - A root of the archive tree after the L2 block is applied - * @param _blockHash - The poseidon2 hash of the header added to the archive tree in the rollup circuit - */ - function propose(bytes calldata _header, bytes32 _archive, bytes32 _blockHash) - public - override(IRollup) - { - SignatureLib.Signature[] memory emptySignatures = new SignatureLib.Signature[](0); - propose(_header, _archive, _blockHash, emptySignatures); + _validateHeader(header, _signatures, _digest, _currentTime, _txsEffectsHash, _flags); } /** @@ -523,9 +480,10 @@ contract Rollup is Leonidas, IRollup, ITestRollup { SignatureLib.Signature[] memory _signatures, bytes32 _digest, uint256 _currentTime, + bytes32 _txEffectsHash, DataStructures.ExecutionFlags memory _flags ) internal view { - _validateHeaderForSubmissionBase(_header, _currentTime, _flags); + _validateHeaderForSubmissionBase(_header, _currentTime, _txEffectsHash, _flags); _validateHeaderForSubmissionSequencerSelection( _header.globalVariables.slotNumber, _signatures, _digest, _currentTime, _flags ); @@ -586,7 +544,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup { * - The last archive root in the header MUST match the current archive * - The slot MUST be larger than the slot of the previous block (ensures single block per slot) * - The timestamp MUST be equal to GENESIS_TIME + slot * SLOT_DURATION - * - The availability oracle MUST return true for availability of txsEffectsHash + * - The `txsEffectsHash` of the header must match the computed `_txsEffectsHash` * - This can be relaxed to happen at the time of `submitProof` instead * * @param _header - The header to validate @@ -594,6 +552,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup { function _validateHeaderForSubmissionBase( HeaderLib.Header memory _header, uint256 _currentTime, + bytes32 _txsEffectsHash, DataStructures.ExecutionFlags memory _flags ) internal view { if (block.chainid != _header.globalVariables.chainId) { @@ -640,10 +599,8 @@ contract Rollup is Leonidas, IRollup, ITestRollup { revert Errors.Rollup__TimestampInFuture(_currentTime, timestamp); } - // Check if the data is available using availability oracle (change availability oracle if you want a different DA layer) - if ( - !_flags.ignoreDA && !AVAILABILITY_ORACLE.isAvailable(_header.contentCommitment.txsEffectsHash) - ) { + // Check if the data is available + if (!_flags.ignoreDA && _header.contentCommitment.txsEffectsHash != _txsEffectsHash) { revert Errors.Rollup__UnavailableTxs(_header.contentCommitment.txsEffectsHash); } } diff --git a/l1-contracts/src/core/availability_oracle/AvailabilityOracle.sol b/l1-contracts/src/core/availability_oracle/AvailabilityOracle.sol deleted file mode 100644 index 5553d5a2143..00000000000 --- a/l1-contracts/src/core/availability_oracle/AvailabilityOracle.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2024 Aztec Labs. -pragma solidity >=0.8.18; - -// Interfaces -import {IAvailabilityOracle} from "./../interfaces/IAvailabilityOracle.sol"; - -// Libraries -import {TxsDecoder} from "./../libraries/decoders/TxsDecoder.sol"; - -/** - * @title AvailabilityOracle - * @author Aztec Labs - * @notice An availability oracle that uses L1 calldata for publication - */ -contract AvailabilityOracle is IAvailabilityOracle { - mapping(bytes32 txsHash => bool available) public override(IAvailabilityOracle) isAvailable; - - /** - * @notice Publishes transactions and marks its commitment, the TxsEffectsHash, as available - * @param _body - The block body - * @return txsEffectsHash - The TxsEffectsHash - */ - function publish(bytes calldata _body) external override(IAvailabilityOracle) returns (bytes32) { - bytes32 txsEffectsHash = TxsDecoder.decode(_body); - isAvailable[txsEffectsHash] = true; - - emit TxsPublished(txsEffectsHash); - - return txsEffectsHash; - } -} diff --git a/l1-contracts/src/core/interfaces/IAvailabilityOracle.sol b/l1-contracts/src/core/interfaces/IAvailabilityOracle.sol deleted file mode 100644 index 9c5f23ab093..00000000000 --- a/l1-contracts/src/core/interfaces/IAvailabilityOracle.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2024 Aztec Labs. -pragma solidity >=0.8.18; - -interface IAvailabilityOracle { - event TxsPublished(bytes32 txsEffectsHash); - - function publish(bytes calldata _body) external returns (bytes32); - - function isAvailable(bytes32 _txsEffectsHash) external view returns (bool); -} diff --git a/l1-contracts/src/core/interfaces/IRollup.sol b/l1-contracts/src/core/interfaces/IRollup.sol index febd60047fd..8fff6e6a5bd 100644 --- a/l1-contracts/src/core/interfaces/IRollup.sol +++ b/l1-contracts/src/core/interfaces/IRollup.sol @@ -25,6 +25,7 @@ interface IRollup { SignatureLib.Signature[] memory _signatures, bytes32 _digest, uint256 _currentTime, + bytes32 _txsEffecstHash, DataStructures.ExecutionFlags memory _flags ) external view; @@ -41,19 +42,6 @@ interface IRollup { SignatureLib.Signature[] memory _signatures, bytes calldata _body ) external; - function propose( - bytes calldata _header, - bytes32 _archive, - bytes32 _blockHash, - bytes calldata _body - ) external; - function propose(bytes calldata _header, bytes32 _archive, bytes32 _blockHash) external; - function propose( - bytes calldata _header, - bytes32 _archive, - bytes32 _blockHash, - SignatureLib.Signature[] memory _signatures - ) external; function submitBlockRootProof( bytes calldata _header, @@ -77,4 +65,5 @@ interface IRollup { function archive() external view returns (bytes32); function archiveAt(uint256 _blockNumber) external view returns (bytes32); + function computeTxsEffectsHash(bytes calldata _body) external view returns (bytes32); } diff --git a/l1-contracts/src/core/libraries/MerkleLib.sol b/l1-contracts/src/core/libraries/MerkleLib.sol index 89dc020a5a2..9d3c66d7f58 100644 --- a/l1-contracts/src/core/libraries/MerkleLib.sol +++ b/l1-contracts/src/core/libraries/MerkleLib.sol @@ -59,15 +59,15 @@ library MerkleLib { * @return (min, max) - The min and max path sizes. */ function computeMinMaxPathLength(uint256 _numTxs) internal pure returns (uint256, uint256) { - uint256 numTxs = _numTxs < 2 ? 2 : _numTxs; + uint256 adjustedNumTxs = _numTxs < 2 ? 2 : _numTxs; uint256 numSubtrees = 0; uint256 currentSubtreeSize = 1; uint256 currentSubtreeHeight = 0; uint256 firstSubtreeHeight; uint256 finalSubtreeHeight; - while (numTxs != 0) { + while (adjustedNumTxs != 0) { // If size & txs == 0, the subtree doesn't exist for this number of txs - if (currentSubtreeSize & numTxs == 0) { + if (currentSubtreeSize & adjustedNumTxs == 0) { currentSubtreeSize <<= 1; currentSubtreeHeight++; continue; @@ -75,8 +75,8 @@ library MerkleLib { // Assign the smallest rightmost subtree height if (numSubtrees == 0) finalSubtreeHeight = currentSubtreeHeight; // Assign the largest leftmost subtree height - if (numTxs - currentSubtreeSize == 0) firstSubtreeHeight = currentSubtreeHeight; - numTxs -= currentSubtreeSize; + if (adjustedNumTxs == 0) firstSubtreeHeight = currentSubtreeHeight; + adjustedNumTxs -= currentSubtreeSize; currentSubtreeSize <<= 1; currentSubtreeHeight++; numSubtrees++; diff --git a/l1-contracts/terraform/main.tf b/l1-contracts/terraform/main.tf index 4b7a1877459..7b9c55131aa 100644 --- a/l1-contracts/terraform/main.tf +++ b/l1-contracts/terraform/main.tf @@ -20,15 +20,6 @@ output "rollup_contract_address" { value = var.ROLLUP_CONTRACT_ADDRESS } -variable "AVAILABILITY_ORACLE_CONTRACT_ADDRESS" { - type = string - default = "" -} - -output "availability_oracle_contract_address" { - value = var.AVAILABILITY_ORACLE_CONTRACT_ADDRESS -} - variable "REGISTRY_CONTRACT_ADDRESS" { type = string default = "" diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index c908099f6a0..a772efccc80 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -15,7 +15,7 @@ import {Rollup} from "../src/core/Rollup.sol"; import {IFeeJuicePortal} from "../src/core/interfaces/IFeeJuicePortal.sol"; import {FeeJuicePortal} from "../src/core/FeeJuicePortal.sol"; import {Leonidas} from "../src/core/sequencer_selection/Leonidas.sol"; -import {AvailabilityOracle} from "../src/core/availability_oracle/AvailabilityOracle.sol"; +import {SignatureLib} from "../src/core/sequencer_selection/SignatureLib.sol"; import {NaiveMerkle} from "./merkle/Naive.sol"; import {MerkleTestUtil} from "./merkle/TestUtil.sol"; import {PortalERC20} from "./portals/PortalERC20.sol"; @@ -37,7 +37,7 @@ contract RollupTest is DecoderBase { PortalERC20 internal portalERC20; FeeJuicePortal internal feeJuicePortal; - AvailabilityOracle internal availabilityOracle; + SignatureLib.Signature[] internal signatures; /** * @notice Set up the contracts needed for the tests with time aligned to the provided block name @@ -53,7 +53,6 @@ contract RollupTest is DecoderBase { } registry = new Registry(address(this)); - availabilityOracle = new AvailabilityOracle(); portalERC20 = new PortalERC20(); feeJuicePortal = new FeeJuicePortal(address(this)); portalERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); @@ -62,7 +61,6 @@ contract RollupTest is DecoderBase { ); rollup = new Rollup( registry, - availabilityOracle, IFeeJuicePortal(address(feeJuicePortal)), bytes32(0), address(this), @@ -84,14 +82,10 @@ contract RollupTest is DecoderBase { bytes32 archive = data.archive; bytes memory body = data.body; - // Progress time as necessary - vm.warp(max(block.timestamp, data.decodedHeader.globalVariables.timestamp)); - availabilityOracle.publish(body); - // We jump to the time of the block. (unless it is in the past) vm.warp(max(block.timestamp, data.decodedHeader.globalVariables.timestamp)); - rollup.propose(header, archive, bytes32(0)); + rollup.propose(header, archive, bytes32(0), signatures, body); rollup.submitBlockRootProof(header, archive, bytes32(0), "", ""); @@ -199,7 +193,6 @@ contract RollupTest is DecoderBase { assembly { mstore(add(header, add(0x20, 0x0248)), feeAmount) } - availabilityOracle.publish(body); assertEq(portalERC20.balanceOf(address(rollup)), 0, "invalid rollup balance"); @@ -213,7 +206,7 @@ contract RollupTest is DecoderBase { assertEq(coinbaseBalance, 0, "invalid initial coinbase balance"); // Assert that balance have NOT been increased by proposing the block - rollup.propose(header, archive, bytes32(0)); + rollup.propose(header, archive, bytes32(0), signatures, body); assertEq(portalERC20.balanceOf(coinbase), 0, "invalid coinbase balance"); vm.expectRevert( @@ -260,8 +253,7 @@ contract RollupTest is DecoderBase { bytes memory body = data.body; vm.warp(max(block.timestamp, data.decodedHeader.globalVariables.timestamp)); - availabilityOracle.publish(body); - rollup.propose(header, archive, bytes32(0)); + rollup.propose(header, archive, bytes32(0), signatures, body); vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__NonSequentialProving.selector)); rollup.submitBlockRootProof(header, archive, bytes32(0), "", ""); @@ -296,10 +288,8 @@ contract RollupTest is DecoderBase { mstore(add(header, add(0x20, 0x0174)), 0x420) } - availabilityOracle.publish(body); - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidBlockNumber.selector, 1, 0x420)); - rollup.propose(header, archive, bytes32(0)); + rollup.propose(header, archive, bytes32(0), signatures, body); } function testRevertInvalidChainId() public setUpFor("empty_block_1") { @@ -313,10 +303,8 @@ contract RollupTest is DecoderBase { mstore(add(header, add(0x20, 0x0134)), 0x420) } - availabilityOracle.publish(body); - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidChainId.selector, 31337, 0x420)); - rollup.propose(header, archive, bytes32(0)); + rollup.propose(header, archive, bytes32(0), signatures, body); } function testRevertInvalidVersion() public setUpFor("empty_block_1") { @@ -329,10 +317,8 @@ contract RollupTest is DecoderBase { mstore(add(header, add(0x20, 0x0154)), 0x420) } - availabilityOracle.publish(body); - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, 1, 0x420)); - rollup.propose(header, archive, bytes32(0)); + rollup.propose(header, archive, bytes32(0), signatures, body); } function testRevertInvalidTimestamp() public setUpFor("empty_block_1") { @@ -350,10 +336,8 @@ contract RollupTest is DecoderBase { mstore(add(header, add(0x20, 0x01b4)), badTs) } - availabilityOracle.publish(body); - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidTimestamp.selector, realTs, badTs)); - rollup.propose(header, archive, bytes32(0)); + rollup.propose(header, archive, bytes32(0), signatures, body); } function testBlocksWithAssumeProven() public setUpFor("mixed_block_1") { @@ -452,9 +436,7 @@ contract RollupTest is DecoderBase { _populateInbox(full.populate.sender, full.populate.recipient, full.populate.l1ToL2Content); - availabilityOracle.publish(body); - - rollup.propose(header, archive, bytes32(0)); + rollup.propose(header, archive, bytes32(0), signatures, body); if (_submitProof) { uint256 pre = rollup.provenBlockCount(); diff --git a/l1-contracts/test/portals/TokenPortal.t.sol b/l1-contracts/test/portals/TokenPortal.t.sol index 6241c57880e..96104d54ddb 100644 --- a/l1-contracts/test/portals/TokenPortal.t.sol +++ b/l1-contracts/test/portals/TokenPortal.t.sol @@ -4,7 +4,6 @@ import "forge-std/Test.sol"; // Rollup Processor import {Rollup} from "../../src/core/Rollup.sol"; -import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol"; import {Constants} from "../../src/core/libraries/ConstantsGen.sol"; import {Registry} from "../../src/core/messagebridge/Registry.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; @@ -61,14 +60,8 @@ contract TokenPortalTest is Test { function setUp() public { registry = new Registry(address(this)); portalERC20 = new PortalERC20(); - rollup = new Rollup( - registry, - new AvailabilityOracle(), - IFeeJuicePortal(address(0)), - bytes32(0), - address(this), - new address[](0) - ); + rollup = + new Rollup(registry, IFeeJuicePortal(address(0)), bytes32(0), address(this), new address[](0)); inbox = rollup.INBOX(); outbox = rollup.OUTBOX(); diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index 06269177402..0f506b279ef 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -4,7 +4,6 @@ import "forge-std/Test.sol"; // Rollup Processor import {Rollup} from "../../src/core/Rollup.sol"; -import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol"; import {Registry} from "../../src/core/messagebridge/Registry.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; import {DataStructures as PortalDataStructures} from "./DataStructures.sol"; @@ -53,14 +52,8 @@ contract UniswapPortalTest is Test { vm.selectFork(forkId); registry = new Registry(address(this)); - rollup = new Rollup( - registry, - new AvailabilityOracle(), - IFeeJuicePortal(address(0)), - bytes32(0), - address(this), - new address[](0) - ); + rollup = + new Rollup(registry, IFeeJuicePortal(address(0)), bytes32(0), address(this), new address[](0)); registry.upgrade(address(rollup)); daiTokenPortal = new TokenPortal(); diff --git a/l1-contracts/test/sparta/Sparta.t.sol b/l1-contracts/test/sparta/Sparta.t.sol index a3e4eac2d2d..e165d8b7bec 100644 --- a/l1-contracts/test/sparta/Sparta.t.sol +++ b/l1-contracts/test/sparta/Sparta.t.sol @@ -15,7 +15,6 @@ import {Outbox} from "../../src/core/messagebridge/Outbox.sol"; import {Errors} from "../../src/core/libraries/Errors.sol"; import {Rollup} from "../../src/core/Rollup.sol"; import {Leonidas} from "../../src/core/sequencer_selection/Leonidas.sol"; -import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol"; import {NaiveMerkle} from "../merkle/Naive.sol"; import {MerkleTestUtil} from "../merkle/TestUtil.sol"; import {PortalERC20} from "../portals/PortalERC20.sol"; @@ -37,8 +36,6 @@ contract SpartaTest is DecoderBase { TxsDecoderHelper internal txsHelper; PortalERC20 internal portalERC20; - AvailabilityOracle internal availabilityOracle; - mapping(address validator => uint256 privateKey) internal privateKeys; SignatureLib.Signature internal emptySignature; @@ -66,15 +63,9 @@ contract SpartaTest is DecoderBase { } registry = new Registry(address(this)); - availabilityOracle = new AvailabilityOracle(); portalERC20 = new PortalERC20(); rollup = new Rollup( - registry, - availabilityOracle, - IFeeJuicePortal(address(0)), - bytes32(0), - address(this), - initialValidators + registry, IFeeJuicePortal(address(0)), bytes32(0), address(this), initialValidators ); inbox = Inbox(address(rollup.INBOX())); outbox = Outbox(address(rollup.OUTBOX())); @@ -175,8 +166,6 @@ contract SpartaTest is DecoderBase { _populateInbox(full.populate.sender, full.populate.recipient, full.populate.l1ToL2Content); - availabilityOracle.publish(body); - ree.proposer = rollup.getCurrentProposer(); ree.shouldRevert = false; @@ -219,13 +208,15 @@ contract SpartaTest is DecoderBase { } vm.prank(ree.proposer); - rollup.propose(header, archive, bytes32(0), signatures); + rollup.propose(header, archive, bytes32(0), signatures, body); if (ree.shouldRevert) { return; } } else { - rollup.propose(header, archive, bytes32(0)); + SignatureLib.Signature[] memory signatures = new SignatureLib.Signature[](0); + + rollup.propose(header, archive, bytes32(0), signatures, body); } assertEq(_expectRevert, ree.shouldRevert, "Does not match revert expectation"); diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index ee7f955f954..95847d27b6a 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -1,5 +1,4 @@ import { - type Body, EncryptedL2BlockL2Logs, EncryptedNoteL2BlockL2Logs, L2Block, @@ -9,7 +8,7 @@ import { import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { sleep } from '@aztec/foundation/sleep'; -import { AvailabilityOracleAbi, type InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { type InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { type MockProxy, mock } from 'jest-mock-extended'; import { @@ -31,7 +30,6 @@ describe('Archiver', () => { const rollupAddress = EthAddress.ZERO; const inboxAddress = EthAddress.ZERO; const registryAddress = EthAddress.ZERO; - const availabilityOracleAddress = EthAddress.ZERO; const blockNumbers = [1, 2, 3]; let publicClient: MockProxy>; @@ -62,7 +60,6 @@ describe('Archiver', () => { archiver = new Archiver( publicClient, rollupAddress, - availabilityOracleAddress, inboxAddress, registryAddress, archiverStore, @@ -75,14 +72,12 @@ describe('Archiver', () => { const blocks = blockNumbers.map(x => L2Block.random(x, 4, x, x + 1, 2, 2)); blocks.forEach((b, i) => (b.header.globalVariables.timestamp = new Fr(now + 1000 * (i + 1)))); - const publishTxs = blocks.map(block => block.body).map(makePublishTx); const rollupTxs = blocks.map(makeRollupTx); publicClient.getBlockNumber.mockResolvedValueOnce(2500n).mockResolvedValueOnce(2600n).mockResolvedValueOnce(2700n); mockGetLogs({ messageSent: [makeMessageSentEvent(98n, 1n, 0n), makeMessageSentEvent(99n, 1n, 1n)], - txPublished: [makeTxsPublishedEvent(101n, blocks[0].body.getTxsEffectsHash())], L2BlockProposed: [makeL2BlockProposedEvent(101n, 1n)], proofVerified: [makeProofVerifiedEvent(102n, 1n, proverId)], }); @@ -94,17 +89,11 @@ describe('Archiver', () => { makeMessageSentEvent(2505n, 2n, 2n), makeMessageSentEvent(2506n, 3n, 1n), ], - txPublished: [ - makeTxsPublishedEvent(2510n, blocks[1].body.getTxsEffectsHash()), - makeTxsPublishedEvent(2520n, blocks[2].body.getTxsEffectsHash()), - ], L2BlockProposed: [makeL2BlockProposedEvent(2510n, 2n), makeL2BlockProposedEvent(2520n, 3n)], }); - publicClient.getTransaction.mockResolvedValueOnce(publishTxs[0]); publicClient.getTransaction.mockResolvedValueOnce(rollupTxs[0]); - publishTxs.slice(1).forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx)); rollupTxs.slice(1).forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx)); await archiver.start(false); @@ -183,7 +172,6 @@ describe('Archiver', () => { archiver = new Archiver( publicClient, rollupAddress, - availabilityOracleAddress, inboxAddress, registryAddress, archiverStore, @@ -196,7 +184,6 @@ describe('Archiver', () => { const blocks = blockNumbers.map(x => L2Block.random(x, 4, x, x + 1, 2, 2)); - const publishTxs = blocks.map(block => block.body).map(makePublishTx); const rollupTxs = blocks.map(makeRollupTx); // Here we set the current L1 block number to 102. L1 to L2 messages after this should not be read. @@ -204,16 +191,11 @@ describe('Archiver', () => { mockGetLogs({ messageSent: [makeMessageSentEvent(66n, 1n, 0n), makeMessageSentEvent(68n, 1n, 1n)], - txPublished: [ - makeTxsPublishedEvent(70n, blocks[0].body.getTxsEffectsHash()), - makeTxsPublishedEvent(80n, blocks[1].body.getTxsEffectsHash()), - ], L2BlockProposed: [makeL2BlockProposedEvent(70n, 1n), makeL2BlockProposedEvent(80n, 2n)], }); mockGetLogs({}); - publishTxs.slice(0, numL2BlocksInTest).forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx)); rollupTxs.slice(0, numL2BlocksInTest).forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx)); await archiver.start(false); @@ -230,13 +212,11 @@ describe('Archiver', () => { // logs should be created in order of how archiver syncs. const mockGetLogs = (logs: { messageSent?: ReturnType[]; - txPublished?: ReturnType[]; L2BlockProposed?: ReturnType[]; proofVerified?: ReturnType[]; }) => { publicClient.getLogs .mockResolvedValueOnce(logs.messageSent ?? []) - .mockResolvedValueOnce(logs.txPublished ?? []) .mockResolvedValueOnce(logs.L2BlockProposed ?? []) .mockResolvedValueOnce(logs.proofVerified ?? []); }; @@ -256,21 +236,6 @@ function makeL2BlockProposedEvent(l1BlockNum: bigint, l2BlockNum: bigint) { } as Log; } -/** - * Makes a fake TxsPublished event for testing purposes. - * @param l1BlockNum - L1 block number. - * @param txsEffectsHash - txsEffectsHash for the body. - * @returns A TxsPublished event log. - */ -function makeTxsPublishedEvent(l1BlockNum: bigint, txsEffectsHash: Buffer) { - return { - blockNumber: l1BlockNum, - args: { - txsEffectsHash: txsEffectsHash.toString('hex'), - }, - } as Log; -} - /** * Makes fake L1ToL2 MessageSent events for testing purposes. * @param l1BlockNum - L1 block number. @@ -306,27 +271,13 @@ function makeProofVerifiedEvent(l1BlockNum: bigint, l2BlockNumber: bigint, prove */ function makeRollupTx(l2Block: L2Block) { const header = toHex(l2Block.header.toBuffer()); + const body = toHex(l2Block.body.toBuffer()); const archive = toHex(l2Block.archive.root.toBuffer()); const blockHash = toHex(l2Block.header.hash().toBuffer()); const input = encodeFunctionData({ abi: RollupAbi, functionName: 'propose', - args: [header, archive, blockHash], - }); - return { input } as Transaction; -} - -/** - * Makes a fake availability oracle tx for testing purposes. - * @param blockBody - The block body posted by the simulated tx. - * @returns A fake tx with calldata that corresponds to calling publish in the Availability Oracle contract. - */ -function makePublishTx(blockBody: Body) { - const body = toHex(blockBody.toBuffer()); - const input = encodeFunctionData({ - abi: AvailabilityOracleAbi, - functionName: 'publish', - args: [body], + args: [header, archive, blockHash, [], body], }); return { input } as Transaction; } diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index dec28dc5228..5015c0a1e35 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -2,7 +2,7 @@ import { type FromLogType, type GetUnencryptedLogsResponse, type L1ToL2MessageSource, - L2Block, + type L2Block, type L2BlockL2Logs, type L2BlockSource, type L2LogsSource, @@ -46,16 +46,10 @@ import { type Chain, type HttpTransport, type PublicClient, createPublicClient, import { type ArchiverDataStore } from './archiver_store.js'; import { type ArchiverConfig } from './config.js'; -import { - retrieveBlockBodiesFromAvailabilityOracle, - retrieveBlockMetadataFromRollup, - retrieveL1ToL2Messages, - retrieveL2ProofVerifiedEvents, -} from './data_retrieval.js'; +import { retrieveBlockFromRollup, retrieveL1ToL2Messages, retrieveL2ProofVerifiedEvents } from './data_retrieval.js'; import { getL1BlockTime } from './eth_log_handlers.js'; import { ArchiverInstrumentation } from './instrumentation.js'; import { type SingletonDataRetrieval } from './structs/data_retrieval.js'; -import { type L1Published } from './structs/published.js'; /** * Helper interface to combine all sources this archiver implementation provides. @@ -86,7 +80,6 @@ export class Archiver implements ArchiveSource { constructor( private readonly publicClient: PublicClient, private readonly rollupAddress: EthAddress, - private readonly availabilityOracleAddress: EthAddress, private readonly inboxAddress: EthAddress, private readonly registryAddress: EthAddress, private readonly store: ArchiverDataStore, @@ -119,7 +112,6 @@ export class Archiver implements ArchiveSource { const archiver = new Archiver( publicClient, config.l1Contracts.rollupAddress, - config.l1Contracts.availabilityOracleAddress, config.l1Contracts.inboxAddress, config.l1Contracts.registryAddress, archiverStore, @@ -247,72 +239,26 @@ export class Archiver implements ArchiveSource { // Read all data from chain and then write to our stores at the end const nextExpectedL2BlockNum = BigInt((await this.store.getSynchedL2BlockNumber()) + 1); - this.log.debug(`Retrieving block bodies from ${blockBodiesSynchedTo + 1n} to ${currentL1BlockNumber}`); - const retrievedBlockBodies = await retrieveBlockBodiesFromAvailabilityOracle( + this.log.debug(`Retrieving blocks from ${blocksSynchedTo + 1n} to ${currentL1BlockNumber}`); + const retrievedBlocks = await retrieveBlockFromRollup( this.publicClient, - this.availabilityOracleAddress, + this.rollupAddress, blockUntilSynced, - blockBodiesSynchedTo + 1n, + blocksSynchedTo + 1n, currentL1BlockNumber, + nextExpectedL2BlockNum, ); - this.log.debug( - `Retrieved ${retrievedBlockBodies.retrievedData.length} block bodies up to L1 block ${retrievedBlockBodies.lastProcessedL1BlockNumber}`, - ); - await this.store.addBlockBodies(retrievedBlockBodies); - - // Now that we have block bodies we will retrieve block metadata and build L2 blocks from the bodies and the metadata - let retrievedBlocks: L1Published[]; - let lastProcessedL1BlockNumber: bigint; - { - // @todo @LHerskind Investigate how necessary that nextExpectedL2BlockNum really is. - // Also, I would expect it to break horribly if we have a reorg. - this.log.debug(`Retrieving block metadata from ${blocksSynchedTo + 1n} to ${currentL1BlockNumber}`); - const retrievedBlockMetadata = await retrieveBlockMetadataFromRollup( - this.publicClient, - this.rollupAddress, - blockUntilSynced, - blocksSynchedTo + 1n, - currentL1BlockNumber, - nextExpectedL2BlockNum, - ); - - const retrievedBodyHashes = retrievedBlockMetadata.map(([header]) => header.contentCommitment.txsEffectsHash); - - // @note @LHerskind We will occasionally be hitting this point BEFORE, we have actually retrieved the bodies. - // The main reason this have not been an issue earlier is because: - // i) the design previously published the body in one tx and the header in another, - // which in an anvil auto mine world mean that they are separate blocks. - // ii) We have been lucky that latency have been small enough to not matter. - const blockBodiesFromStore = await this.store.getBlockBodies(retrievedBodyHashes); + // Add the body - if (retrievedBlockMetadata.length !== blockBodiesFromStore.length) { - this.log.warn('Block headers length does not equal block bodies length'); - } - - const blocks: L1Published[] = []; - for (let i = 0; i < retrievedBlockMetadata.length; i++) { - const [header, archive, l1] = retrievedBlockMetadata[i]; - const blockBody = blockBodiesFromStore[i]; - if (blockBody) { - blocks.push({ data: new L2Block(archive, header, blockBody), l1 }); - } else { - this.log.warn(`Block body not found for block ${header.globalVariables.blockNumber.toBigInt()}.`); - } - } - - (blocks.length ? this.log.verbose : this.log.debug)( - `Retrieved ${blocks.length || 'no'} new L2 blocks between L1 blocks ${ - blocksSynchedTo + 1n - } and ${currentL1BlockNumber}.`, - ); + (retrievedBlocks.length ? this.log.verbose : this.log.debug)( + `Retrieved ${retrievedBlocks.length || 'no'} new L2 blocks between L1 blocks ${ + blocksSynchedTo + 1n + } and ${currentL1BlockNumber}.`, + ); - retrievedBlocks = blocks; - lastProcessedL1BlockNumber = - retrievedBlockMetadata.length > 0 - ? retrievedBlockMetadata[retrievedBlockMetadata.length - 1][2].blockNumber - : blocksSynchedTo; - } + const lastProcessedL1BlockNumber = + retrievedBlocks.length > 0 ? retrievedBlocks[retrievedBlocks.length - 1].l1.blockNumber : blocksSynchedTo; this.log.debug( `Processing retrieved blocks ${retrievedBlocks @@ -320,29 +266,33 @@ export class Archiver implements ArchiveSource { .join(',')} with last processed L1 block ${lastProcessedL1BlockNumber}`, ); - await Promise.all( - retrievedBlocks.map(block => { - const noteEncryptedLogs = block.data.body.noteEncryptedLogs; - const encryptedLogs = block.data.body.encryptedLogs; - const unencryptedLogs = block.data.body.unencryptedLogs; - return this.store.addLogs(noteEncryptedLogs, encryptedLogs, unencryptedLogs, block.data.number); - }), - ); + if (retrievedBlocks.length > 0) { + await Promise.all( + retrievedBlocks.map(block => { + const noteEncryptedLogs = block.data.body.noteEncryptedLogs; + const encryptedLogs = block.data.body.encryptedLogs; + const unencryptedLogs = block.data.body.unencryptedLogs; + return this.store.addLogs(noteEncryptedLogs, encryptedLogs, unencryptedLogs, block.data.number); + }), + ); - // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them - await Promise.all( - retrievedBlocks.map(async block => { - const blockLogs = block.data.body.txEffects - .flatMap(txEffect => (txEffect ? [txEffect.unencryptedLogs] : [])) - .flatMap(txLog => txLog.unrollLogs()); - await this.storeRegisteredContractClasses(blockLogs, block.data.number); - await this.storeDeployedContractInstances(blockLogs, block.data.number); - await this.storeBroadcastedIndividualFunctions(blockLogs, block.data.number); - }), - ); + // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them + await Promise.all( + retrievedBlocks.map(async block => { + const blockLogs = block.data.body.txEffects + .flatMap(txEffect => (txEffect ? [txEffect.unencryptedLogs] : [])) + .flatMap(txLog => txLog.unrollLogs()); + await this.storeRegisteredContractClasses(blockLogs, block.data.number); + await this.storeDeployedContractInstances(blockLogs, block.data.number); + await this.storeBroadcastedIndividualFunctions(blockLogs, block.data.number); + }), + ); - if (retrievedBlocks.length > 0) { const timer = new Timer(); + await this.store.addBlockBodies({ + lastProcessedL1BlockNumber: lastProcessedL1BlockNumber, + retrievedData: retrievedBlocks.map(b => b.data.body), + }); await this.store.addBlocks(retrievedBlocks); this.instrumentation.processNewBlocks( timer.ms() / retrievedBlocks.length, diff --git a/yarn-project/archiver/src/archiver/data_retrieval.ts b/yarn-project/archiver/src/archiver/data_retrieval.ts index 81aca60a783..5827296d3f1 100644 --- a/yarn-project/archiver/src/archiver/data_retrieval.ts +++ b/yarn-project/archiver/src/archiver/data_retrieval.ts @@ -1,5 +1,5 @@ -import { type Body, type InboxLeaf } from '@aztec/circuit-types'; -import { type AppendOnlyTreeSnapshot, Fr, type Header, type Proof } from '@aztec/circuits.js'; +import { type InboxLeaf, type L2Block } from '@aztec/circuit-types'; +import { Fr, type Proof } from '@aztec/circuits.js'; import { type EthAddress } from '@aztec/foundation/eth-address'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { RollupAbi } from '@aztec/l1-artifacts'; @@ -10,25 +10,23 @@ import { getBlockProofFromSubmitProofTx, getL2BlockProposedLogs, getMessageSentLogs, - getTxsPublishedLogs, processL2BlockProposedLogs, processMessageSentLogs, - processTxsPublishedLogs, } from './eth_log_handlers.js'; import { type DataRetrieval } from './structs/data_retrieval.js'; -import { type L1PublishedData } from './structs/published.js'; +import { type L1Published } from './structs/published.js'; /** - * Fetches new L2 block metadata (header, archive snapshot). + * Fetches new L2 blocks. * @param publicClient - The viem public client to use for transaction retrieval. * @param rollupAddress - The address of the rollup contract. * @param blockUntilSynced - If true, blocks until the archiver has fully synced. * @param searchStartBlock - The block number to use for starting the search. * @param searchEndBlock - The highest block number that we should search up to. * @param expectedNextL2BlockNum - The next L2 block number that we expect to find. - * @returns An array of tuples representing block metadata including the header, archive tree snapshot; as well as the next eth block to search from. + * @returns An array of block; as well as the next eth block to search from. */ -export async function retrieveBlockMetadataFromRollup( +export async function retrieveBlockFromRollup( publicClient: PublicClient, rollupAddress: EthAddress, blockUntilSynced: boolean, @@ -36,8 +34,8 @@ export async function retrieveBlockMetadataFromRollup( searchEndBlock: bigint, expectedNextL2BlockNum: bigint, logger: DebugLogger = createDebugLogger('aztec:archiver'), -): Promise<[Header, AppendOnlyTreeSnapshot, L1PublishedData][]> { - const retrievedBlockMetadata: [Header, AppendOnlyTreeSnapshot, L1PublishedData][] = []; +): Promise[]> { + const retrievedBlocks: L1Published[] = []; do { if (searchStartBlock > searchEndBlock) { break; @@ -57,56 +55,12 @@ export async function retrieveBlockMetadataFromRollup( `Got L2 block processed logs for ${L2BlockProposedLogs[0].blockNumber}-${lastLog.blockNumber} between ${searchStartBlock}-${searchEndBlock} L1 blocks`, ); - const newBlockMetadata = await processL2BlockProposedLogs( - publicClient, - expectedNextL2BlockNum, - L2BlockProposedLogs, - ); - retrievedBlockMetadata.push(...newBlockMetadata); + const newBlocks = await processL2BlockProposedLogs(publicClient, expectedNextL2BlockNum, L2BlockProposedLogs); + retrievedBlocks.push(...newBlocks); searchStartBlock = lastLog.blockNumber! + 1n; - expectedNextL2BlockNum += BigInt(newBlockMetadata.length); - } while (blockUntilSynced && searchStartBlock <= searchEndBlock); - return retrievedBlockMetadata; -} - -/** - * Fetches new L2 block bodies and their hashes. - * @param publicClient - The viem public client to use for transaction retrieval. - * @param availabilityOracleAddress - The address of the availability oracle contract. - * @param blockUntilSynced - If true, blocks until the archiver has fully synced. - * @param searchStartBlock - The block number to use for starting the search. - * @param searchEndBlock - The highest block number that we should search up to. - * @returns A array of L2 block bodies as well as the next eth block to search from - */ -export async function retrieveBlockBodiesFromAvailabilityOracle( - publicClient: PublicClient, - availabilityOracleAddress: EthAddress, - blockUntilSynced: boolean, - searchStartBlock: bigint, - searchEndBlock: bigint, -): Promise> { - const retrievedBlockBodies: Body[] = []; - - do { - if (searchStartBlock > searchEndBlock) { - break; - } - const l2TxsPublishedLogs = await getTxsPublishedLogs( - publicClient, - availabilityOracleAddress, - searchStartBlock, - searchEndBlock, - ); - if (l2TxsPublishedLogs.length === 0) { - break; - } - - const newBlockBodies = await processTxsPublishedLogs(publicClient, l2TxsPublishedLogs); - retrievedBlockBodies.push(...newBlockBodies.map(([body]) => body)); - searchStartBlock = l2TxsPublishedLogs[l2TxsPublishedLogs.length - 1].blockNumber + 1n; + expectedNextL2BlockNum += BigInt(newBlocks.length); } while (blockUntilSynced && searchStartBlock <= searchEndBlock); - - return { lastProcessedL1BlockNumber: searchStartBlock - 1n, retrievedData: retrievedBlockBodies }; + return retrievedBlocks; } /** diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index 990cccde1ae..f0fdf6a1075 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -1,22 +1,13 @@ -import { Body, InboxLeaf } from '@aztec/circuit-types'; +import { Body, InboxLeaf, L2Block, type ViemSignature } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, Header, Proof } from '@aztec/circuits.js'; import { type EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { numToUInt32BE } from '@aztec/foundation/serialize'; -import { AvailabilityOracleAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; -import { - type Hex, - type Log, - type PublicClient, - decodeFunctionData, - getAbiItem, - getAddress, - hexToBytes, - slice, -} from 'viem'; +import { type Hex, type Log, type PublicClient, decodeFunctionData, getAbiItem, getAddress, hexToBytes } from 'viem'; -import { type L1PublishedData } from './structs/published.js'; +import { type L1Published, type L1PublishedData } from './structs/published.js'; /** * Processes newly received MessageSent (L1 to L2) logs. @@ -39,25 +30,21 @@ export function processMessageSentLogs( * @param publicClient - The viem public client to use for transaction retrieval. * @param expectedL2BlockNumber - The next expected L2 block number. * @param logs - L2BlockProposed logs. - * @returns - An array of tuples representing block metadata including the header, archive tree snapshot. + * @returns - An array blocks. */ export async function processL2BlockProposedLogs( publicClient: PublicClient, expectedL2BlockNumber: bigint, logs: Log[], -): Promise<[Header, AppendOnlyTreeSnapshot, L1PublishedData][]> { - const retrievedBlockMetadata: [Header, AppendOnlyTreeSnapshot, L1PublishedData][] = []; +): Promise[]> { + const retrievedBlocks: L1Published[] = []; for (const log of logs) { const blockNum = log.args.blockNumber; if (blockNum !== expectedL2BlockNumber) { throw new Error('Block number mismatch. Expected: ' + expectedL2BlockNumber + ' but got: ' + blockNum + '.'); } // TODO: Fetch blocks from calldata in parallel - const [header, archive] = await getBlockMetadataFromRollupTx( - publicClient, - log.transactionHash!, - log.args.blockNumber, - ); + const block = await getBlockFromRollupTx(publicClient, log.transactionHash!, log.args.blockNumber); const l1: L1PublishedData = { blockNumber: log.blockNumber, @@ -65,11 +52,11 @@ export async function processL2BlockProposedLogs( timestamp: await getL1BlockTime(publicClient, log.blockNumber), }; - retrievedBlockMetadata.push([header, archive, l1]); + retrievedBlocks.push({ data: block, l1 }); expectedL2BlockNumber++; } - return retrievedBlockMetadata; + return retrievedBlocks; } export async function getL1BlockTime(publicClient: PublicClient, blockNumber: bigint): Promise { @@ -77,33 +64,20 @@ export async function getL1BlockTime(publicClient: PublicClient, blockNumber: bi return block.timestamp; } -export async function processTxsPublishedLogs( - publicClient: PublicClient, - logs: Log[], -): Promise<[Body, Buffer][]> { - const retrievedBlockBodies: [Body, Buffer][] = []; - for (const log of logs) { - const newBlockBody = await getBlockBodiesFromAvailabilityOracleTx(publicClient, log.transactionHash!); - retrievedBlockBodies.push([newBlockBody, Buffer.from(hexToBytes(log.args.txsEffectsHash))]); - } - - return retrievedBlockBodies; -} - /** - * Gets block metadata (header and archive snapshot) from the calldata of an L1 transaction. + * Gets block from the calldata of an L1 transaction. * Assumes that the block was published from an EOA. * TODO: Add retries and error management. * @param publicClient - The viem public client to use for transaction retrieval. * @param txHash - Hash of the tx that published it. * @param l2BlockNum - L2 block number. - * @returns L2 block metadata (header and archive) from the calldata, deserialized + * @returns L2 block from the calldata, deserialized */ -async function getBlockMetadataFromRollupTx( +async function getBlockFromRollupTx( publicClient: PublicClient, txHash: `0x${string}`, l2BlockNum: bigint, -): Promise<[Header, AppendOnlyTreeSnapshot]> { +): Promise { const { input: data } = await publicClient.getTransaction({ hash: txHash }); const { functionName, args } = decodeFunctionData({ abi: RollupAbi, @@ -113,9 +87,10 @@ async function getBlockMetadataFromRollupTx( if (!(functionName === 'propose')) { throw new Error(`Unexpected method called ${functionName}`); } - const [headerHex, archiveRootHex, _] = args! as readonly [Hex, Hex, Hex]; + const [headerHex, archiveRootHex, , , bodyHex] = args! as readonly [Hex, Hex, Hex, ViemSignature[], Hex]; const header = Header.fromBuffer(Buffer.from(hexToBytes(headerHex))); + const blockBody = Body.fromBuffer(Buffer.from(hexToBytes(bodyHex))); const blockNumberFromHeader = header.globalVariables.blockNumber.toBigInt(); @@ -130,57 +105,7 @@ async function getBlockMetadataFromRollupTx( ]), ); - return [header, archive]; -} - -/** - * Gets block bodies from calldata of an L1 transaction, and deserializes them into Body objects. - * @note Assumes that the block was published using `propose` or `publish`. - * TODO: Add retries and error management. - * @param publicClient - The viem public client to use for transaction retrieval. - * @param txHash - Hash of the tx that published it. - * @returns An L2 block body from the calldata, deserialized - */ -async function getBlockBodiesFromAvailabilityOracleTx( - publicClient: PublicClient, - txHash: `0x${string}`, -): Promise { - const { input: data } = await publicClient.getTransaction({ hash: txHash }); - - // @note Use `forge inspect Rollup methodIdentifiers to get this, - // If using `forge sig` you will get an INVALID value for the case with a struct. - // [ - // "propose(bytes,bytes32,bytes32,(bool,uint8,bytes32,bytes32)[],bytes)": "08978fe9", - // "propose(bytes,bytes32,bytes32,bytes)": "81e6f472", - // "publish(bytes calldata _body)" - // ] - const DATA_INDEX = [4, 3, 0]; - const SUPPORTED_SIGS = ['0x08978fe9', '0x81e6f472', '0x7fd28346']; - - const signature = slice(data, 0, 4); - - if (!SUPPORTED_SIGS.includes(signature)) { - throw new Error(`Unexpected method called ${signature}`); - } - - if (signature === SUPPORTED_SIGS[SUPPORTED_SIGS.length - 1]) { - const { args } = decodeFunctionData({ - abi: AvailabilityOracleAbi, - data, - }); - const [bodyHex] = args! as [Hex]; - const blockBody = Body.fromBuffer(Buffer.from(hexToBytes(bodyHex))); - return blockBody; - } else { - const { args } = decodeFunctionData({ - abi: RollupAbi, - data, - }); - const index = SUPPORTED_SIGS.indexOf(signature); - const bodyHex = args![DATA_INDEX[index]] as Hex; - const blockBody = Body.fromBuffer(Buffer.from(hexToBytes(bodyHex))); - return blockBody; - } + return new L2Block(archive, header, blockBody); } /** @@ -208,31 +133,6 @@ export function getL2BlockProposedLogs( }); } -/** - * Gets relevant `TxsPublished` logs from chain. - * @param publicClient - The viem public client to use for transaction retrieval. - * @param dataAvailabilityOracleAddress - The address of the availability oracle contract. - * @param fromBlock - First block to get logs from (inclusive). - * @param toBlock - Last block to get logs from (inclusive). - * @returns An array of `TxsPublished` logs. - */ -export function getTxsPublishedLogs( - publicClient: PublicClient, - dataAvailabilityOracleAddress: EthAddress, - fromBlock: bigint, - toBlock: bigint, -): Promise[]> { - return publicClient.getLogs({ - address: getAddress(dataAvailabilityOracleAddress.toString()), - event: getAbiItem({ - abi: AvailabilityOracleAbi, - name: 'TxsPublished', - }), - fromBlock, - toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive - }); -} - /** * Get relevant `MessageSent` logs emitted by Inbox on chain. * @param publicClient - The viem public client to use for transaction retrieval. diff --git a/yarn-project/archiver/src/index.ts b/yarn-project/archiver/src/index.ts index 37b0f6da3b6..f23f973101c 100644 --- a/yarn-project/archiver/src/index.ts +++ b/yarn-project/archiver/src/index.ts @@ -13,7 +13,7 @@ export * from './archiver/index.js'; export * from './rpc/index.js'; export * from './factory.js'; -export { retrieveL2ProofVerifiedEvents, retrieveBlockMetadataFromRollup } from './archiver/data_retrieval.js'; +export { retrieveL2ProofVerifiedEvents, retrieveBlockFromRollup } from './archiver/data_retrieval.js'; export { getL2BlockProposedLogs } from './archiver/eth_log_handlers.js'; @@ -37,7 +37,6 @@ async function main() { const archiver = new Archiver( publicClient, l1Contracts.rollupAddress, - l1Contracts.availabilityOracleAddress, l1Contracts.inboxAddress, l1Contracts.registryAddress, archiverStore, diff --git a/yarn-project/aztec-node/src/aztec-node/server.test.ts b/yarn-project/aztec-node/src/aztec-node/server.test.ts index f753431b918..7dbd162fbb9 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.test.ts @@ -69,7 +69,6 @@ describe('aztec node', () => { registryAddress: EthAddress.ZERO, inboxAddress: EthAddress.ZERO, outboxAddress: EthAddress.ZERO, - availabilityOracleAddress: EthAddress.ZERO, }, }, p2p, diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index ed438882142..be8d69c9af8 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -115,8 +115,7 @@ export class AztecNodeService implements AztecNode { `Rollup: ${config.l1Contracts.rollupAddress.toString()}\n` + `Registry: ${config.l1Contracts.registryAddress.toString()}\n` + `Inbox: ${config.l1Contracts.inboxAddress.toString()}\n` + - `Outbox: ${config.l1Contracts.outboxAddress.toString()}\n` + - `Availability Oracle: ${config.l1Contracts.availabilityOracleAddress.toString()}`; + `Outbox: ${config.l1Contracts.outboxAddress.toString()}`; this.log.info(message); } diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index f13bbfd954a..73076d9b456 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -22,7 +22,6 @@ describe('Contract Class', () => { const mockTxReceipt = { type: 'TxReceipt' } as any as TxReceipt; const mockUnconstrainedResultValue = 1; const l1Addresses: L1ContractAddresses = { - availabilityOracleAddress: EthAddress.random(), rollupAddress: EthAddress.random(), registryAddress: EthAddress.random(), inboxAddress: EthAddress.random(), diff --git a/yarn-project/aztec/src/cli/aztec_start_options.ts b/yarn-project/aztec/src/cli/aztec_start_options.ts index 953f07adcb3..4b551d2dc24 100644 --- a/yarn-project/aztec/src/cli/aztec_start_options.ts +++ b/yarn-project/aztec/src/cli/aztec_start_options.ts @@ -132,12 +132,6 @@ export const aztecStartOptions: { [key: string]: AztecStartOption[] } = { defaultValue: undefined, envVar: 'OUTBOX_CONTRACT_ADDRESS', }, - { - flag: '--availability-oracle-address ', - description: 'The deployed L1 availability oracle contract address', - defaultValue: undefined, - envVar: 'AVAILABILITY_ORACLE_CONTRACT_ADDRESS', - }, { flag: '--fee-juice-address ', description: 'The deployed L1 Fee Juice contract address', diff --git a/yarn-project/aztec/src/sandbox.ts b/yarn-project/aztec/src/sandbox.ts index 81e24a94856..200cdcbe04f 100644 --- a/yarn-project/aztec/src/sandbox.ts +++ b/yarn-project/aztec/src/sandbox.ts @@ -14,8 +14,6 @@ import { import { createDebugLogger } from '@aztec/foundation/log'; import { retryUntil } from '@aztec/foundation/retry'; import { - AvailabilityOracleAbi, - AvailabilityOracleBytecode, FeeJuicePortalAbi, FeeJuicePortalBytecode, InboxAbi, @@ -105,10 +103,6 @@ export async function deployContractsToL1( contractAbi: OutboxAbi, contractBytecode: OutboxBytecode, }, - availabilityOracle: { - contractAbi: AvailabilityOracleAbi, - contractBytecode: AvailabilityOracleBytecode, - }, rollup: { contractAbi: RollupAbi, contractBytecode: RollupBytecode, diff --git a/yarn-project/aztec/terraform/node/main.tf b/yarn-project/aztec/terraform/node/main.tf index 4d684d4ed1b..9933df21a32 100644 --- a/yarn-project/aztec/terraform/node/main.tf +++ b/yarn-project/aztec/terraform/node/main.tf @@ -315,10 +315,6 @@ resource "aws_ecs_task_definition" "aztec-node" { name = "REGISTRY_CONTRACT_ADDRESS" value = data.terraform_remote_state.l1_contracts.outputs.registry_contract_address }, - { - name = "AVAILABILITY_ORACLE_CONTRACT_ADDRESS" - value = data.terraform_remote_state.l1_contracts.outputs.availability_oracle_contract_address - }, { name = "FEE_JUICE_CONTRACT_ADDRESS" value = data.terraform_remote_state.l1_contracts.outputs.fee_juice_contract_address diff --git a/yarn-project/aztec/terraform/prover-node/main.tf b/yarn-project/aztec/terraform/prover-node/main.tf index 21bbf2fe783..a9c9a9708ca 100644 --- a/yarn-project/aztec/terraform/prover-node/main.tf +++ b/yarn-project/aztec/terraform/prover-node/main.tf @@ -273,7 +273,6 @@ resource "aws_ecs_task_definition" "aztec-prover-node" { { name = "INBOX_CONTRACT_ADDRESS", value = data.terraform_remote_state.l1_contracts.outputs.inbox_contract_address }, { name = "OUTBOX_CONTRACT_ADDRESS", value = data.terraform_remote_state.l1_contracts.outputs.outbox_contract_address }, { name = "REGISTRY_CONTRACT_ADDRESS", value = data.terraform_remote_state.l1_contracts.outputs.registry_contract_address }, - { name = "AVAILABILITY_ORACLE_CONTRACT_ADDRESS", value = data.terraform_remote_state.l1_contracts.outputs.availability_oracle_contract_address }, { name = "FEE_JUICE_CONTRACT_ADDRESS", value = data.terraform_remote_state.l1_contracts.outputs.fee_juice_contract_address }, { name = "FEE_JUICE_PORTAL_CONTRACT_ADDRESS", value = data.terraform_remote_state.l1_contracts.outputs.FEE_JUICE_PORTAL_CONTRACT_ADDRESS }, diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index c0e63aa43d3..21eba85c30e 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -48,7 +48,7 @@ export class Body { /** * Computes the transactions effects hash for the L2 block - * This hash is also computed in the `AvailabilityOracle`. + * This hash is also computed in the `TxDecoder`. * @returns The txs effects hash. */ getTxsEffectsHash() { diff --git a/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts b/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts index b57bae95ee9..08a4cc2cbf5 100644 --- a/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts +++ b/yarn-project/cli/src/cmds/l1/deploy_l1_contracts.ts @@ -27,7 +27,6 @@ export async function deployL1Contracts( log(`Registry Address: ${l1ContractAddresses.registryAddress.toString()}`); log(`L1 -> L2 Inbox Address: ${l1ContractAddresses.inboxAddress.toString()}`); log(`L2 -> L1 Outbox Address: ${l1ContractAddresses.outboxAddress.toString()}`); - log(`Availability Oracle Address: ${l1ContractAddresses.availabilityOracleAddress.toString()}`); log(`Fee Juice Address: ${l1ContractAddresses.feeJuiceAddress.toString()}`); log(`Fee Juice Portal Address: ${l1ContractAddresses.feeJuicePortalAddress.toString()}`); } diff --git a/yarn-project/cli/src/cmds/pxe/get_node_info.ts b/yarn-project/cli/src/cmds/pxe/get_node_info.ts index 8128de79104..a3347f792d5 100644 --- a/yarn-project/cli/src/cmds/pxe/get_node_info.ts +++ b/yarn-project/cli/src/cmds/pxe/get_node_info.ts @@ -13,7 +13,6 @@ export async function getNodeInfo(rpcUrl: string, debugLogger: DebugLogger, log: log(` Registry Address: ${info.l1ContractAddresses.registryAddress.toString()}`); log(` L1 -> L2 Inbox Address: ${info.l1ContractAddresses.inboxAddress.toString()}`); log(` L2 -> L1 Outbox Address: ${info.l1ContractAddresses.outboxAddress.toString()}`); - log(` Availability Oracle Address: ${info.l1ContractAddresses.availabilityOracleAddress.toString()}`); log(` Fee Juice Address: ${info.l1ContractAddresses.feeJuiceAddress.toString()}`); log(` Fee Juice Portal Address: ${info.l1ContractAddresses.feeJuicePortalAddress.toString()}`); diff --git a/yarn-project/cli/src/utils/aztec.ts b/yarn-project/cli/src/utils/aztec.ts index 06f234a1207..921fd4ac56d 100644 --- a/yarn-project/cli/src/utils/aztec.ts +++ b/yarn-project/cli/src/utils/aztec.ts @@ -69,8 +69,7 @@ export async function deployAztecContracts( RegistryBytecode, RollupAbi, RollupBytecode, - AvailabilityOracleAbi, - AvailabilityOracleBytecode, + FeeJuicePortalAbi, FeeJuicePortalBytecode, PortalERC20Abi, @@ -96,10 +95,6 @@ export async function deployAztecContracts( contractAbi: OutboxAbi, contractBytecode: OutboxBytecode, }, - availabilityOracle: { - contractAbi: AvailabilityOracleAbi, - contractBytecode: AvailabilityOracleBytecode, - }, rollup: { contractAbi: RollupAbi, contractBytecode: RollupBytecode, diff --git a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts index bc59c817ebc..b978ecda0a5 100644 --- a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts @@ -2,7 +2,6 @@ import { type ArchiveSource } from '@aztec/archiver'; import { getConfigEnvVars } from '@aztec/aztec-node'; import { AztecAddress, - Body, EthCheatCodes, Fr, GlobalVariables, @@ -38,7 +37,7 @@ import { fr, makeScopedL2ToL1Message } from '@aztec/circuits.js/testing'; import { type L1ContractAddresses, createEthereumChain } from '@aztec/ethereum'; import { makeTuple, range } from '@aztec/foundation/array'; import { openTmpStore } from '@aztec/kv-store/utils'; -import { AvailabilityOracleAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types'; import { TxProver } from '@aztec/prover-client'; @@ -57,7 +56,6 @@ import { type HttpTransport, type PublicClient, type WalletClient, - decodeEventLog, encodeFunctionData, getAbiItem, getAddress, @@ -323,29 +321,6 @@ describe('L1Publisher integration', () => { return blockTicket; }; - it('Block body is correctly published to AvailabilityOracle', async () => { - const body = Body.random(); - // `sendPublishTx` function is private so I am hacking around TS here. I think it's ok for test purposes. - const txHash = await (publisher as any).sendPublishTx(body.toBuffer()); - const txReceipt = await publicClient.waitForTransactionReceipt({ - hash: txHash, - }); - - // Exactly 1 event should be emitted in the transaction - expect(txReceipt.logs.length).toBe(1); - - // We decode the event log before checking it - const txLog = txReceipt.logs[0]; - const topics = decodeEventLog({ - abi: AvailabilityOracleAbi, - data: txLog.data, - topics: txLog.topics, - }); - // Sol gives bytes32 txsHash, so we pad the ts bytes31 version - // We check that the txsHash in the TxsPublished event is as expected - expect(topics.args.txsEffectsHash).toEqual(`0x${body.getTxsEffectsHash().toString('hex').padStart(64, '0')}`); - }); - it(`Build ${numberOfConsecutiveBlocks} blocks of 4 bloated txs building on each other`, async () => { const archiveInRollup_ = await rollup.read.archive(); expect(hexStringToBuffer(archiveInRollup_.toString())).toEqual(new Fr(GENESIS_ARCHIVE_ROOT).toBuffer()); @@ -526,29 +501,17 @@ describe('L1Publisher integration', () => { hash: logs[i].transactionHash!, }); - const expectedData = - i == 0 - ? encodeFunctionData({ - abi: RollupAbi, - functionName: 'propose', - args: [ - `0x${block.header.toBuffer().toString('hex')}`, - `0x${block.archive.root.toBuffer().toString('hex')}`, - `0x${block.header.hash().toBuffer().toString('hex')}`, - [], - `0x${block.body.toBuffer().toString('hex')}`, - ], - }) - : encodeFunctionData({ - abi: RollupAbi, - functionName: 'propose', - args: [ - `0x${block.header.toBuffer().toString('hex')}`, - `0x${block.archive.root.toBuffer().toString('hex')}`, - `0x${block.header.hash().toBuffer().toString('hex')}`, - [], - ], - }); + const expectedData = encodeFunctionData({ + abi: RollupAbi, + functionName: 'propose', + args: [ + `0x${block.header.toBuffer().toString('hex')}`, + `0x${block.archive.root.toBuffer().toString('hex')}`, + `0x${block.header.hash().toBuffer().toString('hex')}`, + [], + `0x${block.body.toBuffer().toString('hex')}`, + ], + }); expect(ethTx.input).toEqual(expectedData); await progressTimeBySlot(); diff --git a/yarn-project/end-to-end/src/fixtures/setup_l1_contracts.ts b/yarn-project/end-to-end/src/fixtures/setup_l1_contracts.ts index 4cc48f528fa..62099e72a14 100644 --- a/yarn-project/end-to-end/src/fixtures/setup_l1_contracts.ts +++ b/yarn-project/end-to-end/src/fixtures/setup_l1_contracts.ts @@ -1,7 +1,5 @@ import { type DebugLogger, type L1ContractArtifactsForDeployment, deployL1Contracts } from '@aztec/aztec.js'; import { - AvailabilityOracleAbi, - AvailabilityOracleBytecode, FeeJuicePortalAbi, FeeJuicePortalBytecode, InboxAbi, @@ -41,10 +39,6 @@ export const setupL1Contracts = async ( contractAbi: OutboxAbi, contractBytecode: OutboxBytecode, }, - availabilityOracle: { - contractAbi: AvailabilityOracleAbi, - contractBytecode: AvailabilityOracleBytecode, - }, rollup: { contractAbi: RollupAbi, contractBytecode: RollupBytecode, diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 94c65a0c088..1045d838954 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -44,8 +44,6 @@ import { NULL_KEY, isAnvilTestChain } from '@aztec/ethereum'; import { bufferAsFields } from '@aztec/foundation/abi'; import { makeBackoff, retry, retryUntil } from '@aztec/foundation/retry'; import { - AvailabilityOracleAbi, - AvailabilityOracleBytecode, FeeJuicePortalAbi, FeeJuicePortalBytecode, InboxAbi, @@ -133,10 +131,6 @@ export const setupL1Contracts = async ( contractAbi: OutboxAbi, contractBytecode: OutboxBytecode, }, - availabilityOracle: { - contractAbi: AvailabilityOracleAbi, - contractBytecode: AvailabilityOracleBytecode, - }, rollup: { contractAbi: RollupAbi, contractBytecode: RollupBytecode, diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index eaf4f83f13b..290d0728a68 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -73,10 +73,6 @@ export interface L1ContractArtifactsForDeployment { * Outbox contract artifacts */ outbox: ContractArtifacts; - /** - * Availability Oracle contract artifacts - */ - availabilityOracle: ContractArtifacts; /** * Registry contract artifacts */ @@ -186,9 +182,6 @@ export const deployL1Contracts = async ( const registryAddress = await deployer.deploy(contractsToDeploy.registry, [account.address.toString()]); logger.info(`Deployed Registry at ${registryAddress}`); - const availabilityOracleAddress = await deployer.deploy(contractsToDeploy.availabilityOracle); - logger.info(`Deployed AvailabilityOracle at ${availabilityOracleAddress}`); - const feeJuiceAddress = await deployer.deploy(contractsToDeploy.feeJuice); logger.info(`Deployed Fee Juice at ${feeJuiceAddress}`); @@ -199,7 +192,6 @@ export const deployL1Contracts = async ( const rollupAddress = await deployer.deploy(contractsToDeploy.rollup, [ getAddress(registryAddress.toString()), - getAddress(availabilityOracleAddress.toString()), getAddress(feeJuicePortalAddress.toString()), args.vkTreeRoot.toString(), account.address.toString(), @@ -318,7 +310,6 @@ export const deployL1Contracts = async ( logger.verbose(`All transactions for L1 deployment have been mined`); const l1Contracts: L1ContractAddresses = { - availabilityOracleAddress, rollupAddress, registryAddress, inboxAddress, diff --git a/yarn-project/ethereum/src/l1_contract_addresses.ts b/yarn-project/ethereum/src/l1_contract_addresses.ts index 6ec61e8b24c..0230ad3d491 100644 --- a/yarn-project/ethereum/src/l1_contract_addresses.ts +++ b/yarn-project/ethereum/src/l1_contract_addresses.ts @@ -8,7 +8,6 @@ import type { DebugLogger } from '@aztec/foundation/log'; * For reference: https://github.com/AztecProtocol/aztec-packages/pull/5553 */ export const l1ContractsNames = [ - 'availabilityOracleAddress', 'rollupAddress', 'registryAddress', 'inboxAddress', @@ -27,11 +26,6 @@ export type L1ContractAddresses = { const parseEnv = (val: string) => EthAddress.fromString(val); export const l1ContractAddressesMapping: ConfigMappingsType = { - availabilityOracleAddress: { - env: 'AVAILABILITY_ORACLE_CONTRACT_ADDRESS', - description: 'The deployed L1 availability oracle contract address.', - parseEnv, - }, rollupAddress: { env: 'ROLLUP_CONTRACT_ADDRESS', description: 'The deployed L1 rollup contract address.', diff --git a/yarn-project/foundation/src/config/env_var.ts b/yarn-project/foundation/src/config/env_var.ts index ebd360bcf5a..7b01983b743 100644 --- a/yarn-project/foundation/src/config/env_var.ts +++ b/yarn-project/foundation/src/config/env_var.ts @@ -11,7 +11,6 @@ export type EnvVar = | 'REGISTRY_CONTRACT_ADDRESS' | 'INBOX_CONTRACT_ADDRESS' | 'OUTBOX_CONTRACT_ADDRESS' - | 'AVAILABILITY_ORACLE_CONTRACT_ADDRESS' | 'FEE_JUICE_CONTRACT_ADDRESS' | 'FEE_JUICE_PORTAL_CONTRACT_ADDRESS' | 'ARCHIVER_URL' diff --git a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh index 520619a558b..1d82db63c06 100755 --- a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh +++ b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh @@ -10,7 +10,6 @@ target_dir=./generated # - a .{CONTRACT_NAME}Abi.ts containing the contract ABI. CONTRACTS=( - "l1-contracts:AvailabilityOracle" "l1-contracts:Registry" "l1-contracts:Inbox" "l1-contracts:Outbox" diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts index b8931137f01..b634eb62777 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts @@ -26,7 +26,6 @@ function createPXEService(): Promise { node.getVersion.mockResolvedValue(1); node.getChainId.mockResolvedValue(1); const mockedContracts: L1ContractAddresses = { - availabilityOracleAddress: EthAddress.random(), rollupAddress: EthAddress.random(), registryAddress: EthAddress.random(), inboxAddress: EthAddress.random(), diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts index 6722ded9101..da2a8aebe14 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts @@ -9,27 +9,6 @@ import { type GetTransactionReceiptReturnType, type PrivateKeyAccount } from 'vi import { type PublisherConfig, type TxSenderConfig } from './config.js'; import { L1Publisher } from './l1-publisher.js'; -interface MockAvailabilityOracleWrite { - publish: (args: readonly [`0x${string}`], options: { account: PrivateKeyAccount }) => Promise<`0x${string}`>; -} - -interface MockAvailabilityOracleEstimate { - publish: (args: readonly [`0x${string}`], options: { account: PrivateKeyAccount }) => Promise; -} - -interface MockAvailabilityOracleRead { - isAvailable: (args: readonly [`0x${string}`]) => Promise; -} - -class MockAvailabilityOracle { - constructor( - public write: MockAvailabilityOracleWrite, - public simulate: MockAvailabilityOracleWrite, - public estimateGas: MockAvailabilityOracleEstimate, - public read: MockAvailabilityOracleRead, - ) {} -} - interface MockPublicClient { getTransactionReceipt: ({ hash }: { hash: '0x${string}' }) => Promise; getBlock(): Promise<{ timestamp: bigint }>; @@ -71,12 +50,6 @@ describe('L1Publisher', () => { let rollupContractSimulate: MockProxy; let rollupContract: MockRollupContract; - let availabilityOracleRead: MockProxy; - let availabilityOracleWrite: MockProxy; - let availabilityOracleSimulate: MockProxy; - let availabilityOracleEstimate: MockProxy; - let availabilityOracle: MockAvailabilityOracle; - let publicClient: MockProxy; let processTxHash: `0x${string}`; @@ -123,17 +96,6 @@ describe('L1Publisher', () => { rollupContractRead = mock(); rollupContract = new MockRollupContract(rollupContractWrite, rollupContractSimulate, rollupContractRead); - availabilityOracleWrite = mock(); - availabilityOracleRead = mock(); - availabilityOracleSimulate = mock(); - availabilityOracleEstimate = mock(); - availabilityOracle = new MockAvailabilityOracle( - availabilityOracleWrite, - availabilityOracleSimulate, - availabilityOracleEstimate, - availabilityOracleRead, - ); - publicClient = mock(); const config = { @@ -141,7 +103,6 @@ describe('L1Publisher', () => { l1ChainId: 1, publisherPrivateKey: `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80`, l1Contracts: { - availabilityOracleAddress: EthAddress.ZERO.toString(), rollupAddress: EthAddress.ZERO.toString(), }, l1PublishRetryIntervalMS: 1, @@ -149,14 +110,12 @@ describe('L1Publisher', () => { publisher = new L1Publisher(config, new NoopTelemetryClient()); - (publisher as any)['availabilityOracleContract'] = availabilityOracle; (publisher as any)['rollupContract'] = rollupContract; (publisher as any)['publicClient'] = publicClient; account = (publisher as any)['account']; rollupContractRead.getCurrentSlot.mockResolvedValue(l2Block.header.globalVariables.slotNumber.toBigInt()); - availabilityOracleEstimate.publish.mockResolvedValueOnce(GAS_GUESS); publicClient.getBlock.mockResolvedValue({ timestamp: 12n }); }); @@ -186,7 +145,6 @@ describe('L1Publisher', () => { }); it('publishes l2 block to l1 (already published body)', async () => { - availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); rollupContractWrite.propose.mockResolvedValueOnce(processTxHash); rollupContractSimulate.propose.mockResolvedValueOnce(processTxHash); @@ -206,7 +164,6 @@ describe('L1Publisher', () => { }); it('does not retry if sending a propose tx fails', async () => { - availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); rollupContractWrite.propose .mockRejectedValueOnce(new Error()) @@ -245,7 +202,6 @@ describe('L1Publisher', () => { }); it('retries if fetching the receipt fails (propose)', async () => { - availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); rollupContractSimulate.propose.mockResolvedValueOnce(processTxHash); rollupContractWrite.propose.mockResolvedValueOnce(processTxHash); @@ -280,7 +236,6 @@ describe('L1Publisher', () => { }); it('returns false if propose tx reverts', async () => { - availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); publicClient.getTransactionReceipt.mockResolvedValueOnce({ ...processTxReceipt, status: 'reverted' }); @@ -303,7 +258,6 @@ describe('L1Publisher', () => { }); it('returns false if sending propose tx is interrupted', async () => { - availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); rollupContractWrite.propose.mockImplementationOnce(() => sleep(10, processTxHash) as Promise<`0x${string}`>); diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index 4f30bef3215..e473f95329b 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -7,7 +7,7 @@ import { createDebugLogger } from '@aztec/foundation/log'; import { serializeToBuffer } from '@aztec/foundation/serialize'; import { InterruptibleSleep } from '@aztec/foundation/sleep'; import { Timer } from '@aztec/foundation/timer'; -import { AvailabilityOracleAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { RollupAbi } from '@aztec/l1-artifacts'; import { type TelemetryClient } from '@aztec/telemetry-client'; import pick from 'lodash.pick'; @@ -21,6 +21,7 @@ import { type WalletClient, createPublicClient, createWalletClient, + encodeFunctionData, getAddress, getContract, hexToBytes, @@ -103,10 +104,6 @@ export class L1Publisher { private metrics: L1PublisherMetrics; private log = createDebugLogger('aztec:sequencer:publisher'); - private availabilityOracleContract: GetContractReturnType< - typeof AvailabilityOracleAbi, - WalletClient - >; private rollupContract: GetContractReturnType< typeof RollupAbi, WalletClient @@ -135,11 +132,6 @@ export class L1Publisher { transport: http(chain.rpcUrl), }); - this.availabilityOracleContract = getContract({ - address: getAddress(l1Contracts.availabilityOracleAddress.toString()), - abi: AvailabilityOracleAbi, - client: walletClient, - }); this.rollupContract = getContract({ address: getAddress(l1Contracts.rollupAddress.toString()), abi: RollupAbi, @@ -192,6 +184,7 @@ export class L1Publisher { formattedSignatures, `0x${attestationData.digest.toString('hex')}`, ts, + `0x${header.contentCommitment.txsEffectsHash.toString('hex')}`, flags, ] as const; @@ -214,11 +207,6 @@ export class L1Publisher { return committee.map(EthAddress.fromString); } - checkIfTxsAreAvailable(block: L2Block): Promise { - const args = [`0x${block.body.getTxsEffectsHash().toString('hex').padStart(64, '0')}`] as const; - return this.availabilityOracleContract.read.isAvailable(args); - } - async getTransactionStats(txHash: string): Promise { const tx = await this.publicClient.getTransaction({ hash: txHash as Hex }); if (!tx) { @@ -254,11 +242,8 @@ export class L1Publisher { // Publish body and propose block (if not already published) if (!this.interrupted) { - let txHash; const timer = new Timer(); - const isAvailable = await this.checkIfTxsAreAvailable(block); - // @note This will make sure that we are passing the checks for our header ASSUMING that the data is also made available // This means that we can avoid the simulation issues in later checks. // By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which @@ -268,12 +253,7 @@ export class L1Publisher { signatures: attestations ?? [], }); - if (isAvailable) { - this.log.verbose(`Transaction effects of block ${block.number} already published.`, ctx); - txHash = await this.sendProposeWithoutBodyTx(processTxArgs); - } else { - txHash = await this.sendProposeTx(processTxArgs); - } + const txHash = await this.sendProposeTx(processTxArgs); if (!txHash) { this.log.info(`Failed to publish block ${block.number} to L1`, ctx); @@ -406,57 +386,19 @@ export class L1Publisher { } } - // This is used in `integration_l1_publisher.test.ts` currently. Could be removed though. - private async sendPublishTx(encodedBody: Buffer): Promise { - if (!this.interrupted) { - try { - this.log.info(`TxEffects size=${encodedBody.length} bytes`); - const args = [`0x${encodedBody.toString('hex')}`] as const; - - await this.availabilityOracleContract.simulate.publish(args, { - account: this.account, - }); - - return await this.availabilityOracleContract.write.publish(args, { - account: this.account, - }); - } catch (err) { - this.log.error(`TxEffects publish failed`, err); - return undefined; - } - } - } - - private async sendProposeWithoutBodyTx(encodedData: L1ProcessArgs): Promise { + private async sendProposeTx(encodedData: L1ProcessArgs): Promise { if (!this.interrupted) { try { - const attestations = encodedData.attestations - ? encodedData.attestations.map(attest => attest.toViemSignature()) - : []; - const args = [ - `0x${encodedData.header.toString('hex')}`, - `0x${encodedData.archive.toString('hex')}`, - `0x${encodedData.blockHash.toString('hex')}`, - attestations, - ] as const; - - return await this.rollupContract.write.propose(args, { - account: this.account, - gas: L1Publisher.PROPOSE_GAS_GUESS, + // We have to jump a few hoops because viem is not happy around estimating gas for view functions + const computeTxsEffectsHashGas = await this.publicClient.estimateGas({ + to: this.rollupContract.address, + data: encodeFunctionData({ + abi: this.rollupContract.abi, + functionName: 'computeTxsEffectsHash', + args: [`0x${encodedData.body.toString('hex')}`], + }), }); - } catch (err) { - this.log.error(`Rollup publish failed`, err); - return undefined; - } - } - } - private async sendProposeTx(encodedData: L1ProcessArgs): Promise { - if (!this.interrupted) { - try { - const publishGas = await this.availabilityOracleContract.estimateGas.publish([ - `0x${encodedData.body.toString('hex')}`, - ]); const min = (a: bigint, b: bigint) => (a > b ? b : a); // @note We perform this guesstimate instead of the usual `gasEstimate` since @@ -464,7 +406,7 @@ export class L1Publisher { // we will fail estimation in the case where we are simulating for the // first ethereum block within our slot (as current time is not in the // slot yet). - const gasGuesstimate = min(publishGas * 2n + L1Publisher.PROPOSE_GAS_GUESS, 15_000_000n); + const gasGuesstimate = min(computeTxsEffectsHashGas + L1Publisher.PROPOSE_GAS_GUESS, 15_000_000n); const attestations = encodedData.attestations ? encodedData.attestations.map(attest => attest.toViemSignature()) diff --git a/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts index 3b435b0386a..571c758d483 100644 --- a/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts +++ b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts @@ -2,7 +2,6 @@ import { PedersenCommitment } from '../opcodes/commitment.js'; import { DAGasLeft, L2GasLeft } from '../opcodes/context_getters.js'; import { EcAdd } from '../opcodes/ec_add.js'; import { Keccak, KeccakF1600, Pedersen, Poseidon2, Sha256 } from '../opcodes/hashing.js'; -import { Instruction } from '../opcodes/index.js'; import { Add, Address, @@ -24,6 +23,7 @@ import { FieldDiv, FunctionSelector, GetContractInstance, + Instruction, InternalCall, InternalReturn, Jump,