Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ee8dc36
fix: reroll noir hash loops
Maddiaa0 Jun 26, 2023
80657bd
fix: use libraries refactor
Maddiaa0 Jul 4, 2023
ec876ab
feat: add automatic formatting to build command
Maddiaa0 Jul 4, 2023
3e1a7b3
fix: merge noir refactors
Maddiaa0 Jul 5, 2023
6993900
fix: update test contract
Maddiaa0 Jul 5, 2023
0d492f1
fix: update zk_token
Maddiaa0 Jul 5, 2023
0719269
fix: update public private
Maddiaa0 Jul 5, 2023
8a936ec
fix: update non native token
Maddiaa0 Jul 5, 2023
1ac7df5
refactor: move aztec-noir lib into libs folder
Maddiaa0 Jul 5, 2023
d4882cd
fix: update compile all
Maddiaa0 Jul 5, 2023
27976ad
feat: unshield tokens
Maddiaa0 Jun 27, 2023
3480ee0
fix: formatting
Maddiaa0 Jun 27, 2023
43f4441
fix: revert plookup change
Maddiaa0 Jun 27, 2023
6e1dcc0
fix: increase timeout
Maddiaa0 Jun 27, 2023
2b5dc7e
merge
Maddiaa0 Jun 27, 2023
cbdd11c
fix: merge conflict
Maddiaa0 Jul 3, 2023
023613c
fix: review comments
Maddiaa0 Jul 3, 2023
a76942a
fix: fmt
Maddiaa0 Jul 3, 2023
20196b5
fix: test contract recompile
Maddiaa0 Jul 3, 2023
da7fa27
fix: hash code cleanup
Maddiaa0 Jul 3, 2023
dabc818
fix: update public to private e2e to check key invariants
Maddiaa0 Jul 4, 2023
8ee2833
chore(fmt): e2e
Maddiaa0 Jul 4, 2023
e2f7e17
fmt
Maddiaa0 Jul 4, 2023
daba48b
fix: post rebase clean
Maddiaa0 Jul 5, 2023
629f9ea
fix: fmt
Maddiaa0 Jul 5, 2023
7c7af5d
fmt
Maddiaa0 Jul 5, 2023
9770592
fix
Maddiaa0 Jul 5, 2023
d49336a
Merge branch 'master' into md/878-unshield
Maddiaa0 Jul 5, 2023
d680ef3
fix: collapse l1 to l2 message loops
Maddiaa0 Jul 5, 2023
47dc272
fix: more unrolling
Maddiaa0 Jul 5, 2023
1c56fb1
fix: note on sig
Maddiaa0 Jul 5, 2023
772e3e0
Merge branch 'md/noir-libs' into md/878-unshield
Maddiaa0 Jul 5, 2023
c6bdb67
Merge branch 'master' into md/878-unshield
Maddiaa0 Jul 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
ChildAbi,
NonNativeTokenContractAbi,
ParentAbi,
PublicToPrivateContractAbi,
TestContractAbi,
ZkTokenContractAbi,
} from '@aztec/noir-contracts/examples';
Expand Down Expand Up @@ -444,7 +443,7 @@ describe('Private Execution test suite', () => {

const contractAddress = AztecAddress.random();
const amount = 100n;
const abi = PublicToPrivateContractAbi.functions.find(f => f.name === 'mintFromPublicMessage')!;
const abi = NonNativeTokenContractAbi.functions.find(f => f.name === 'redeemShield')!;

const wasm = await CircuitsWasm.get();
const secret = new Fr(1n);
Expand Down
18 changes: 8 additions & 10 deletions yarn-project/acir-simulator/src/public/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import {
ChildAbi,
NonNativeTokenContractAbi,
ParentAbi,
PublicToPrivateContractAbi,
PublicTokenContractAbi,
TestContractAbi,
} from '@aztec/noir-contracts/examples';
import { MockProxy, mock } from 'jest-mock-extended';
import { default as memdown, type MemDown } from 'memdown';
Expand Down Expand Up @@ -260,8 +260,8 @@ describe('ACIR public execution simulator', () => {
});

it('Should be able to create a commitment from the public context', async () => {
const publicToPrivateAbi = PublicToPrivateContractAbi.functions.find(f => f.name === 'mintFromPublicToPrivate')!;
const args = encodeArguments(publicToPrivateAbi, params);
const shieldAbi = NonNativeTokenContractAbi.functions.find(f => f.name === 'shield')!;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As noted later, this should handle the burning to not inflate.

const args = encodeArguments(shieldAbi, params);

const callContext = CallContext.from({
msgSender: AztecAddress.random(),
Expand All @@ -272,7 +272,9 @@ describe('ACIR public execution simulator', () => {
isStaticCall: false,
});

publicContracts.getBytecode.mockResolvedValue(Buffer.from(publicToPrivateAbi.bytecode, 'hex'));
publicContracts.getBytecode.mockResolvedValue(Buffer.from(shieldAbi.bytecode, 'hex'));
// mock initial balance to be greater than the amount being sent
publicState.storageRead.mockResolvedValue(amount);

const execution: PublicExecution = { contractAddress, functionData, args, callContext };
const result = await executor.execute(execution, GlobalVariables.empty());
Expand All @@ -288,9 +290,7 @@ describe('ACIR public execution simulator', () => {
});

it('Should be able to create a L2 to L1 message from the public context', async () => {
const createL2ToL1MessagePublicAbi = PublicToPrivateContractAbi.functions.find(
f => f.name === 'createL2ToL1MessagePublic',
)!;
const createL2ToL1MessagePublicAbi = TestContractAbi.functions.find(f => f.name === 'createL2ToL1MessagePublic')!;
const args = encodeArguments(createL2ToL1MessagePublicAbi, params);

const callContext = CallContext.from({
Expand Down Expand Up @@ -375,9 +375,7 @@ describe('ACIR public execution simulator', () => {
});

it('Should be able to create a nullifier from the public context', async () => {
const createNullifierPublicAbi = PublicToPrivateContractAbi.functions.find(
f => f.name === 'createNullifierPublic',
)!;
const createNullifierPublicAbi = TestContractAbi.functions.find(f => f.name === 'createNullifierPublic')!;

const args = encodeArguments(createNullifierPublicAbi, params);

Expand Down
2 changes: 2 additions & 0 deletions yarn-project/circuits.js/src/structs/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,7 @@ export const ROLLUP_VK_TREE_HEIGHT = 8;

export const FUNCTION_SELECTOR_NUM_BYTES = 4;

export const MAPPING_SLOT_PEDERSEN_SEPARATOR = 4;

// sha256 hash is stored in two fields to accommodate all 256-bits of the hash
export const NUM_FIELDS_PER_SHA256 = 2;
35 changes: 33 additions & 2 deletions yarn-project/end-to-end/src/cross_chain/test_harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AztecAddress, EthAddress, Fr, Point } from '@aztec/circuits.js';
import { DeployL1Contracts } from '@aztec/ethereum';
import { DebugLogger } from '@aztec/foundation/log';
import { PublicClient, HttpTransport, Chain, getContract } from 'viem';
import { deployAndInitializeNonNativeL2TokenContracts, expectStorageSlot, pointToPublicKey } from '../utils.js';
import { deployAndInitializeNonNativeL2TokenContracts, expectAztecStorageSlot, pointToPublicKey } from '../utils.js';
import { OutboxAbi } from '@aztec/l1-artifacts';
import { sha256ToField } from '@aztec/foundation/crypto';
import { toBufferBE } from '@aztec/foundation/bigint-buffer';
Expand Down Expand Up @@ -199,7 +199,7 @@ export class CrossChainTestHarness {
}

async expectPublicBalanceOnL2(owner: AztecAddress, expectedBalance: bigint, publicBalanceSlot: bigint) {
await expectStorageSlot(
await expectAztecStorageSlot(
this.logger,
this.aztecNode,
this.l2Contract,
Expand Down Expand Up @@ -251,6 +251,37 @@ export class CrossChainTestHarness {
return withdrawEntryKey;
}

async shieldFundsOnL2(shieldAmount: bigint, secretHash: Fr) {
this.logger('Shielding funds on L2');
const shieldTx = this.l2Contract.methods.shield(shieldAmount, secretHash).send({ from: this.ownerAddress });
await shieldTx.isMined(0, 0.1);
const shieldReceipt = await shieldTx.getReceipt();
expect(shieldReceipt.status).toBe(TxStatus.MINED);
}

async redeemShieldPrivatelyOnL2(shieldAmount: bigint, secret: Fr) {
this.logger('Spending commitment in private call');
const privateTx = this.l2Contract.methods
.redeemShield(shieldAmount, secret, this.ownerPub)
.send({ from: this.ownerAddress });

await privateTx.isMined();
const privateReceipt = await privateTx.getReceipt();

expect(privateReceipt.status).toBe(TxStatus.MINED);
}

async unshieldTokensOnL2(unshieldAmount: bigint) {
this.logger('Unshielding tokens');
const unshieldTx = this.l2Contract.methods
.unshieldTokens(unshieldAmount, this.ownerPub, this.ownerAddress.toField())
.send({ from: this.ownerAddress });
await unshieldTx.isMined();
const unshieldReceipt = await unshieldTx.getReceipt();

expect(unshieldReceipt.status).toBe(TxStatus.MINED);
}

async stop() {
await this.aztecNode?.stop();
await this.aztecRpcServer?.stop();
Expand Down
130 changes: 68 additions & 62 deletions yarn-project/end-to-end/src/e2e_public_to_private_messaging.test.ts
Original file line number Diff line number Diff line change
@@ -1,86 +1,92 @@
import { AztecNodeService } from '@aztec/aztec-node';
import {
AztecAddress,
AztecRPCServer,
Contract,
ContractDeployer,
Fr,
TxStatus,
computeMessageSecretHash,
} from '@aztec/aztec.js';
import { PublicToPrivateContractAbi } from '@aztec/noir-contracts/examples';
import { AztecAddress, AztecRPCServer, EthAddress } from '@aztec/aztec.js';
import { DebugLogger } from '@aztec/foundation/log';
import { pointToPublicKey, setup } from './utils.js';
import { CrossChainTestHarness } from './cross_chain/test_harness.js';
import { delay, setup } from './utils.js';

describe('e2e_public_to_private_messaging', () => {
let aztecNode: AztecNodeService;
let aztecRpcServer: AztecRPCServer;
let accounts: AztecAddress[];
let logger: DebugLogger;

let contract: Contract;
let ethAccount: EthAddress;

let underlyingERC20: any;

const initialBalance = 10n;
let ownerAddress: AztecAddress;

let crossChainTestHarness: CrossChainTestHarness;

beforeEach(async () => {
({ aztecNode, aztecRpcServer, accounts, logger } = await setup(2));
const {
aztecNode: aztecNode_,
aztecRpcServer: aztecRpcServer_,
deployL1ContractsValues,
accounts,
logger: logger_,
} = await setup(2);
crossChainTestHarness = await CrossChainTestHarness.new(
initialBalance,
aztecNode_,
aztecRpcServer_,
deployL1ContractsValues,
accounts,
logger_,
);

ethAccount = crossChainTestHarness.ethAccount;
ownerAddress = crossChainTestHarness.ownerAddress;
underlyingERC20 = crossChainTestHarness.underlyingERC20;
aztecRpcServer = crossChainTestHarness.aztecRpcServer;
aztecNode = aztecNode_;

logger = logger_;
logger('Successfully deployed contracts and initialized portal');
}, 100_000);

afterEach(async () => {
await aztecNode?.stop();
await aztecRpcServer?.stop();
await crossChainTestHarness?.stop();
});

const expectBalance = async (owner: AztecAddress, expectedBalance: bigint) => {
const ownerPublicKey = await aztecRpcServer.getAccountPublicKey(owner);
const [balance] = await contract.methods.getBalance(pointToPublicKey(ownerPublicKey)).view({ from: owner });
logger(`Account ${owner} balance: ${balance}`);
expect(balance).toBe(expectedBalance);
};

const deployContract = async () => {
logger(`Deploying Public to Private L2 contract...`);
const deployer = new ContractDeployer(PublicToPrivateContractAbi, aztecRpcServer);
const tx = deployer.deploy().send();
const receipt = await tx.getReceipt();
contract = new Contract(receipt.contractAddress!, PublicToPrivateContractAbi, aztecRpcServer);
await tx.isMined(0, 0.1);
await tx.getReceipt();
logger('L2 contract deployed');
return contract;
};

/**
* Milestone 5.4: Intra-contract Public -\> Private calls.
*/
it('5.4: Should be able to create a commitment in a public function and spend in a private function', async () => {
const mintAmount = 100n;

const [owner, receiver] = accounts;

const deployedContract = await deployContract();

// Create a secret for the transparent message
const secret = Fr.random();
const secretHash = await computeMessageSecretHash(secret);
it('Milestone 5.4: Should be able to create a commitment in a public function and spend in a private function', async () => {
// Generate a claim secret using pedersen
const l1TokenBalance = 1000000n;
const bridgeAmount = 100n;
const shieldAmount = 50n;
const publicBalanceSlot = 2n;

// Create the commitment to be spent in the private domain
logger('Creating commitment in public call');
const publicTx = deployedContract.methods.mintFromPublicToPrivate(mintAmount, secretHash).send({ from: receiver });
const [secret, secretHash] = await crossChainTestHarness.generateClaimSecret();

await publicTx.isMined(0, 0.1);
const publicReceipt = await publicTx.getReceipt();
await crossChainTestHarness.mintTokensOnL1(l1TokenBalance);
const messageKey = await crossChainTestHarness.sendTokensToPortal(bridgeAmount, secretHash);
expect(await underlyingERC20.read.balanceOf([ethAccount.toString()])).toBe(l1TokenBalance - bridgeAmount);

expect(publicReceipt.status).toBe(TxStatus.MINED);
// Wait for the archiver to process the message
await delay(5000); /// waiting 5 seconds.

// Create the transaction spending the commitment
logger('Spending commitment in private call');
const privateTx = deployedContract.methods
.mintFromPublicMessage(mintAmount, secret, pointToPublicKey(await aztecRpcServer.getAccountPublicKey(owner)))
.send({ from: owner });
// Perform another unrelated transaction on L2 to progress the rollup.
await crossChainTestHarness.expectBalanceOnL2(ownerAddress, initialBalance);
const transferAmount = 1n;
await crossChainTestHarness.performL2Transfer(transferAmount);
await crossChainTestHarness.expectBalanceOnL2(ownerAddress, initialBalance - transferAmount);

await crossChainTestHarness.consumeMessageOnAztecAndMintPublicly(bridgeAmount, messageKey, secret);
await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount, publicBalanceSlot);

await privateTx.isMined();
const privateReceipt = await privateTx.getReceipt();
// Create the commitment to be spent in the private domain
await crossChainTestHarness.shieldFundsOnL2(shieldAmount, secretHash);

expect(privateReceipt.status).toBe(TxStatus.MINED);
await expectBalance(owner, mintAmount);
}, 60_000);
// Create the transaction spending the commitment
await crossChainTestHarness.redeemShieldPrivatelyOnL2(shieldAmount, secret);
await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount - shieldAmount, publicBalanceSlot);
await crossChainTestHarness.expectBalanceOnL2(ownerAddress, initialBalance + shieldAmount - transferAmount);

// Unshield the tokens again, sending them to the same account, however this can be any account.
await crossChainTestHarness.unshieldTokensOnL2(shieldAmount);
await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount, publicBalanceSlot);
await crossChainTestHarness.expectBalanceOnL2(ownerAddress, initialBalance - transferAmount);
}, 120_000);
});
13 changes: 10 additions & 3 deletions yarn-project/end-to-end/src/e2e_public_token_contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { DebugLogger } from '@aztec/foundation/log';
import { PublicTokenContractAbi } from '@aztec/noir-contracts/examples';

import times from 'lodash.times';
import { expectStorageSlot, pointToPublicKey, setup } from './utils.js';
import { expectAztecStorageSlot, pointToPublicKey, setup } from './utils.js';
import { L2BlockL2Logs } from '@aztec/types';

describe('e2e_public_token_contract', () => {
Expand Down Expand Up @@ -69,7 +69,7 @@ describe('e2e_public_token_contract', () => {
const receipt = await tx.getReceipt();

expect(receipt.status).toBe(TxStatus.MINED);
await expectStorageSlot(logger, aztecNode, contract, balanceSlot, Fr.fromBuffer(PK.x.toBuffer()), mintAmount);
await expectAztecStorageSlot(logger, aztecNode, contract, balanceSlot, Fr.fromBuffer(PK.x.toBuffer()), mintAmount);
await expectLogsFromLastBlockToBe(['Coins minted']);
}, 45_000);

Expand All @@ -93,7 +93,14 @@ describe('e2e_public_token_contract', () => {
expect(receipts.map(r => r.status)).toEqual(times(3, () => TxStatus.MINED));
expect(receipts.map(r => r.blockNumber)).toEqual(times(3, () => receipts[0].blockNumber));

await expectStorageSlot(logger, aztecNode, contract, balanceSlot, Fr.fromBuffer(PK.x.toBuffer()), mintAmount * 3n);
await expectAztecStorageSlot(
logger,
aztecNode,
contract,
balanceSlot,
Fr.fromBuffer(PK.x.toBuffer()),
mintAmount * 3n,
);
await expectLogsFromLastBlockToBe(['Coins minted', 'Coins minted', 'Coins minted']);
}, 60_000);
});
13 changes: 7 additions & 6 deletions yarn-project/end-to-end/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node';
import { DebugLogger, Logger, createDebugLogger } from '@aztec/foundation/log';
import { Fr } from '@aztec/foundation/fields';
import { MAPPING_SLOT_PEDERSEN_SEPARATOR } from '@aztec/circuits.js';

import {
AztecAddress,
Expand Down Expand Up @@ -242,17 +243,17 @@ export function delay(ms: number): Promise<void> {
* @param key - The key within the mapping.
* @returns The mapping's key.
*/
export async function calculateStorageSlot(slot: bigint, key: Fr): Promise<Fr> {
export async function calculateAztecStorageSlot(slot: bigint, key: Fr): Promise<Fr> {
const wasm = await CircuitsWasm.get();
const balancesStorageSlot = new Fr(slot); // this value is manually set in the Noir contract
const mappingStorageSlot = new Fr(4n); // The pedersen domain separator for storage slot calculations.
const mappingStorageSlot = new Fr(slot); // this value is manually set in the Noir contract
const mappingStorageSlotSeparator = new Fr(BigInt(MAPPING_SLOT_PEDERSEN_SEPARATOR)); // The pedersen domain separator for storage slot calculations.

// Based on `at` function in
// aztec3-packages/yarn-project/noir-contracts/src/contracts/noir-aztec/src/state_vars/map.nr
const storageSlot = Fr.fromBuffer(
pedersenPlookupCommitInputs(
wasm,
[mappingStorageSlot, balancesStorageSlot, key].map(f => f.toBuffer()),
[mappingStorageSlotSeparator, mappingStorageSlot, key].map(f => f.toBuffer()),
),
);

Expand All @@ -268,15 +269,15 @@ export async function calculateStorageSlot(slot: bigint, key: Fr): Promise<Fr> {
* @param key - The mapping's key.
* @param expectedValue - The expected value of the mapping.
*/
export async function expectStorageSlot(
export async function expectAztecStorageSlot(
logger: Logger,
aztecNode: AztecNodeService,
contract: Contract,
slot: bigint,
key: Fr,
expectedValue: bigint,
) {
const storageSlot = await calculateStorageSlot(slot, key);
const storageSlot = await calculateAztecStorageSlot(slot, key);
const storageValue = await aztecNode.getStorageAt(contract.address!, storageSlot.value);
if (storageValue === undefined) {
throw new Error(`Storage slot ${storageSlot} not found`);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/noir-contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ This package contains the source code and the Aztec ABIs for the example contrac
compiler_version = "0.7.1"

[dependencies]
aztec = { path = "../noir-aztec" }
aztec = { path = "../../libs/noir-aztec" }
```

4. Replace the content of the generated `example_contract/src/main.nr` file with your contract code.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ authors = [""]
compiler_version = "0.1"

[dependencies]
aztec = { path = "../noir-aztec" }
aztec = { path = "../../libs/noir-aztec" }
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ authors = [""]
compiler_version = "0.1"

[dependencies]
aztec = { path = "../noir-aztec" }
aztec = { path = "../../libs/noir-aztec" }
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ authors = [""]
compiler_version = "0.1"

[dependencies]
aztec = { path = "../noir-aztec" }
aztec = { path = "../../libs/noir-aztec" }
Loading