Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,16 @@ jobs:
aztec_manifest_key: end-to-end
<<: *defaults_e2e_test

e2e-account-init-fees:
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_account_init_fees.test.ts ENABLE_GAS=1
aztec_manifest_key: end-to-end
<<: *defaults_e2e_test

e2e-dapp-subscription:
steps:
- *checkout
Expand Down Expand Up @@ -1480,6 +1490,7 @@ workflows:
- e2e-card-game: *e2e_test
- e2e-avm-simulator: *e2e_test
- e2e-fees: *e2e_test
- e2e-account-init-fees: *e2e_test
- e2e-dapp-subscription: *e2e_test
- pxe: *e2e_test
- cli-docs-sandbox: *e2e_test
Expand Down Expand Up @@ -1546,6 +1557,7 @@ workflows:
- e2e-card-game
- e2e-avm-simulator
- e2e-fees
- e2e-account-init-fees
- e2e-dapp-subscription
- pxe
- boxes-vanilla
Expand Down
10 changes: 10 additions & 0 deletions noir-projects/aztec-nr/authwit/src/account.nr
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ impl AccountActions {
}
// docs:end:entrypoint

pub fn pay_init_fee(self, fee_payload: FeePayload) {
let valid_fn = self.is_valid_impl;
let mut private_context = self.context.private.unwrap();

let fee_hash = fee_payload.hash();
assert(valid_fn(private_context, fee_hash));
fee_payload.execute_calls(private_context);
private_context.capture_min_revertible_side_effect_counter();
}

// docs:start:spend_private_authwit
pub fn spend_private_authwit(self, inner_hash: Field) -> Field {
let context = self.context.private.unwrap();
Expand Down
15 changes: 15 additions & 0 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,19 @@ impl PrivateContext {
assert_eq(item.public_inputs.start_side_effect_counter, self.side_effect_counter);
self.side_effect_counter = item.public_inputs.end_side_effect_counter + 1;

// TODO (fees) figure out why this crashes the prover and enable it
// we need this in order to pay fees inside child call contexts
// assert(
// (item.public_inputs.min_revertible_side_effect_counter == 0 as u32)
// | (item.public_inputs.min_revertible_side_effect_counter
// > self.min_revertible_side_effect_counter)
// );

// if item.public_inputs.min_revertible_side_effect_counter
// > self.min_revertible_side_effect_counter {
// self.min_revertible_side_effect_counter = item.public_inputs.min_revertible_side_effect_counter;
// }

assert(contract_address.eq(item.contract_address));
assert(function_selector.eq(item.function_data.selector));

Expand All @@ -370,6 +383,8 @@ impl PrivateContext {
);
}

// crate::oracle::debug_log::debug_log_array_with_prefix("Private call stack item", item.serialize());

self.private_call_stack_hashes.push(item.hash());

item.public_inputs.return_values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ contract EcdsaAccount {
}

#[aztec(private)]
#[aztec(noinitcheck)]
fn pay_init_fee(fee_payload: pub FeePayload) {
let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.pay_init_fee(fee_payload);
}
Comment on lines +44 to +47
Copy link
Contributor

Choose a reason for hiding this comment

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

The idea is to delete this method once we can figure out the hash mismatch, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, here's the PR #5623


#[aztec(private)]
#[aztec(noinitcheck)]
fn spend_private_authwit(inner_hash: Field) -> Field {
let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.spend_private_authwit(inner_hash)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ contract SchnorrAccount {

// Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts file
#[aztec(private)]
#[aztec(noinitcheck)]
fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) {
let actions = AccountActions::private(
&mut context,
Expand All @@ -48,6 +49,18 @@ contract SchnorrAccount {
}

#[aztec(private)]
#[aztec(noinitcheck)]
fn pay_init_fee(fee_payload: pub FeePayload) {
let actions = AccountActions::private(
&mut context,
storage.approved_actions.storage_slot,
is_valid_impl
);
actions.pay_init_fee(fee_payload);
}

#[aztec(private)]
#[aztec(noinitcheck)]
fn spend_private_authwit(inner_hash: Field) -> Field {
let actions = AccountActions::private(
&mut context,
Expand All @@ -58,6 +71,7 @@ contract SchnorrAccount {
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn spend_public_authwit(inner_hash: Field) -> Field {
let actions = AccountActions::public(
&mut context,
Expand All @@ -75,6 +89,7 @@ contract SchnorrAccount {

#[aztec(public)]
#[aztec(internal)]
#[aztec(noinitcheck)]
fn approve_public_authwit(outer_hash: Field) {
let actions = AccountActions::public(
&mut context,
Expand Down Expand Up @@ -118,9 +133,9 @@ contract SchnorrAccount {
* @param block_number The block number to check the nullifier against
* @param check_private Whether to check the validity of the authwitness in private state or not
* @param message_hash The message hash of the message to check the validity
* @return An array of two booleans, the first is the validity of the authwitness in the private state,
* @return An array of two booleans, the first is the validity of the authwitness in the private state,
* the second is the validity of the authwitness in the public state
* Both values will be `false` if the nullifier is spent
* Both values will be `false` if the nullifier is spent
*/
unconstrained fn lookup_validity(
myself: AztecAddress,
Expand Down Expand Up @@ -148,7 +163,7 @@ contract SchnorrAccount {
let valid_in_public = storage.approved_actions.at(message_hash).read();

// Compute the nullifier and check if it is spent
// This will BLINDLY TRUST the oracle, but the oracle is us, and
// This will BLINDLY TRUST the oracle, but the oracle is us, and
// it is not as part of execution of the contract, so we are good.
let siloed_nullifier = compute_siloed_nullifier(myself, message_hash);
let lower_wit = get_low_nullifier_membership_witness(block_number, siloed_nullifier);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ contract SchnorrHardcodedAccount {
actions.entrypoint(app_payload, fee_payload);
}

#[aztec(private)]
fn pay_init_fee(fee_payload: pub FeePayload) {
let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.pay_init_fee(fee_payload);
}

#[aztec(private)]
fn spend_private_authwit(inner_hash: Field) -> Field {
let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ contract SchnorrSingleKeyAccount {
actions.entrypoint(app_payload, fee_payload);
}

#[aztec(private)]
fn pay_init_fee(fee_payload: pub FeePayload) {
let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.pay_init_fee(fee_payload);
}

#[aztec(private)]
fn spend_private_authwit(inner_hash: Field) -> Field {
let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
Expand Down
8 changes: 4 additions & 4 deletions yarn-project/accounts/src/defaults/account_interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type AccountInterface, type AuthWitnessProvider } from '@aztec/aztec.js/account';
import { type EntrypointInterface, type FeeOptions } from '@aztec/aztec.js/entrypoint';
import { type AuthWitness, type FunctionCall, type TxExecutionRequest } from '@aztec/circuit-types';
import { type EntrypointInterface, type ExecutionRequestInit } from '@aztec/aztec.js/entrypoint';
import { type AuthWitness, type TxExecutionRequest } from '@aztec/circuit-types';
import { type AztecAddress, type CompleteAddress, Fr } from '@aztec/circuits.js';
import { DefaultAccountEntrypoint } from '@aztec/entrypoints/account';
import { type NodeInfo } from '@aztec/types/interfaces';
Expand Down Expand Up @@ -29,8 +29,8 @@ export class DefaultAccountInterface implements AccountInterface {
this.version = new Fr(nodeInfo.protocolVersion);
}

createTxExecutionRequest(executions: FunctionCall[], fee?: FeeOptions): Promise<TxExecutionRequest> {
return this.entrypoint.createTxExecutionRequest(executions, fee);
createTxExecutionRequest(execution: ExecutionRequestInit): Promise<TxExecutionRequest> {
return this.entrypoint.createTxExecutionRequest(execution);
}

createAuthWit(messageHash: Fr): Promise<AuthWitness> {
Expand Down
8 changes: 7 additions & 1 deletion yarn-project/aztec.js/src/account/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { type CompleteAddress } from '@aztec/circuit-types';
import { type ContractArtifact } from '@aztec/foundation/abi';
import { type NodeInfo } from '@aztec/types/interfaces';

import { type AccountInterface } from './interface.js';
import { type AccountInterface, type AuthWitnessProvider } from './interface.js';

// docs:start:account-contract-interface
/**
Expand All @@ -29,5 +29,11 @@ export interface AccountContract {
* @returns An account interface instance for creating tx requests and authorizing actions.
*/
getInterface(address: CompleteAddress, nodeInfo: NodeInfo): AccountInterface;

/**
* Returns the auth witness provider for the given address.
* @param address - Address for which to create auth witnesses.
*/
getAuthWitnessProvider(address: CompleteAddress): AuthWitnessProvider;
}
// docs:end:account-contract-interface
71 changes: 71 additions & 0 deletions yarn-project/aztec.js/src/account_manager/deploy_account_method.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { type PublicKey } from '@aztec/circuit-types';
import { FunctionData } from '@aztec/circuits.js';
import {
type ContractArtifact,
type FunctionArtifact,
encodeArguments,
getFunctionArtifact,
} from '@aztec/foundation/abi';

import { type AuthWitnessProvider } from '../account/interface.js';
import { type Wallet } from '../account/wallet.js';
import { type ExecutionRequestInit } from '../api/entrypoint.js';
import { Contract } from '../contract/contract.js';
import { DeployMethod, type DeployOptions } from '../contract/deploy_method.js';
import { EntrypointPayload } from '../entrypoint/payload.js';

/**
* Contract interaction for deploying an account contract. Handles fee preparation and contract initialization.
*/
export class DeployAccountMethod extends DeployMethod {
#authWitnessProvider: AuthWitnessProvider;
#feePaymentArtifact: FunctionArtifact | undefined;

constructor(
authWitnessProvider: AuthWitnessProvider,
publicKey: PublicKey,
wallet: Wallet,
artifact: ContractArtifact,
args: any[] = [],
constructorNameOrArtifact?: string | FunctionArtifact,
feePaymentNameOrArtifact?: string | FunctionArtifact,
) {
super(
publicKey,
wallet,
artifact,
(address, wallet) => Contract.at(address, artifact, wallet),
args,
constructorNameOrArtifact,
);

this.#authWitnessProvider = authWitnessProvider;
this.#feePaymentArtifact =
typeof feePaymentNameOrArtifact === 'string'
? getFunctionArtifact(artifact, feePaymentNameOrArtifact)
: feePaymentNameOrArtifact;
}

protected async getInitializeFunctionCalls(options: DeployOptions): Promise<ExecutionRequestInit> {
const exec = await super.getInitializeFunctionCalls(options);

if (options.fee && this.#feePaymentArtifact) {
const { address } = this.getInstance();
const feePayload = await EntrypointPayload.fromFeeOptions(options?.fee);

exec.calls.push({
to: address,
args: encodeArguments(this.#feePaymentArtifact, [feePayload]),
functionData: FunctionData.fromAbi(this.#feePaymentArtifact),
});

exec.authWitnesses ??= [];
exec.packedArguments ??= [];

exec.authWitnesses.push(await this.#authWitnessProvider.createAuthWit(feePayload.hash()));
exec.packedArguments.push(...feePayload.packedArguments);
}

return exec;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type TxHash, type TxReceipt } from '@aztec/circuit-types';
import { type PXE, type TxHash, type TxReceipt } from '@aztec/circuit-types';
import { type FieldsOf } from '@aztec/foundation/types';

import { type Wallet } from '../account/index.js';
Expand All @@ -15,8 +15,8 @@ export type DeployAccountTxReceipt = FieldsOf<TxReceipt> & {
* A deployment transaction for an account contract sent to the network, extending SentTx with methods to get the resulting wallet.
*/
export class DeployAccountSentTx extends SentTx {
constructor(private wallet: Wallet, txHashPromise: Promise<TxHash>) {
super(wallet, txHashPromise);
constructor(pxe: PXE, txHashPromise: Promise<TxHash>, private getWalletPromise: Promise<Wallet>) {
super(pxe, txHashPromise);
}

/**
Expand All @@ -36,7 +36,8 @@ export class DeployAccountSentTx extends SentTx {
*/
public async wait(opts: WaitOpts = DefaultWaitOpts): Promise<DeployAccountTxReceipt> {
const receipt = await super.wait(opts);
await waitForAccountSynch(this.pxe, this.wallet.getCompleteAddress(), opts);
return { ...receipt, wallet: this.wallet };
const wallet = await this.getWalletPromise;
await waitForAccountSynch(this.pxe, wallet.getCompleteAddress(), opts);
return { ...receipt, wallet };
}
}
Loading