Skip to content

Commit

Permalink
chore: add FunctionData.fromAbi for QoL (#1333)
Browse files Browse the repository at this point in the history
# Description

Fixes #1223 where possible by introducing a `fromAbi` function on the
`FunctionData`, note that we can also use a `ContractFunctionDao` since
it consist of data from that abi.

For the public executor, we don't have the abi so we still need to
populate it little differently there.


# Checklist:

- [ ] I have reviewed my diff in github, line by line.
- [ ] Every change is related to the PR description.
- [ ] I have
[linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
this pull request to the issue(s) that it resolves.
- [ ] There are no unexpected formatting changes, superfluous debug
logs, or commented-out code.
- [ ] The branch has been merged or rebased against the head of its
merge target.
- [ ] I'm happy for the PR to be merged at the reviewer's next
convenience.
  • Loading branch information
LHerskind authored Aug 1, 2023
1 parent 5353ed0 commit 6f5fc3b
Show file tree
Hide file tree
Showing 10 changed files with 47 additions and 48 deletions.
24 changes: 14 additions & 10 deletions yarn-project/acir-simulator/src/client/private_execution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,20 @@ describe('Private Execution test suite', () => {
args = [],
origin = AztecAddress.random(),
contractAddress = defaultContractAddress,
isConstructor = false,
txContext = {},
}: {
abi: FunctionAbi;
origin?: AztecAddress;
contractAddress?: AztecAddress;
isConstructor?: boolean;
args?: any[];
txContext?: Partial<FieldsOf<TxContext>>;
}) => {
const packedArguments = await PackedArguments.fromArgs(encodeArguments(abi, args), circuitsWasm);
const functionData = FunctionData.fromAbi(abi);
const txRequest = TxExecutionRequest.from({
origin,
argsHash: packedArguments.hash,
functionData: new FunctionData(Buffer.alloc(4), false, true, isConstructor),
functionData,
txContext: TxContext.from({ ...txContextFields, ...txContext }),
packedArguments: [packedArguments],
});
Expand All @@ -110,7 +109,7 @@ describe('Private Execution test suite', () => {
return acirSimulator.run(
txRequest,
abi,
isConstructor ? AztecAddress.ZERO : contractAddress,
functionData.isConstructor ? AztecAddress.ZERO : contractAddress,
EthAddress.ZERO,
historicRoots,
);
Expand Down Expand Up @@ -156,7 +155,7 @@ describe('Private Execution test suite', () => {
const abi = TestContractAbi.functions[0];
const contractDeploymentData = makeContractDeploymentData(100);
const txContext = { isContractDeploymentTx: true, contractDeploymentData };
const result = await runSimulator({ abi, isConstructor: true, txContext });
const result = await runSimulator({ abi, txContext });

const emptyCommitments = new Array(MAX_NEW_COMMITMENTS_PER_CALL).fill(Fr.ZERO);
expect(result.callStackItem.publicInputs.newCommitments).toEqual(emptyCommitments);
Expand Down Expand Up @@ -242,7 +241,7 @@ describe('Private Execution test suite', () => {
it('should a constructor with arguments that inserts notes', async () => {
const abi = ZkTokenContractAbi.functions.find(f => f.name === 'constructor')!;

const result = await runSimulator({ args: [140, owner], abi, isConstructor: true });
const result = await runSimulator({ args: [140, owner], abi });

expect(result.preimages.newNotes).toHaveLength(1);
const newNote = result.preimages.newNotes[0];
Expand Down Expand Up @@ -398,7 +397,7 @@ describe('Private Execution test suite', () => {
const parentAbi = ParentContractAbi.functions.find(f => f.name === 'entryPoint')!;
const parentAddress = AztecAddress.random();
const childAddress = AztecAddress.random();
const childSelector = Buffer.alloc(4, 1); // should match the call
const childSelector = generateFunctionSelector(childAbi.name, childAbi.parameters);

oracle.getFunctionABI.mockImplementation(() => Promise.resolve(childAbi));
oracle.getPortalContractAddress.mockImplementation(() => Promise.resolve(EthAddress.ZERO));
Expand Down Expand Up @@ -512,13 +511,14 @@ describe('Private Execution test suite', () => {
describe('enqueued calls', () => {
it.each([false, true])('parent should enqueue call to child', async isInternal => {
const parentAbi = ParentContractAbi.functions.find(f => f.name === 'enqueueCallToChild')!;
const childContractAbi = ParentContractAbi.functions[0];
const childAddress = AztecAddress.random();
const childPortalContractAddress = EthAddress.random();
const childSelector = Buffer.alloc(4, 1); // should match the call
const childSelector = generateFunctionSelector(childContractAbi.name, childContractAbi.parameters);
const parentAddress = AztecAddress.random();

oracle.getPortalContractAddress.mockImplementation(() => Promise.resolve(childPortalContractAddress));
oracle.getFunctionABI.mockImplementation(() => Promise.resolve({ ...ChildContractAbi.functions[0], isInternal }));
oracle.getFunctionABI.mockImplementation(() => Promise.resolve({ ...childContractAbi, isInternal }));

const args = [Fr.fromBuffer(childAddress.toBuffer()), Fr.fromBuffer(childSelector), 42n];
const result = await runSimulator({
Expand All @@ -528,9 +528,13 @@ describe('Private Execution test suite', () => {
args,
});

// Alter function data (abi) to match the manipulated oracle
const functionData = FunctionData.fromAbi(childContractAbi);
functionData.isInternal = isInternal;

const publicCallRequest = PublicCallRequest.from({
contractAddress: childAddress,
functionData: new FunctionData(childSelector, isInternal, false, false),
functionData: functionData,
args: [new Fr(42n)],
callContext: CallContext.from({
msgSender: parentAddress,
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/acir-simulator/src/client/private_execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export class PrivateFunctionExecution {
curve: Grumpkin,
) {
const targetAbi = await this.context.db.getFunctionABI(targetContractAddress, targetFunctionSelector);
const targetFunctionData = new FunctionData(targetFunctionSelector, targetAbi.isInternal, true, false);
const targetFunctionData = FunctionData.fromAbi(targetAbi);
const derivedCallContext = await this.deriveCallContext(callerContext, targetContractAddress, false, false);
const context = this.context.extend();

Expand Down Expand Up @@ -301,10 +301,11 @@ export class PrivateFunctionExecution {
): Promise<PublicCallRequest> {
const targetAbi = await this.context.db.getFunctionABI(targetContractAddress, targetFunctionSelector);
const derivedCallContext = await this.deriveCallContext(callerContext, targetContractAddress, false, false);

return PublicCallRequest.from({
args: targetArgs,
callContext: derivedCallContext,
functionData: new FunctionData(targetFunctionSelector, targetAbi.isInternal, false, false),
functionData: FunctionData.fromAbi(targetAbi),
contractAddress: targetContractAddress,
});
}
Expand Down
12 changes: 7 additions & 5 deletions yarn-project/acir-simulator/src/public/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import {
PrivateHistoricTreeRoots,
} from '@aztec/circuits.js';
import { pedersenPlookupCommitInputs } from '@aztec/circuits.js/barretenberg';
import { FunctionAbi, encodeArguments } from '@aztec/foundation/abi';
import { FunctionAbi, encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { keccak } from '@aztec/foundation/crypto';
import { EthAddress } from '@aztec/foundation/eth-address';
import { Fr } from '@aztec/foundation/fields';
import { toBigInt } from '@aztec/foundation/serialize';
Expand Down Expand Up @@ -63,7 +62,7 @@ describe('ACIR public execution simulator', () => {
it('should run the mint function', async () => {
const contractAddress = AztecAddress.random();
const mintAbi = PublicTokenContractAbi.functions.find(f => f.name === 'mint')!;
const functionData = new FunctionData(Buffer.alloc(4), false, false, false);
const functionData = FunctionData.fromAbi(mintAbi);
const args = encodeArguments(mintAbi, [140, recipient]);

const callContext = CallContext.from({
Expand Down Expand Up @@ -192,11 +191,14 @@ describe('ACIR public execution simulator', () => {
async isInternal => {
const parentContractAddress = AztecAddress.random();
const parentEntryPointFn = ParentContractAbi.functions.find(f => f.name === 'pubEntryPoint')!;
const parentEntryPointFnSelector = keccak(Buffer.from(parentEntryPointFn.name)).subarray(0, 4);
const parentEntryPointFnSelector = generateFunctionSelector(
parentEntryPointFn.name,
parentEntryPointFn.parameters,
);

const childContractAddress = AztecAddress.random();
const childValueFn = ChildContractAbi.functions.find(f => f.name === 'pubValue')!;
const childValueFnSelector = keccak(Buffer.from(childValueFn.name)).subarray(0, 4);
const childValueFnSelector = generateFunctionSelector(childValueFn.name, childValueFn.parameters);

const initialValue = 3n;

Expand Down
15 changes: 3 additions & 12 deletions yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
PrivateKey,
PublicKey,
} from '@aztec/circuits.js';
import { FunctionType, encodeArguments } from '@aztec/foundation/abi';
import { encodeArguments } from '@aztec/foundation/abi';
import { Fr } from '@aztec/foundation/fields';
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
import {
Expand Down Expand Up @@ -385,19 +385,10 @@ export class AztecRPCServer implements AztecRPC {
throw new Error(`Unknown function ${functionName} in contract ${contract.name}.`);
}

const flatArgs = encodeArguments(functionDao, args);

const functionData = new FunctionData(
functionDao.selector,
functionDao.isInternal,
functionDao.functionType === FunctionType.SECRET,
false,
);

return {
args: flatArgs,
args: encodeArguments(functionDao, args),
from,
functionData,
functionData: FunctionData.fromAbi(functionDao),
to,
};
}
Expand Down
3 changes: 1 addition & 2 deletions yarn-project/aztec-rpc/src/contract_tree/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ export class ContractTree {
}));
const leaves = generateFunctionLeaves(functions, wasm);
const root = computeFunctionTreeRoot(wasm, leaves);
const constructorSelector = generateFunctionSelector(constructorAbi.name, constructorAbi.parameters);
const functionData = new FunctionData(constructorSelector, false, true, true);
const functionData = FunctionData.fromAbi(constructorAbi);
const vkHash = hashVKStr(constructorAbi.verificationKey, wasm);
const argsHash = await computeVarArgsHash(wasm, args);
const constructorHash = hashConstructor(wasm, functionData, argsHash, vkHash);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
TxContext,
} from '@aztec/circuits.js';
import { Signer } from '@aztec/circuits.js/barretenberg';
import { ContractAbi, encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi';
import { ContractAbi, encodeArguments } from '@aztec/foundation/abi';
import { ExecutionRequest, PackedArguments, TxExecutionRequest } from '@aztec/types';

import partition from 'lodash.partition';
Expand Down Expand Up @@ -50,12 +50,11 @@ export class SingleKeyAccountContract implements AccountImplementation {
const publicKey = await generatePublicKey(this.privateKey);
const args = [payload, publicKey.toBuffer(), signature, this.partialContractAddress];
const abi = this.getEntrypointAbi();
const selector = generateFunctionSelector(abi.name, abi.parameters);
const packedArgs = await PackedArguments.fromArgs(encodeArguments(abi, args), wasm);
const txRequest = TxExecutionRequest.from({
argsHash: packedArgs.hash,
origin: this.address,
functionData: new FunctionData(selector, abi.isInternal, true, false),
functionData: FunctionData.fromAbi(abi),
txContext,
packedArguments: [...callsPackedArguments, packedArgs],
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AztecAddress, CircuitsWasm, FunctionData, PrivateKey, TxContext } from '@aztec/circuits.js';
import { Signer } from '@aztec/circuits.js/barretenberg';
import { ContractAbi, encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi';
import { ContractAbi, encodeArguments } from '@aztec/foundation/abi';
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
import { ExecutionRequest, PackedArguments, TxExecutionRequest } from '@aztec/types';

Expand Down Expand Up @@ -41,12 +41,11 @@ export class StoredKeyAccountContract implements AccountImplementation {

const args = [payload, signature];
const abi = this.getEntrypointAbi();
const selector = generateFunctionSelector(abi.name, abi.parameters);
const packedArgs = await PackedArguments.fromArgs(encodeArguments(abi, args), wasm);
const txRequest = TxExecutionRequest.from({
argsHash: packedArgs.hash,
origin: this.address,
functionData: new FunctionData(selector, abi.isInternal, true, false),
functionData: FunctionData.fromAbi(abi),
txContext,
packedArguments: [...callsPackedArguments, packedArgs],
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AztecAddress, Fr, FunctionData, TxContext } from '@aztec/circuits.js';
import { FunctionAbi, FunctionType, encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi';
import { FunctionAbi, FunctionType, encodeArguments } from '@aztec/foundation/abi';
import { ExecutionRequest, Tx, TxExecutionRequest } from '@aztec/types';

import { Wallet } from '../aztec_rpc_client/wallet.js';
Expand Down Expand Up @@ -98,16 +98,9 @@ export class ContractFunctionInteraction {
const flatArgs = encodeArguments(this.functionDao, this.args);
from = from ?? this.wallet.getAddress();

const functionData = new FunctionData(
generateFunctionSelector(this.functionDao.name, this.functionDao.parameters),
this.functionDao.isInternal,
this.functionDao.functionType === FunctionType.SECRET,
this.functionDao.name === 'constructor',
);

return {
args: flatArgs,
functionData,
functionData: FunctionData.fromAbi(this.functionDao),
to,
from,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ export async function getContractDeploymentInfo(
}));
const leaves = generateFunctionLeaves(functions, wasm);
const functionTreeRoot = computeFunctionTreeRoot(wasm, leaves);
const constructorSelector = generateFunctionSelector(constructorAbi.name, constructorAbi.parameters);
const functionData = new FunctionData(constructorSelector, false, true, true);
const functionData = FunctionData.fromAbi(constructorAbi);
const flatArgs = encodeArguments(constructorAbi, args);
const argsHash = await computeVarArgsHash(wasm, flatArgs);
const constructorHash = hashConstructor(wasm, functionData, argsHash, constructorVkHash.toBuffer());
Expand Down
12 changes: 12 additions & 0 deletions yarn-project/circuits.js/src/structs/function_data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { FunctionAbi, FunctionType, generateFunctionSelector } from '@aztec/foundation/abi';
import { BufferReader, deserializeUInt32, numToUInt32BE } from '@aztec/foundation/serialize';

import { ContractFunctionDao } from '../index.js';
import { serializeToBuffer } from '../utils/serialize.js';

const FUNCTION_SELECTOR_LENGTH = 4;
Expand Down Expand Up @@ -40,6 +42,16 @@ export class FunctionData {
this.functionSelectorBuffer = numToUInt32BE(functionSelector);
}
}

static fromAbi(abi: FunctionAbi | ContractFunctionDao): FunctionData {
return new FunctionData(
generateFunctionSelector(abi.name, abi.parameters),
abi.isInternal,
abi.functionType === FunctionType.SECRET,
abi.name === 'constructor',
);
}

// For serialization, must match function_selector name in C++ and return as number
// TODO(AD) somehow remove this cruft, probably by using a buffer selector in C++
get functionSelector(): number {
Expand Down

0 comments on commit 6f5fc3b

Please sign in to comment.