diff --git a/docs/docs/developers/debugging/sandbox-errors.md b/docs/docs/developers/debugging/sandbox-errors.md index 911654026b60..783df3ab1fda 100644 --- a/docs/docs/developers/debugging/sandbox-errors.md +++ b/docs/docs/developers/debugging/sandbox-errors.md @@ -177,7 +177,7 @@ Users may create a proof against a historical state in Aztec. The rollup circuit ## Archiver Errors -- "No L1 to L2 message found for message hash ${messageHash.toString()}" - happens when the L1 to L2 message doesn't exist or is "pending", when the user has sent a message on L1 via the Inbox contract but it has yet to be included in an L2 block by the sequencer - user has to wait for enough blocks to progress and for the archiver to sync the respective L2 block. You can get the sequencer to pick it up by doing 2 arbitrary transaction on L2 (eg. send DAI to yourself 2 times). This would give the sequencer a transaction to process and as a side effect it would consume 2 subtrees of new messages from the Inbox contract. 2 subtrees needs to be consumed and not just 1 because there is a 1 block lag to prevent the subtree from changing when the sequencer is proving. +- "No non-nullified L1 to L2 message found for message hash ${messageHash.toString()}" - happens when the L1 to L2 message doesn't exist or is "pending", when the user has sent a message on L1 via the Inbox contract but it has yet to be included in an L2 block by the sequencer - user has to wait for enough blocks to progress and for the archiver to sync the respective L2 block. You can get the sequencer to pick it up by doing 2 arbitrary transaction on L2 (eg. send DAI to yourself 2 times). This would give the sequencer a transaction to process and as a side effect it would consume 2 subtrees of new messages from the Inbox contract. 2 subtrees needs to be consumed and not just 1 because there is a 1 block lag to prevent the subtree from changing when the sequencer is proving. - "Block number mismatch: expected ${l2BlockNum} but got ${block.number}" - The archiver keeps track of the next expected L2 block number. It throws this error if it got a different one when trying to sync with the rollup contract's events on L1. diff --git a/yarn-project/circuits.js/src/hash/hash.ts b/yarn-project/circuits.js/src/hash/hash.ts index 3ead475e6f11..4812502251a2 100644 --- a/yarn-project/circuits.js/src/hash/hash.ts +++ b/yarn-project/circuits.js/src/hash/hash.ts @@ -173,3 +173,7 @@ export function computeNullifierHash(input: SideEffectLinkedToNoteHash) { export function computeMessageSecretHash(secretMessage: Fr) { return pedersenHash([secretMessage.toBuffer()], GeneratorIndex.L1_TO_L2_MESSAGE_SECRET); } + +export function computeL1ToL2MessageNullifier(messageHash: Fr, secret: Fr, messageIndex: bigint) { + return pedersenHash([messageHash, secret, messageIndex], GeneratorIndex.NULLIFIER); +} diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts index c87579abff7c..36ec4f0eb3df 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts @@ -178,7 +178,7 @@ describe('e2e_cross_chain_messaging', () => { .withWallet(user2Wallet) .methods.claim_private(secretHashForL2MessageConsumption, bridgeAmount, secretForL2MessageConsumption) .simulate(), - ).rejects.toThrow(`No L1 to L2 message found for message hash ${wrongMessage.hash().toString()}`); + ).rejects.toThrow(`No non-nullified L1 to L2 message found for message hash ${wrongMessage.hash().toString()}`); // send the right one - const consumptionReceipt = await l2Bridge @@ -258,6 +258,6 @@ describe('e2e_cross_chain_messaging', () => { .withWallet(user2Wallet) .methods.claim_public(ownerAddress, bridgeAmount, secretForL2MessageConsumption) .simulate(), - ).rejects.toThrow(`Message ${wrongMessage.hash().toString()} not found`); + ).rejects.toThrow(`No non-nullified L1 to L2 message found for message hash ${wrongMessage.hash().toString()}`); }, 120_000); }); diff --git a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts index 2dbfa75bc6dd..722e87727e11 100644 --- a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts @@ -170,7 +170,7 @@ describe('e2e_public_cross_chain_messaging', () => { // user2 tries to consume this message and minting to itself -> should fail since the message is intended to be consumed only by owner. await expect( l2Bridge.withWallet(user2Wallet).methods.claim_public(user2Wallet.getAddress(), bridgeAmount, secret).simulate(), - ).rejects.toThrow(`Message ${wrongMessage.hash().toString()} not found`); + ).rejects.toThrow(`No non-nullified L1 to L2 message found for message hash ${wrongMessage.hash().toString()}`); // user2 consumes owner's L1-> L2 message on bridge contract and mints public tokens on L2 logger("user2 consumes owner's message on L2 Publicly"); @@ -223,7 +223,7 @@ describe('e2e_public_cross_chain_messaging', () => { await expect( l2Bridge.withWallet(user2Wallet).methods.claim_private(secretHash, bridgeAmount, secret).simulate(), - ).rejects.toThrow(`No L1 to L2 message found for message hash ${wrongMessage.hash().toString()}`); + ).rejects.toThrow(`No non-nullified L1 to L2 message found for message hash ${wrongMessage.hash().toString()}`); }, 60_000); // Note: We register one portal address when deploying contract but that address is no-longer the only address diff --git a/yarn-project/foundation/src/crypto/pedersen/pedersen.wasm.ts b/yarn-project/foundation/src/crypto/pedersen/pedersen.wasm.ts index dbe457a2971c..c7a90507001c 100644 --- a/yarn-project/foundation/src/crypto/pedersen/pedersen.wasm.ts +++ b/yarn-project/foundation/src/crypto/pedersen/pedersen.wasm.ts @@ -1,6 +1,7 @@ import { BarretenbergSync, Fr as FrBarretenberg } from '@aztec/bb.js'; import { Fr } from '../../fields/fields.js'; +import { Bufferable, serializeToBufferArray } from '../../serialize/serialize.js'; /** * Create a pedersen commitment (point) from an array of input fields. @@ -21,16 +22,17 @@ export function pedersenCommit(input: Buffer[]) { * Create a pedersen hash (field) from an array of input fields. * Left pads any inputs less than 32 bytes. */ -export function pedersenHash(input: Buffer[], index = 0): Fr { - if (!input.every(i => i.length <= 32)) { +export function pedersenHash(input: Bufferable[], index = 0): Fr { + let bufferredInput = serializeToBufferArray(input); + if (!bufferredInput.every(i => i.length <= 32)) { throw new Error('All Pedersen Hash input buffers must be <= 32 bytes.'); } - input = input.map(i => (i.length < 32 ? Buffer.concat([Buffer.alloc(32 - i.length, 0), i]) : i)); + bufferredInput = bufferredInput.map(i => (i.length < 32 ? Buffer.concat([Buffer.alloc(32 - i.length, 0), i]) : i)); return Fr.fromBuffer( Buffer.from( BarretenbergSync.getSingleton() .pedersenHash( - input.map(i => new FrBarretenberg(i)), + bufferredInput.map(i => new FrBarretenberg(i)), index, ) .toBuffer(), diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index c814f347d555..24c732b88734 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -14,16 +14,15 @@ import { EthAddress, Fr, FunctionSelector, - GeneratorIndex, Header, - L1_TO_L2_MSG_TREE_HEIGHT, + L1_TO_L2_MSG_TREE_HEIGHT } from '@aztec/circuits.js'; import { FunctionArtifactWithDebugMetadata, getFunctionArtifactWithDebugMetadata } from '@aztec/foundation/abi'; -import { pedersenHash } from '@aztec/foundation/crypto'; import { createDebugLogger } from '@aztec/foundation/log'; import { DBOracle, KeyPair, MessageLoadOracleInputs } from '@aztec/simulator'; import { ContractInstance } from '@aztec/types/contracts'; +import { computeL1ToL2MessageNullifier } from '@aztec/circuits.js/hash'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; import { PxeDatabase } from '../database/index.js'; @@ -137,7 +136,7 @@ export class SimulatorOracle implements DBOracle { let messageIndex = 0n; let siblingPath: SiblingPath; - // We iterate over messages until we find one whose nullifier is not in the nullifier tree --> ewe need to check + // We iterate over messages until we find one whose nullifier is not in the nullifier tree --> we need to check // for nullifiers because messages can have duplicates. do { const response = await this.aztecNode.getL1ToL2MessageMembershipWitness('latest', messageHash, messageIndex); @@ -146,11 +145,7 @@ export class SimulatorOracle implements DBOracle { } [messageIndex, siblingPath] = response; - // TODO: create separate helper function - const messageNullifier = pedersenHash( - [messageHash, secret, new Fr(messageIndex)].map(v => v.toBuffer()), - GeneratorIndex.NULLIFIER, - ); + const messageNullifier = computeL1ToL2MessageNullifier(messageHash, secret, messageIndex); nullifierIndex = await this.getNullifierIndex(messageNullifier); } while (nullifierIndex !== undefined); diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 010bf0ccd023..5c7f0f4dcda7 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -2,7 +2,6 @@ import { L1ToL2MessageSource, MerkleTreeId, NullifierMembershipWitness, - SiblingPath, Tx, UnencryptedL2Log, } from '@aztec/circuit-types'; @@ -13,14 +12,12 @@ import { EthAddress, Fr, FunctionSelector, - GeneratorIndex, L1_TO_L2_MSG_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT, NullifierLeafPreimage, PublicDataTreeLeafPreimage, } from '@aztec/circuits.js'; -import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; -import { pedersenHash } from '@aztec/foundation/crypto'; +import { computeL1ToL2MessageNullifier, computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { createDebugLogger } from '@aztec/foundation/log'; import { getCanonicalClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '@aztec/simulator'; @@ -233,7 +230,7 @@ export class WorldStateDB implements CommitmentsDB { let nullifierIndex: bigint | undefined; let messageIndex: bigint | undefined; - // We iterate over messages until we find one whose nullifier is not in the nullifier tree --> ewe need to check + // We iterate over messages until we find one whose nullifier is not in the nullifier tree --> we need to check // for nullifiers because messages can have duplicates. do { messageIndex = (await this.db.findLeafIndex(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, messageHash.toBuffer()))!; @@ -241,12 +238,7 @@ export class WorldStateDB implements CommitmentsDB { throw new Error(`No non-nullified L1 to L2 message found for message hash ${messageHash.toString()}`); } - // TODO: create separate helper function - const messageNullifier = pedersenHash( - [messageHash, secret, new Fr(messageIndex)].map(v => v.toBuffer()), - GeneratorIndex.NULLIFIER, - ); - + const messageNullifier = computeL1ToL2MessageNullifier(messageHash, secret, messageIndex); nullifierIndex = await this.getNullifierIndex(messageNullifier); } while (nullifierIndex !== undefined);