Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Recursive fn calls to spend more notes. #1779

Merged
merged 13 commits into from
Aug 25, 2023
60 changes: 30 additions & 30 deletions yarn-project/acir-simulator/src/client/private_execution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,13 @@ describe('Private Execution test suite', () => {
const runSimulator = async ({
abi,
args = [],
origin = AztecAddress.random(),
msgSender = AztecAddress.ZERO,
contractAddress = defaultContractAddress,
portalContractAddress = EthAddress.ZERO,
txContext = {},
}: {
abi: FunctionAbi;
origin?: AztecAddress;
msgSender?: AztecAddress;
contractAddress?: AztecAddress;
portalContractAddress?: EthAddress;
args?: any[];
Expand All @@ -101,7 +101,7 @@ describe('Private Execution test suite', () => {
const packedArguments = await PackedArguments.fromArgs(encodeArguments(abi, args), circuitsWasm);
const functionData = FunctionData.fromAbi(abi);
const txRequest = TxExecutionRequest.from({
origin,
origin: contractAddress,
argsHash: packedArguments.hash,
functionData,
txContext: TxContext.from({ ...txContextFields, ...txContext }),
Expand All @@ -113,6 +113,7 @@ describe('Private Execution test suite', () => {
abi,
functionData.isConstructor ? AztecAddress.ZERO : contractAddress,
portalContractAddress,
msgSender,
);
};

Expand Down Expand Up @@ -301,12 +302,13 @@ describe('Private Execution test suite', () => {
);
await insertLeaves(consumedNotes.map(n => n.siloedNoteHash));

const args = [amountToTransfer, owner, recipient];
const result = await runSimulator({ args, abi });
const args = [amountToTransfer, recipient];
const result = await runSimulator({ args, abi, msgSender: owner });

// The two notes were nullified
const newNullifiers = result.callStackItem.publicInputs.newNullifiers.filter(field => !field.equals(Fr.ZERO));
expect(newNullifiers).toEqual(consumedNotes.map(n => n.innerNullifier));
expect(newNullifiers).toHaveLength(consumedNotes.length);
expect(newNullifiers).toEqual(expect.arrayContaining(consumedNotes.map(n => n.innerNullifier)));

expect(result.preimages.newNotes).toHaveLength(2);
const [changeNote, recipientNote] = result.preimages.newNotes;
Expand All @@ -327,7 +329,8 @@ describe('Private Execution test suite', () => {
expect(changeNote.preimage[0]).toEqual(new Fr(40n));

const readRequests = result.callStackItem.publicInputs.readRequests.filter(field => !field.equals(Fr.ZERO));
expect(readRequests).toEqual(consumedNotes.map(n => n.uniqueSiloedNoteHash));
expect(readRequests).toHaveLength(consumedNotes.length);
expect(readRequests).toEqual(expect.arrayContaining(consumedNotes.map(n => n.uniqueSiloedNoteHash)));
});

it('should be able to transfer with dummy notes', async () => {
Expand All @@ -345,8 +348,8 @@ describe('Private Execution test suite', () => {
);
await insertLeaves(consumedNotes.map(n => n.siloedNoteHash));

const args = [amountToTransfer, owner, recipient];
const result = await runSimulator({ args, abi });
const args = [amountToTransfer, recipient];
const result = await runSimulator({ args, abi, msgSender: owner });

const newNullifiers = result.callStackItem.publicInputs.newNullifiers.filter(field => !field.equals(Fr.ZERO));
expect(newNullifiers).toEqual(consumedNotes.map(n => n.innerNullifier));
Expand Down Expand Up @@ -531,12 +534,13 @@ describe('Private Execution test suite', () => {
);
await insertLeaves(consumedNotes.map(n => n.siloedNoteHash));

const args = [amountToTransfer, owner, recipient];
const result = await runSimulator({ args, abi });
const args = [amountToTransfer, recipient];
const result = await runSimulator({ args, abi, msgSender: owner });

// The two notes were nullified
const newNullifiers = result.callStackItem.publicInputs.newNullifiers.filter(field => !field.equals(Fr.ZERO));
expect(newNullifiers).toEqual(consumedNotes.map(n => n.innerNullifier));
expect(newNullifiers).toHaveLength(consumedNotes.length);
expect(newNullifiers).toEqual(expect.arrayContaining(consumedNotes.map(n => n.innerNullifier)));

expect(result.preimages.newNotes).toHaveLength(2);
const [changeNote, recipientNote] = result.preimages.newNotes;
Expand All @@ -557,7 +561,8 @@ describe('Private Execution test suite', () => {
expect(changeNote.preimage[0]).toEqual(new Fr(40n));

const readRequests = result.callStackItem.publicInputs.readRequests.filter(field => !field.equals(Fr.ZERO));
expect(readRequests).toEqual(consumedNotes.map(n => n.uniqueSiloedNoteHash));
expect(readRequests).toHaveLength(consumedNotes.length);
expect(readRequests).toEqual(expect.arrayContaining(consumedNotes.map(n => n.uniqueSiloedNoteHash)));
});

it('should be able to transfer with dummy notes', async () => {
Expand All @@ -575,8 +580,8 @@ describe('Private Execution test suite', () => {
);
await insertLeaves(consumedNotes.map(n => n.siloedNoteHash));

const args = [amountToTransfer, owner, recipient];
const result = await runSimulator({ args, abi });
const args = [amountToTransfer, recipient];
const result = await runSimulator({ args, abi, msgSender: owner });

const newNullifiers = result.callStackItem.publicInputs.newNullifiers.filter(field => !field.equals(Fr.ZERO));
expect(newNullifiers).toEqual(consumedNotes.map(n => n.innerNullifier));
Expand Down Expand Up @@ -613,7 +618,7 @@ describe('Private Execution test suite', () => {
logger(`Calling child function ${childSelector.toString()} at ${childAddress.toShortString()}`);

const args = [Fr.fromBuffer(childAddress.toBuffer()), Fr.fromBuffer(childSelector.toBuffer())];
const result = await runSimulator({ args, abi: parentAbi, origin: parentAddress });
const result = await runSimulator({ args, abi: parentAbi });

expect(result.callStackItem.publicInputs.returnValues[0]).toEqual(new Fr(privateIncrement));
expect(oracle.getFunctionABI.mock.calls[0]).toEqual([childAddress, childSelector]);
Expand Down Expand Up @@ -651,7 +656,6 @@ describe('Private Execution test suite', () => {
});

it('test function should be callable through autogenerated interface', async () => {
const importerAddress = AztecAddress.random();
const testAddress = AztecAddress.random();
const parentAbi = ImportTestContractAbi.functions.find(f => f.name === 'main')!;
const testCodeGenSelector = FunctionSelector.fromNameAndParameters(
Expand All @@ -664,7 +668,7 @@ describe('Private Execution test suite', () => {

logger(`Calling importer main function`);
const args = [testAddress];
const result = await runSimulator({ args, abi: parentAbi, origin: importerAddress });
const result = await runSimulator({ args, abi: parentAbi });

expect(result.callStackItem.publicInputs.returnValues[0]).toEqual(argsHash);
expect(oracle.getFunctionABI.mock.calls[0]).toEqual([testAddress, testCodeGenSelector]);
Expand Down Expand Up @@ -716,7 +720,7 @@ describe('Private Execution test suite', () => {
});

const args = [bridgedAmount, recipient, messageKey, secret, canceller.toField()];
const result = await runSimulator({ origin: contractAddress, contractAddress, abi, args });
const result = await runSimulator({ contractAddress, abi, args });

// Check a nullifier has been inserted
const newNullifiers = result.callStackItem.publicInputs.newNullifiers.filter(field => !field.equals(Fr.ZERO));
Expand Down Expand Up @@ -751,7 +755,6 @@ describe('Private Execution test suite', () => {
});

const result = await runSimulator({
origin: contractAddress,
abi,
args: [amount, secret, recipient],
});
Expand Down Expand Up @@ -781,7 +784,7 @@ describe('Private Execution test suite', () => {

const args = [Fr.fromBuffer(childAddress.toBuffer()), childSelector.toField(), 42n];
const result = await runSimulator({
origin: parentAddress,
msgSender: parentAddress,
contractAddress: parentAddress,
abi: parentAbi,
args,
Expand Down Expand Up @@ -855,8 +858,7 @@ describe('Private Execution test suite', () => {
const result = await runSimulator({
args: args,
abi: abi,
origin: contractAddress,
contractAddress: contractAddress,
contractAddress,
});

expect(result.preimages.newNotes).toHaveLength(1);
Expand Down Expand Up @@ -918,7 +920,6 @@ describe('Private Execution test suite', () => {
const result = await runSimulator({
args: args,
abi: abi,
origin: contractAddress,
contractAddress: contractAddress,
});

Expand Down Expand Up @@ -972,8 +973,7 @@ describe('Private Execution test suite', () => {
const result = await runSimulator({
args: args,
abi: abi,
origin: contractAddress,
contractAddress: contractAddress,
contractAddress,
});

expect(result.preimages.newNotes).toHaveLength(1);
Expand Down Expand Up @@ -1015,7 +1015,7 @@ describe('Private Execution test suite', () => {
const pubKey = completeAddress.publicKey;

oracle.getCompleteAddress.mockResolvedValue(completeAddress);
const result = await runSimulator({ origin: AztecAddress.random(), abi, args });
const result = await runSimulator({ abi, args });
expect(result.returnValues).toEqual([pubKey.x.value, pubKey.y.value]);
});
});
Expand All @@ -1033,7 +1033,7 @@ describe('Private Execution test suite', () => {

// Overwrite the oracle return value
oracle.getPortalContractAddress.mockResolvedValue(portalContractAddress);
const result = await runSimulator({ origin: AztecAddress.random(), abi, args });
const result = await runSimulator({ abi, args });
expect(result.returnValues).toEqual(portalContractAddress.toField().value);
});

Expand All @@ -1045,7 +1045,7 @@ describe('Private Execution test suite', () => {
abi.returnTypes = [{ kind: 'field' }];

// Overwrite the oracle return value
const result = await runSimulator({ origin: AztecAddress.random(), abi, args: [], contractAddress });
const result = await runSimulator({ abi, args: [], contractAddress });
expect(result.returnValues).toEqual(contractAddress.toField().value);
});

Expand All @@ -1057,7 +1057,7 @@ describe('Private Execution test suite', () => {
abi.returnTypes = [{ kind: 'field' }];

// Overwrite the oracle return value
const result = await runSimulator({ origin: AztecAddress.random(), abi, args: [], portalContractAddress });
const result = await runSimulator({ abi, args: [], portalContractAddress });
expect(result.returnValues).toEqual(portalContractAddress.toField().value);
});
});
Expand Down
7 changes: 3 additions & 4 deletions yarn-project/acir-simulator/src/client/simulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,15 @@ export class AcirSimulator {
* @param entryPointABI - The ABI of the entry point function.
* @param contractAddress - The address of the contract (should match request.origin)
* @param portalContractAddress - The address of the portal contract.
* @param historicBlockData - Data required to reconstruct the block hash, this also contains the historic tree roots.
* @param curve - The curve instance for elliptic curve operations.
* @param packedArguments - The entrypoint packed arguments
* @param msgSender - The address calling the function. This can be replaced to simulate a call from another contract or a specific account.
* @returns The result of the execution.
*/
public async run(
request: TxExecutionRequest,
entryPointABI: FunctionAbiWithDebugMetadata,
contractAddress: AztecAddress,
portalContractAddress: EthAddress,
msgSender = AztecAddress.ZERO,
): Promise<ExecutionResult> {
if (entryPointABI.functionType !== FunctionType.SECRET) {
throw new Error(`Cannot run ${entryPointABI.functionType} function as secret`);
Expand All @@ -76,7 +75,7 @@ export class AcirSimulator {

const historicBlockData = await this.db.getHistoricBlockData();
const callContext = new CallContext(
AztecAddress.ZERO,
msgSender,
contractAddress,
portalContractAddress,
false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ async function main() {

// Perform a transfer
logger(`Transferring ${SECONDARY_AMOUNT} tokens from owner to another account.`);
const transferTx = zkContract.methods
.transfer(SECONDARY_AMOUNT, owner.address, account2.address)
.send({ origin: owner.address });
const transferTx = zkContract.methods.transfer(SECONDARY_AMOUNT, account2.address).send({ origin: owner.address });
await transferTx.isMined({ interval: 0.5 });
const balanceAfterTransfer = await getBalance(zkContract, owner.address);
const receiverBalance = await getBalance(zkContract, account2.address);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,7 @@ const transferWethOnL2 = async (
receiver: AztecAddress,
transferAmount: bigint,
) => {
const transferTx = wethL2Contract.methods
.transfer(transferAmount, ownerAddress, receiver)
.send({ origin: ownerAddress });
const transferTx = wethL2Contract.methods.transfer(transferAmount, receiver).send({ origin: ownerAddress });
await transferTx.isMined({ interval: 0.5 });
const transferReceipt = await transferTx.getReceipt();
// expect(transferReceipt.status).toBe(TxStatus.MINED);
Expand Down
4 changes: 1 addition & 3 deletions yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,7 @@ const transferWethOnL2 = async (
receiver: AztecAddress,
transferAmount: bigint,
) => {
const transferTx = wethL2Contract.methods
.transfer(transferAmount, ownerAddress, receiver)
.send({ origin: ownerAddress });
const transferTx = wethL2Contract.methods.transfer(transferAmount, receiver).send({ origin: ownerAddress });
await transferTx.isMined();
const transferReceipt = await transferTx.getReceipt();
expect(transferReceipt.status).toBe(TxStatus.MINED);
Expand Down
8 changes: 2 additions & 6 deletions yarn-project/end-to-end/src/e2e_2_rpc_servers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ describe('e2e_2_rpc_servers', () => {

// Transfer funds from A to B via RPC server A
const contractWithWalletA = await PrivateTokenContract.at(tokenAddress, walletA);
const txAToB = contractWithWalletA.methods
.transfer(transferAmount1, userA.address, userB.address)
.send({ origin: userA.address });
const txAToB = contractWithWalletA.methods.transfer(transferAmount1, userB.address).send({ origin: userA.address });

await txAToB.isMined({ interval: 0.1 });
const receiptAToB = await txAToB.getReceipt();
Expand All @@ -127,9 +125,7 @@ describe('e2e_2_rpc_servers', () => {

// Transfer funds from B to A via RPC server B
const contractWithWalletB = await PrivateTokenContract.at(tokenAddress, walletB);
const txBToA = contractWithWalletB.methods
.transfer(transferAmount2, userB.address, userA.address)
.send({ origin: userB.address });
const txBToA = contractWithWalletB.methods.transfer(transferAmount2, userA.address).send({ origin: userB.address });

await txBToA.isMined({ interval: 0.1 });
const receiptBToA = await txBToA.getReceipt();
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/src/e2e_aztec_js_browser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ conditionalDescribe()('e2e_aztec.js_browser', () => {
const receiver = accounts[1].address;
const wallet = await AztecJs.getSandboxAccountsWallet(client);
const contract = await Contract.at(AztecAddress.fromString(contractAddress), PrivateTokenContractAbi, wallet);
await contract.methods.transfer(transferAmount, owner, receiver).send({ origin: owner }).wait();
await contract.methods.transfer(transferAmount, receiver).send({ origin: owner }).wait();
console.log(`Transferred ${transferAmount} tokens to new Account`);
return await contract.methods.getBalance(receiver).view({ from: receiver });
},
Expand Down
14 changes: 3 additions & 11 deletions yarn-project/end-to-end/src/e2e_escrow_contract.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { AztecNodeService } from '@aztec/aztec-node';
import { AztecRPCServer } from '@aztec/aztec-rpc';
import { AztecAddress, BatchCall, Wallet, generatePublicKey } from '@aztec/aztec.js';
import { CompleteAddress, Fr, FunctionSelector, PrivateKey, getContractDeploymentInfo } from '@aztec/circuits.js';
import { toBufferBE } from '@aztec/foundation/bigint-buffer';
import { CompleteAddress, Fr, PrivateKey, getContractDeploymentInfo } from '@aztec/circuits.js';
import { DebugLogger } from '@aztec/foundation/log';
import { EscrowContractAbi, PrivateTokenContractAbi } from '@aztec/noir-contracts/artifacts';
import { EscrowContractAbi } from '@aztec/noir-contracts/artifacts';
import { EscrowContract, PrivateTokenContract } from '@aztec/noir-contracts/types';
import { AztecRPC, PublicKey } from '@aztec/types';

Expand All @@ -25,13 +24,6 @@ describe('e2e_escrow_contract', () => {
let escrowPrivateKey: PrivateKey;
let escrowPublicKey: PublicKey;

beforeAll(() => {
// Validate transfer selector. If this fails, then make sure to change it in the escrow contract.
const transferAbi = PrivateTokenContractAbi.functions.find(f => f.name === 'transfer')!;
const transferSelector = FunctionSelector.fromNameAndParameters(transferAbi.name, transferAbi.parameters);
expect(transferSelector.toBuffer()).toEqual(toBufferBE(0xdcd4c318n, 4));
});

beforeEach(async () => {
// Setup environment
({ aztecNode, aztecRpcServer, accounts, wallet, logger } = await setup(2));
Expand Down Expand Up @@ -92,7 +84,7 @@ describe('e2e_escrow_contract', () => {
await expectBalance(owner, 50n);

const actions = [
privateTokenContract.methods.transfer(10, owner, recipient).request(),
privateTokenContract.methods.transfer(10, recipient).request(),
escrowContract.methods.withdraw(privateTokenContract.address, 20, recipient).request(),
];

Expand Down
Loading