From e07ea1a887484f3a1a2ba8b5328af5abf6ccc6a2 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Tue, 5 Sep 2023 21:44:59 +0100 Subject: [PATCH] refactor: Update function selector computation (#2001) Fixed #1990. Also adds an oracle to more easily compute selectors from inside the contracts for improved devex. --- yarn-project/acir-simulator/src/acvm/acvm.ts | 1 + .../src/client/function_selectors.ts | 5 -- .../src/client/private_execution.ts | 5 ++ .../acir-simulator/src/client/simulator.ts | 26 +++++++--- .../src/client/unconstrained_execution.ts | 7 ++- .../acir-simulator/src/public/executor.ts | 5 +- .../src/e2e_lending_contract.test.ts | 2 +- yarn-project/foundation/src/abi/decoder.ts | 52 ++++++++++++++++++- .../foundation/src/abi/function_selector.ts | 9 ++-- .../src/contracts/child_contract/src/main.nr | 11 ++-- .../lending_contract/src/interfaces.nr | 17 +++--- .../contracts/lending_contract/src/main.nr | 33 ++++++------ .../native_token_contract/src/main.nr | 28 ++-------- .../non_native_token_contract/src/main.nr | 7 ++- .../src/contracts/parent_contract/src/main.nr | 9 ++-- .../src/interface.nr | 12 ++--- .../private_token_contract/src/interface.nr | 4 +- .../contracts/test_contract/src/interface.nr | 18 +++---- .../noir-libs/noir-aztec/src/oracle.nr | 3 +- .../noir-aztec/src/oracle/compute_selector.nr | 6 +++ 20 files changed, 163 insertions(+), 97 deletions(-) delete mode 100644 yarn-project/acir-simulator/src/client/function_selectors.ts create mode 100644 yarn-project/noir-libs/noir-aztec/src/oracle/compute_selector.nr diff --git a/yarn-project/acir-simulator/src/acvm/acvm.ts b/yarn-project/acir-simulator/src/acvm/acvm.ts index 23f3a477b58..076842c1a6d 100644 --- a/yarn-project/acir-simulator/src/acvm/acvm.ts +++ b/yarn-project/acir-simulator/src/acvm/acvm.ts @@ -32,6 +32,7 @@ export const ONE_ACVM_FIELD: ACVMField = `0x${'00'.repeat(Fr.SIZE_IN_BYTES - 1)} * The supported oracle names. */ type ORACLE_NAMES = + | 'computeSelector' | 'packArguments' | 'getSecretKey' | 'getNote' diff --git a/yarn-project/acir-simulator/src/client/function_selectors.ts b/yarn-project/acir-simulator/src/client/function_selectors.ts deleted file mode 100644 index 1c8e34f0a35..00000000000 --- a/yarn-project/acir-simulator/src/client/function_selectors.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { FunctionSelector } from '@aztec/circuits.js'; - -export const computeNoteHashAndNullifierSignature = 'compute_note_hash_and_nullifier(field,field,field,array)'; - -export const computeNoteHashAndNullifierSelector = FunctionSelector.fromSignature(computeNoteHashAndNullifierSignature); diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index 943c89a4839..4a079ca3b5b 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -72,6 +72,11 @@ export class PrivateFunctionExecution { const unencryptedLogs = new FunctionL2Logs([]); const { partialWitness } = await acvm(await AcirSimulator.getSolver(), acir, initialWitness, { + computeSelector: (...args) => { + const signature = oracleDebugCallToFormattedStr(args); + const returnValue = toACVMField(FunctionSelector.fromSignature(signature).toField()); + return Promise.resolve(returnValue); + }, packArguments: async args => { return toACVMField(await this.context.packedArgsCache.pack(args.map(fromACVMField))); }, diff --git a/yarn-project/acir-simulator/src/client/simulator.ts b/yarn-project/acir-simulator/src/client/simulator.ts index b21033fc99c..5c4948b56e3 100644 --- a/yarn-project/acir-simulator/src/client/simulator.ts +++ b/yarn-project/acir-simulator/src/client/simulator.ts @@ -1,7 +1,7 @@ -import { CallContext, CircuitsWasm, FunctionData, TxContext } from '@aztec/circuits.js'; +import { CallContext, CircuitsWasm, FunctionData, MAX_NOTE_FIELDS_LENGTH, TxContext } from '@aztec/circuits.js'; import { computeTxHash } from '@aztec/circuits.js/abis'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { ArrayType, FunctionType, encodeArguments } from '@aztec/foundation/abi'; +import { ArrayType, FunctionSelector, FunctionType, encodeArguments } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; @@ -15,7 +15,6 @@ import { PackedArgsCache } from '../common/packed_args_cache.js'; import { ClientTxExecutionContext } from './client_execution_context.js'; import { DBOracle, FunctionAbiWithDebugMetadata } from './db_oracle.js'; import { ExecutionResult } from './execution_result.js'; -import { computeNoteHashAndNullifierSelector, computeNoteHashAndNullifierSignature } from './function_selectors.js'; import { PrivateFunctionExecution } from './private_execution.js'; import { UnconstrainedFunctionExecution } from './unconstrained_execution.js'; @@ -177,12 +176,23 @@ export class AcirSimulator { storageSlot: Fr, notePreimage: Fr[], ) { - let abi: FunctionAbiWithDebugMetadata; - try { - abi = await this.db.getFunctionABI(contractAddress, computeNoteHashAndNullifierSelector); - } catch (e) { + let abi: FunctionAbiWithDebugMetadata | undefined = undefined; + + // Brute force + for (let i = 0; i < MAX_NOTE_FIELDS_LENGTH; i++) { + const signature = `compute_note_hash_and_nullifier(Field,Field,Field,[Field;${i}])`; + const selector = FunctionSelector.fromSignature(signature); + try { + abi = await this.db.getFunctionABI(contractAddress, selector); + if (abi !== undefined) break; + } catch (e) { + // ignore + } + } + + if (abi == undefined) { throw new Error( - `Mandatory implementation of "${computeNoteHashAndNullifierSignature}" missing in noir contract ${contractAddress.toString()}.`, + `Mandatory implementation of "compute_note_hash_and_nullifier" missing in noir contract ${contractAddress.toString()}.`, ); } diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts index cc679d8313a..f11c95d4c70 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts @@ -1,5 +1,5 @@ import { CallContext, FunctionData } from '@aztec/circuits.js'; -import { DecodedReturn, decodeReturnValues } from '@aztec/foundation/abi'; +import { DecodedReturn, FunctionSelector, decodeReturnValues } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -48,6 +48,11 @@ export class UnconstrainedFunctionExecution { const initialWitness = toACVMWitness(1, this.args); const { partialWitness } = await acvm(await AcirSimulator.getSolver(), acir, initialWitness, { + computeSelector: (...args) => { + const signature = oracleDebugCallToFormattedStr(args); + const returnValue = toACVMField(FunctionSelector.fromSignature(signature).toField()); + return Promise.resolve(returnValue); + }, getSecretKey: ([ownerX], [ownerY]) => this.context.getSecretKey(this.contractAddress, ownerX, ownerY), getPublicKey: async ([acvmAddress]) => { const address = frToAztecAddress(fromACVMField(acvmAddress)); diff --git a/yarn-project/acir-simulator/src/public/executor.ts b/yarn-project/acir-simulator/src/public/executor.ts index ee59f21719d..bdfd538e490 100644 --- a/yarn-project/acir-simulator/src/public/executor.ts +++ b/yarn-project/acir-simulator/src/public/executor.ts @@ -78,10 +78,13 @@ export class PublicExecutor { // We use this cache to hold the packed arguments. const packedArgs = await PackedArgsCache.create([]); const { partialWitness } = await acvm(await AcirSimulator.getSolver(), acir, initialWitness, { + computeSelector: (...args) => { + const signature = oracleDebugCallToFormattedStr(args); + return Promise.resolve(toACVMField(FunctionSelector.fromSignature(signature).toField())); + }, packArguments: async args => { return toACVMField(await packedArgs.pack(args.map(fromACVMField))); }, - debugLog: (...args) => { this.log(oracleDebugCallToFormattedStr(args)); return Promise.resolve(ZERO_ACVM_FIELD); diff --git a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts index 2eee79c81ee..27a303e5d9f 100644 --- a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts @@ -54,7 +54,7 @@ describe('e2e_lending_contract', () => { logger(`Tx sent with hash ${await tx.getTxHash()}`); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); - logger(`Debt asset deployed to ${receipt.contractAddress}`); + logger(`Stable coin asset deployed to ${receipt.contractAddress}`); stableCoin = await NativeTokenContract.at(receipt.contractAddress!, wallet); } diff --git a/yarn-project/foundation/src/abi/decoder.ts b/yarn-project/foundation/src/abi/decoder.ts index 778e109bf51..5ca889f9d63 100644 --- a/yarn-project/foundation/src/abi/decoder.ts +++ b/yarn-project/foundation/src/abi/decoder.ts @@ -1,4 +1,4 @@ -import { ABIType, FunctionAbi } from '@aztec/foundation/abi'; +import { ABIParameter, ABIType, FunctionAbi } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; /** @@ -86,3 +86,53 @@ class ReturnValuesDecoder { export function decodeReturnValues(abi: FunctionAbi, returnValues: Fr[]) { return new ReturnValuesDecoder(abi, returnValues.slice()).decode(); } + +/** + * Decodes the signature of a function from the name and parameters. + */ +export class FunctionSignatureDecoder { + constructor(private name: string, private parameters: ABIParameter[]) {} + + /** + * Decodes a single function parameter for the function signature. + * @param param - The parameter to decode. + * @returns A string representing the parameter type. + */ + private decodeParameter(param: ABIType): string { + switch (param.kind) { + case 'field': + return 'Field'; + case 'integer': + if (param.sign === 'signed') { + throw new Error('Unsupported type: signed integer'); + } + return `u${param.width}`; + case 'boolean': + return 'bool'; + case 'array': + return `[${this.decodeParameter(param.type)};${param.length}]`; + case 'struct': + return `(${param.fields.map(field => `${this.decodeParameter(field.type)}`).join(',')})`; + default: + throw new Error(`Unsupported type: ${param.kind}`); + } + } + + /** + * Decodes all the parameters and build the function signature + * @returns The function signature. + */ + public decode(): string { + return `${this.name}(${this.parameters.map(param => this.decodeParameter(param.type)).join(',')})`; + } +} + +/** + * Decodes a function signature from the name and parameters. + * @param name - The name of the function- + * @param parameters - The parameters of the function. + * @returns - The function signature. + */ +export function decodeFunctionSignature(name: string, parameters: ABIParameter[]) { + return new FunctionSignatureDecoder(name, parameters).decode(); +} diff --git a/yarn-project/foundation/src/abi/function_selector.ts b/yarn-project/foundation/src/abi/function_selector.ts index dac9909eaaa..236acfedd79 100644 --- a/yarn-project/foundation/src/abi/function_selector.ts +++ b/yarn-project/foundation/src/abi/function_selector.ts @@ -1,4 +1,4 @@ -import { ABIParameter } from '@aztec/foundation/abi'; +import { ABIParameter, decodeFunctionSignature } from '@aztec/foundation/abi'; import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer'; import { keccak } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; @@ -97,8 +97,11 @@ export class FunctionSelector { * @returns A Buffer containing the 4-byte function selector. */ static fromNameAndParameters(name: string, parameters: ABIParameter[]) { - const signature = name === 'constructor' ? name : `${name}(${parameters.map(p => p.type.kind).join(',')})`; - return FunctionSelector.fromSignature(signature); + const signature = decodeFunctionSignature(name, parameters); + const selector = FunctionSelector.fromSignature(signature); + // If using the debug logger here it kill the typing in the `server_world_state_synchroniser` and jest tests. + // console.log(`Function selector for ${signature} is ${selector}`); + return selector; } /** diff --git a/yarn-project/noir-contracts/src/contracts/child_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/child_contract/src/main.nr index 419bb4b14ef..879ccd537f8 100644 --- a/yarn-project/noir-contracts/src/contracts/child_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/child_contract/src/main.nr @@ -5,7 +5,10 @@ contract Child { use crate::storage::Storage; use dep::aztec::{ abi::CallContext, - oracle::logs::emit_unencrypted_log, + oracle::{ + logs::emit_unencrypted_log, + compute_selector::compute_selector, + } }; use dep::std::option::Option; @@ -34,7 +37,7 @@ contract Child { input + context.chain_id() + context.version() } - // Returns base_value + 42. + // Returns base_value + chain_id + version + block_number + timestamp #[aztec(public)] fn pubGetValue(base_value: Field) -> Field { let returnValue = base_value + context.chain_id() + context.version() + context.block_number() + context.timestamp(); @@ -77,7 +80,7 @@ contract Child { #[aztec(public)] fn setValueTwiceWithNestedFirst() { - let pubSetValueSelector = 0x5b0f91b0; + let pubSetValueSelector = compute_selector("pubSetValue(Field)"); let _ret = context.call_public_function(context.this_address(), pubSetValueSelector, [10]); let storage = Storage::init(Option::none(), Option::some(&mut context)); @@ -91,7 +94,7 @@ contract Child { storage.current_value.write(20); let _hash = emit_unencrypted_log(20); - let pubSetValueSelector = 0x5b0f91b0; + let pubSetValueSelector = compute_selector("pubSetValue(Field)"); let _ret = context.call_public_function(context.this_address(), pubSetValueSelector, [10]); } } diff --git a/yarn-project/noir-contracts/src/contracts/lending_contract/src/interfaces.nr b/yarn-project/noir-contracts/src/contracts/lending_contract/src/interfaces.nr index 8af2b6266d5..d6b457652a3 100644 --- a/yarn-project/noir-contracts/src/contracts/lending_contract/src/interfaces.nr +++ b/yarn-project/noir-contracts/src/contracts/lending_contract/src/interfaces.nr @@ -7,6 +7,7 @@ use dep::aztec::context::{ use crate::storage::Asset; use dep::aztec::constants_gen::RETURN_VALUES_LENGTH; +use dep::aztec::oracle::compute_selector::compute_selector; struct PriceFeed { address: Field, @@ -20,7 +21,7 @@ impl PriceFeed { fn get_price(self: Self, context: PublicContext) -> u120 { let return_values = context.call_public_function( self.address, - 3359284436, + compute_selector("get_price(Field)"), [0] ); @@ -40,15 +41,15 @@ impl Token { fn transfer_pub(self: Self, context: PublicContext, to: Field, amount: Field) { let _transfer_return_values = context.call_public_function( self.address, - 1012824788, + compute_selector("transfer_pub(Field,Field)"), [to, amount] ); } fn transfer_from_pub(self: Self, context: PublicContext, from: Field, to: Field, amount: Field) { let _transfer_return_values = context.call_public_function( - self.address, - 1602017294, + self.address, + compute_selector("transfer_from_pub(Field,Field,Field)"), [from, to, amount] ); } @@ -56,7 +57,7 @@ impl Token { fn owner_mint_pub(self: Self, context: PublicContext, to: Field, amount: Field) { let _transfer_return_values = context.call_public_function( self.address, - 1071038680, + compute_selector("owner_mint_pub(Field,Field)"), [to, amount] ); } @@ -65,7 +66,7 @@ impl Token { fn unshield(self: Self, context: &mut PrivateContext, from: Field, to: Field, amount: Field) -> [Field; RETURN_VALUES_LENGTH] { context.call_private_function( self.address, - 2423803924, + compute_selector("unshieldTokens(Field,Field,Field)"), [from, to, amount] ) } @@ -82,8 +83,8 @@ impl Lending { fn update_accumulator(self: Self, context: PublicContext) -> Asset { let return_values = context.call_public_function_no_args( - self.address, - 0x1873b536 + self.address, + compute_selector("update_accumulator()"), ); Asset { diff --git a/yarn-project/noir-contracts/src/contracts/lending_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/lending_contract/src/main.nr index 3a36c320dc7..2f33b92a719 100644 --- a/yarn-project/noir-contracts/src/contracts/lending_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/lending_contract/src/main.nr @@ -18,6 +18,7 @@ contract Lending { use crate::interest_math::compute_multiplier; use crate::helpers::{covered_by_collateral, DebtReturn, debt_updates, debt_value, compute_identifier}; use crate::interfaces::{Token, Lending, PriceFeed}; + use dep::aztec::oracle::compute_selector::compute_selector; struct Position { collateral: Field, @@ -59,7 +60,6 @@ contract Lending { } // Create a position. - // keccak256("update_accumulator()") >> 224 -> 0x1873b536 #[aztec(public)] fn update_accumulator() -> Asset { let storage = Storage::init(Option::none(), Option::some(&mut context)); @@ -98,7 +98,8 @@ contract Lending { let on_behalf_of = compute_identifier(secret, on_behalf_of, context.msg_sender()); let _res = Token::at(collateral_asset).unshield(&mut context, asset_owner, context.this_address(), amount); // _deposit(on_behalf_of, amount, collateral_asset) - let _callStackItem2 = context.call_public_function(context.this_address(), 0x08506e50,[on_behalf_of, amount, collateral_asset]); + let selector = compute_selector("_deposit(Field,Field,Field)"); + let _callStackItem2 = context.call_public_function(context.this_address(), selector, [on_behalf_of, amount, collateral_asset]); } #[aztec(public)] @@ -108,13 +109,13 @@ contract Lending { collateral_asset: Field, ) -> Field { Token::at(collateral_asset).transfer_from_pub(context, context.msg_sender(), context.this_address(), amount); - let return_values = context.call_public_function(context.this_address(), 0x08506e50, [owner, amount, collateral_asset]); + let selector = compute_selector("_deposit(Field,Field,Field)"); + let return_values = context.call_public_function(context.this_address(), selector, [owner, amount, collateral_asset]); return_values[0] } #[aztec(public)] - // keccak256("_deposit(field,field,field)") >> 224 -> 0x08506e50 internal fn _deposit( owner: Field, amount: Field, @@ -140,7 +141,8 @@ contract Lending { amount: Field ) { let on_behalf_of = compute_identifier(secret, 0, context.msg_sender()); - let _callStackItem = context.call_public_function(context.this_address(), 0x5af6f634, [on_behalf_of, to, amount]); + let selector = compute_selector("_withdraw(Field,Field,Field)"); + let _callStackItem = context.call_public_function(context.this_address(), selector, [on_behalf_of, to, amount]); } #[aztec(public)] @@ -148,13 +150,12 @@ contract Lending { to: Field, amount: Field, ) -> Field { - // _withdraw(msg.sender, to, amount); - let return_values = context.call_public_function(context.this_address(), 0x5af6f634, [context.msg_sender(), to, amount]); + let selector = compute_selector("_withdraw(Field,Field,Field)"); + let return_values = context.call_public_function(context.this_address(), selector, [context.msg_sender(), to, amount]); return_values[0] } - // keccak256("_withdraw(field,field,field)") >> 224 -> 0x5af6f634 #[aztec(public)] internal fn _withdraw( owner: Field, @@ -195,8 +196,8 @@ contract Lending { amount: Field ) { let on_behalf_of = compute_identifier(secret, 0, context.msg_sender()); - // _borrow(msg.sender, to, amount) - let _callStackItem = context.call_public_function(context.this_address(), 0xceffa31a, [on_behalf_of, to, amount]); + let selector = compute_selector("_borrow(Field,Field,Field)"); + let _callStackItem = context.call_public_function(context.this_address(), selector, [on_behalf_of, to, amount]); } #[aztec(public)] @@ -204,13 +205,12 @@ contract Lending { to: Field, amount: Field ) -> Field { - // _borrow(msg.sender, to, amount) - let return_values = context.call_public_function(context.this_address(), 0xceffa31a, [context.msg_sender(), to, amount]); + let selector = compute_selector("_borrow(Field,Field,Field)"); + let return_values = context.call_public_function(context.this_address(), selector, [context.msg_sender(), to, amount]); return_values[0] } - // keccak256("_borrow(field,field,field)") >> 224 -> 0xceffa31a #[aztec(public)] internal fn _borrow( owner: Field, @@ -250,7 +250,8 @@ contract Lending { ) { let on_behalf_of = compute_identifier(secret, on_behalf_of, context.msg_sender()); let _res = Token::at(stable_coin).unshield(&mut context, asset_owner, context.this_address(), amount); - let _callStackItem = context.call_public_function(context.this_address(), 0xfa94ab54, [on_behalf_of, amount, stable_coin]); + let selector = compute_selector("_repay(Field,Field,Field)"); + let _callStackItem = context.call_public_function(context.this_address(), selector, [on_behalf_of, amount, stable_coin]); } #[aztec(public)] @@ -261,12 +262,12 @@ contract Lending { ) -> Field { // Should probably just burn the tokens actually :thinking: Token::at(stable_coin).transfer_from_pub(context, context.msg_sender(), context.this_address(), amount); - let return_values = context.call_public_function(context.this_address(), 0xfa94ab54, [owner, amount, stable_coin]); + let selector = compute_selector("_repay(Field,Field,Field)"); + let return_values = context.call_public_function(context.this_address(), selector, [owner, amount, stable_coin]); return_values[0] } - // keccak256("_repay(field,field,field)") >> 224 -> 0xfa94ab54 #[aztec(public)] internal fn _repay( owner: Field, diff --git a/yarn-project/noir-contracts/src/contracts/native_token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/native_token_contract/src/main.nr index 0155a592d3e..da46929f836 100644 --- a/yarn-project/noir-contracts/src/contracts/native_token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/native_token_contract/src/main.nr @@ -33,6 +33,7 @@ contract NativeToken { }; use dep::aztec::public_call_stack_item::PublicCallStackItem; + use dep::aztec::oracle::compute_selector::compute_selector; #[aztec(private)] fn constructor( @@ -45,7 +46,6 @@ contract NativeToken { increment(balance, initial_supply, owner); } - // uint256(keccak256("owner_mint_pub(field,field)")) >> 224 -> 1071038680 #[aztec(public)] fn owner_mint_pub( to: Field, @@ -59,7 +59,6 @@ contract NativeToken { 1 } - // uint256(keccak256("owner_mint_priv(field,field)")) >> 224 -> 3157518188 #[aztec(public)] fn owner_mint_priv( amount: Field, @@ -79,7 +78,6 @@ contract NativeToken { // Mint Private Function // This mint function differs to the typical token mint function as it only allows minting // upon consuming valid messages from a token portal contract - // uint256(keccak256("mint(field,field,field,field,field)")) >> 224 -> 2341211258 #[aztec(private)] fn mint( amount: Field, @@ -103,7 +101,6 @@ contract NativeToken { // Withdraws using user's private balance. // @dev Destroys 2 of user's notes and sends a message to the L1 portal contract. That message can then be consumed // by calling the `withdraw` function on the L1 portal contract (assuming the args are set correctly). - // uint256(keccak256("withdraw(field,field,field,field)")) >> 224 -> 3193431016 #[aztec(private)] fn withdraw( amount: Field, @@ -123,7 +120,6 @@ contract NativeToken { // Mint Public Function // This mint function differs to the typical token mint function as it only allows minting // upon consuming valid messages from a token portal contract - // uint256(keccak256("mintPublic(field,field,field,field,field)")) >> 224 -> 1598652179 #[aztec(public)] fn mintPublic( amount: Field, @@ -151,7 +147,6 @@ contract NativeToken { } // Withdraws using user's public balance. - // uint256(keccak256("withdrawPublic(field,field,field)")) >> 224 -> 2996031894 #[aztec(public)] fn withdrawPublic( amount: Field, @@ -166,12 +161,7 @@ contract NativeToken { let current_sender_balance: Field = sender_balance.read(); - if (current_sender_balance as u120) > (amount as u120) { - // User has sufficient balance so we decrement it by `amount` - let _void1 = sender_balance.write(current_sender_balance - amount); - } - // TODO: Revert if there is not enough balance - + assert(current_sender_balance as u120 >= amount as u120); let content = get_withdraw_content_hash(amount, recipient, callerOnL1); // Emit the l2 to l1 message @@ -187,7 +177,6 @@ contract NativeToken { storage.public_allowances.at(context.msg_sender()).at(spender).write(allowance); } - // uint256(keccak256("transfer_pub(field,field)")) >> 224 -> 1012824788 #[aztec(public)] fn transfer_pub( to: Field, @@ -209,7 +198,6 @@ contract NativeToken { to_balance.write(current_to_balance + amount); } - // uint256(keccak256("transfer_from_pub(field,field,field)")) >> 224 -> 1602017294 #[aztec(public)] fn transfer_from_pub( from: Field, @@ -239,7 +227,6 @@ contract NativeToken { // Transfers `amount` of tokens from `sender`'s private balance to a `recipient`. // Note: Copied from PrivateToken - // uint256(keccak256("transfer(field,field,field)")) >> 224 -> 3704931096 #[aztec(private)] fn transfer( from: Field, @@ -257,7 +244,6 @@ contract NativeToken { } // Shield creates a way for a user to move tokens from the public context into the private context. - // uint256(keccak256("shield(field,field)")) >> 224 -> 845411215 #[aztec(public)] fn shield( amount: Field, @@ -286,7 +272,6 @@ contract NativeToken { // The shield function takes a public balance, and creates a commitment containing the amount of tokens // in the private context. - // uint256(keccak256("redeemShield(field,field,field)")) >> 224 -> 2260077221 #[aztec(private)] fn redeemShield( amount: Field, @@ -306,7 +291,6 @@ contract NativeToken { increment(balance, amount, owner); } - // uint256(keccak256("unshieldTokens(field,field,field)")) >> 224 -> 2423803924 #[aztec(private)] fn unshieldTokens( from: Field, @@ -322,10 +306,8 @@ contract NativeToken { // enqueue a public function to perform the public state update. let thisAddress = context.this_address(); - // addUnshieldedBalance selector (in decimal) - // recompute by: `cast keccak addUnshieldedBalance(field,field)` -> convert to decimal - let pubEntryPointSelector = 753269941; - let _callStackItem1 = context.call_public_function(thisAddress, pubEntryPointSelector, [amount, to]); + let addUnshieldedBalance = compute_selector("addUnshieldedBalance(Field,Field)"); + let _callStackItem1 = context.call_public_function(thisAddress, addUnshieldedBalance, [amount, to]); } #[aztec(public)] @@ -355,7 +337,7 @@ contract NativeToken { // Note 2: Having it in all the contracts gives us the ability to compute the note hash and nullifier differently for different kind of notes. unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, preimage: [Field; VALUE_NOTE_LEN]) -> [Field; 4] { let note_header = NoteHeader { contract_address, nonce, storage_slot }; - if (storage_slot == 2) { + if (storage_slot == 3) { note_utils::compute_note_hash_and_nullifier(TransparentNoteMethods, note_header, preimage) } else { note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, preimage) diff --git a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr index f9878a152d4..53d7e84e8e4 100644 --- a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr @@ -43,6 +43,7 @@ contract NonNativeToken { }; use dep::aztec::public_call_stack_item::PublicCallStackItem; + use dep::aztec::oracle::compute_selector::compute_selector; #[aztec(private)] fn constructor( @@ -236,10 +237,8 @@ contract NonNativeToken { // enqueue a public function to perform the public state update. let thisAddress = context.this_address(); - // addUnshieldedBalance selector (in decimal) - // recompute by: `cast keccak addUnshieldedBalance(field,field)` -> convert to decimal - let pubEntryPointSelector = 753269941; - let _callStackItem1 = context.call_public_function(thisAddress, pubEntryPointSelector, [amount, recipient]); + let addUnshieldedBalance = compute_selector("addUnshieldedBalance(Field,Field)"); + let _callStackItem1 = context.call_public_function(thisAddress, addUnshieldedBalance, [amount, recipient]); } #[aztec(public)] diff --git a/yarn-project/noir-contracts/src/contracts/parent_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/parent_contract/src/main.nr index 99458ff1014..d1d0c377b4a 100644 --- a/yarn-project/noir-contracts/src/contracts/parent_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/parent_contract/src/main.nr @@ -1,5 +1,6 @@ // A contract used along with `Child` contract to test nested calls. contract Parent { + use dep::aztec::oracle::compute_selector::compute_selector; #[aztec(private)] fn constructor() {} @@ -60,7 +61,7 @@ contract Parent { targetContract: Field, targetSelector: Field, ) { - let enqueueCallToChildSelector = 0x94015a34; + let enqueueCallToChildSelector = compute_selector("enqueueCallToChild(Field,Field,Field)"); let _ret = context.call_private_function(context.this_address(), enqueueCallToChildSelector, [targetContract, targetSelector, 10]); context.call_public_function(targetContract, targetSelector, [20]); } @@ -74,7 +75,7 @@ contract Parent { targetSelector: Field, ) { context.call_public_function(targetContract, targetSelector, [20]); - let enqueueCallToChildSelector = 0x94015a34; + let enqueueCallToChildSelector = compute_selector("enqueueCallToChild(Field,Field,Field)"); let _ret = context.call_private_function(context.this_address(), enqueueCallToChildSelector, [targetContract, targetSelector, 10]); } @@ -98,7 +99,7 @@ contract Parent { targetSelector: Field, targetValue: Field, ) { - let pubEntryPointSelector = 3221316504; + let pubEntryPointSelector = compute_selector("pubEntryPoint(Field,Field,Field)"); let thisAddress = context.this_address(); let _void = context.call_public_function(thisAddress, pubEntryPointSelector, [targetContract, targetSelector, targetValue]); } @@ -110,7 +111,7 @@ contract Parent { targetSelector: Field, targetValue: Field, ) { - let pubEntryPointSelector = 3221316504; + let pubEntryPointSelector = compute_selector("pubEntryPoint(Field,Field,Field)"); let thisAddress = context.this_address(); context.call_public_function(thisAddress, pubEntryPointSelector, [targetContract, targetSelector, targetValue]); diff --git a/yarn-project/noir-contracts/src/contracts/private_token_airdrop_contract/src/interface.nr b/yarn-project/noir-contracts/src/contracts/private_token_airdrop_contract/src/interface.nr index 975acddead8..6c8a95fb33a 100644 --- a/yarn-project/noir-contracts/src/contracts/private_token_airdrop_contract/src/interface.nr +++ b/yarn-project/noir-contracts/src/contracts/private_token_airdrop_contract/src/interface.nr @@ -36,7 +36,7 @@ impl PrivateTokenAirdropPrivateContextInterface { serialised_args[6] = recipients[2]; serialised_args[7] = spend_note_offset as Field; - context.call_private_function(self.address, 0x88bd156f, serialised_args) + context.call_private_function(self.address, 0xbf748730, serialised_args) } @@ -50,7 +50,7 @@ impl PrivateTokenAirdropPrivateContextInterface { serialised_args[0] = amount; serialised_args[1] = owner; - context.call_private_function(self.address, 0x7ecb218a, serialised_args) + context.call_private_function(self.address, 0xa4fa3a6f, serialised_args) } @@ -66,7 +66,7 @@ impl PrivateTokenAirdropPrivateContextInterface { serialised_args[1] = secret; serialised_args[2] = owner; - context.call_private_function(self.address, 0x9f7bacc8, serialised_args) + context.call_private_function(self.address, 0xd68b55c1, serialised_args) } @@ -82,7 +82,7 @@ impl PrivateTokenAirdropPrivateContextInterface { serialised_args[2] = secrets[0]; serialised_args[3] = secrets[1]; - context.call_private_function(self.address, 0xcaf1f505, serialised_args) + context.call_private_function(self.address, 0x720f5cc9, serialised_args) } @@ -96,7 +96,7 @@ impl PrivateTokenAirdropPrivateContextInterface { serialised_args[0] = amount; serialised_args[1] = owner; - context.call_private_function(self.address, 0x1dc9c3c0, serialised_args) + context.call_private_function(self.address, 0x1535439c, serialised_args) } @@ -110,7 +110,7 @@ impl PrivateTokenAirdropPrivateContextInterface { serialised_args[0] = amount; serialised_args[1] = recipient; - context.call_private_function(self.address, 0x61dd7032, serialised_args) + context.call_private_function(self.address, 0xc0888d22, serialised_args) } } diff --git a/yarn-project/noir-contracts/src/contracts/private_token_contract/src/interface.nr b/yarn-project/noir-contracts/src/contracts/private_token_contract/src/interface.nr index c308d2e8886..1eee266adcb 100644 --- a/yarn-project/noir-contracts/src/contracts/private_token_contract/src/interface.nr +++ b/yarn-project/noir-contracts/src/contracts/private_token_contract/src/interface.nr @@ -28,7 +28,7 @@ impl PrivateTokenPrivateContextInterface { serialised_args[0] = amount; serialised_args[1] = owner; - context.call_private_function(self.address, 0x1dc9c3c0, serialised_args) + context.call_private_function(self.address, 0x1535439c, serialised_args) } @@ -42,7 +42,7 @@ impl PrivateTokenPrivateContextInterface { serialised_args[0] = amount; serialised_args[1] = recipient; - context.call_private_function(self.address, 0x61dd7032, serialised_args) + context.call_private_function(self.address, 0xc0888d22, serialised_args) } } diff --git a/yarn-project/noir-contracts/src/contracts/test_contract/src/interface.nr b/yarn-project/noir-contracts/src/contracts/test_contract/src/interface.nr index 7ccee2964e7..6d03ba23bd0 100644 --- a/yarn-project/noir-contracts/src/contracts/test_contract/src/interface.nr +++ b/yarn-project/noir-contracts/src/contracts/test_contract/src/interface.nr @@ -49,7 +49,7 @@ impl TestPrivateContextInterface { serialised_args[0] = amount; serialised_args[1] = secretHash; - context.call_public_function(self.address, 0x1c031d17, serialised_args) + context.call_public_function(self.address, 0xbac98727, serialised_args) } @@ -63,7 +63,7 @@ impl TestPrivateContextInterface { serialised_args[0] = amount; serialised_args[1] = secretHash; - context.call_public_function(self.address, 0x0217ef40, serialised_args) + context.call_public_function(self.address, 0x42040a24, serialised_args) } @@ -75,7 +75,7 @@ impl TestPrivateContextInterface { let mut serialised_args = [0; 1]; serialised_args[0] = aztec_address; - context.call_private_function(self.address, 0xe5df1726, serialised_args) + context.call_private_function(self.address, 0xaf15a45f, serialised_args) } @@ -87,7 +87,7 @@ impl TestPrivateContextInterface { let mut serialised_args = [0; 1]; serialised_args[0] = address; - context.call_private_function(self.address, 0x553aaad4, serialised_args) + context.call_private_function(self.address, 0x88f0753b, serialised_args) } @@ -119,7 +119,7 @@ impl TestPrivateContextInterface { let mut serialised_args = [0; 1]; serialised_args[0] = time; - context.call_public_function(self.address, 0x57587e4d, serialised_args) + context.call_public_function(self.address, 0xfff6026c, serialised_args) } @@ -152,7 +152,7 @@ impl TestPrivateContextInterface { serialised_args[15] = aDeepStruct.manyNotes[2].amount; serialised_args[16] = aDeepStruct.manyNotes[2].secretHash; - context.call_private_function(self.address, 0x7c97ca29, serialised_args) + context.call_private_function(self.address, 0x81d7c118, serialised_args) } } @@ -182,7 +182,7 @@ impl TestPublicContextInterface { serialised_args[0] = amount; serialised_args[1] = secretHash; - context.call_public_function(self.address, 0x1c031d17, serialised_args) + context.call_public_function(self.address, 0xbac98727, serialised_args) } @@ -196,7 +196,7 @@ impl TestPublicContextInterface { serialised_args[0] = amount; serialised_args[1] = secretHash; - context.call_public_function(self.address, 0x0217ef40, serialised_args) + context.call_public_function(self.address, 0x42040a24, serialised_args) } @@ -208,7 +208,7 @@ impl TestPublicContextInterface { let mut serialised_args = [0; 1]; serialised_args[0] = time; - context.call_public_function(self.address, 0x57587e4d, serialised_args) + context.call_public_function(self.address, 0xfff6026c, serialised_args) } } diff --git a/yarn-project/noir-libs/noir-aztec/src/oracle.nr b/yarn-project/noir-libs/noir-aztec/src/oracle.nr index 4133c00fc99..838821db45f 100644 --- a/yarn-project/noir-libs/noir-aztec/src/oracle.nr +++ b/yarn-project/noir-libs/noir-aztec/src/oracle.nr @@ -11,4 +11,5 @@ mod enqueue_public_function_call; mod public_call; mod notes; mod storage; -mod logs; \ No newline at end of file +mod logs; +mod compute_selector; \ No newline at end of file diff --git a/yarn-project/noir-libs/noir-aztec/src/oracle/compute_selector.nr b/yarn-project/noir-libs/noir-aztec/src/oracle/compute_selector.nr new file mode 100644 index 00000000000..89a130fecd6 --- /dev/null +++ b/yarn-project/noir-libs/noir-aztec/src/oracle/compute_selector.nr @@ -0,0 +1,6 @@ +#[oracle(computeSelector)] +fn compute_selector_oracle(_selector: T, _size: Field) -> Field {} + +unconstrained fn compute_selector(signature: T) -> Field { + compute_selector_oracle(signature, 0) +} \ No newline at end of file