Skip to content

Commit

Permalink
feat: TXE 2: Electric boogaloo (#7154)
Browse files Browse the repository at this point in the history
Adds new capabilities to TXE, and a proper `TokenContract` suite to
showcase them:

- Private -> Public calls
- Public -> Public calls
- Actual account contract deployment for complex interactions
- Auhtwits, both public and private
- Note cache storage
- Speed improvements

![Screenshot 2024-06-21 at 18 16
23](https://github.com/AztecProtocol/aztec-packages/assets/5404052/16e583bb-e05e-497a-b278-1a39ee177b23)

The full test suite is comparable to the e2e one (with some caveats,
some things just cannot be tested yet using TXE), but runs significantly
faster. Interestingly, runs faster on an M3 macbook than on mainframe
(120s vs. 240s).

e2e tests take more than 600s (without stored snapshots), but the gap
increases as we reduce the amount of tests launched simultaneously. An
unconstrained private transfer runs in less than 10s using TXE!

If launching many tests in parallel, it is recommended to increase the
nargo timeout for foreign calls to avoid timeout errors:
`NARGO_FOREIGN_CALL_TIMEOUT=300000`

Closes #7086

---------

Co-authored-by: Nicolás Venturo <[email protected]>
  • Loading branch information
Thunkar and nventuro authored Jun 25, 2024
1 parent 26fc599 commit bb38246
Show file tree
Hide file tree
Showing 35 changed files with 2,047 additions and 341 deletions.
4 changes: 3 additions & 1 deletion noir-projects/Dockerfile.test
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ RUN cd /usr/src/yarn-project/txe && yarn start & echo $! > /tmp/txe.pid && \
# Wait for TXE to initialize
sleep 5 && \
cd ./noir-contracts && \
./bootstrap.sh && nargo test --silence-warnings --oracle-resolver http://localhost:8080 ; \
# We need to increase the timeout since all tests running in parallel hammer TXE at the same time, and processing slows down leading to timeouts
# The only way we currently have to batch tests is via RAYON_NUM_THREADS, which is not ideal
./bootstrap.sh && NARGO_FOREIGN_CALL_TIMEOUT=300000 nargo test --silence-warnings --oracle-resolver http://localhost:8080 ; \
kill $(cat /tmp/txe.pid)

RUN cd /usr/src/yarn-project/txe && yarn start & echo $! > /tmp/txe.pid && \
Expand Down
5 changes: 4 additions & 1 deletion noir-projects/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ test:
RUN cd /usr/src/yarn-project/txe && yarn start & echo $! > /tmp/txe.pid && \
# Wait for TXE to initialize
sleep 5 && \
cd /usr/src/noir-projects/noir-contracts && nargo test --silence-warnings --oracle-resolver http://localhost:8080 ; \
cd /usr/src/noir-projects/noir-contracts && \
# We need to increase the timeout since all tests running in parallel hammer TXE at the same time and processing slows down, leading to timeouts
# The only way we currently have to batch tests is via RAYON_NUM_THREADS, which is not ideal
NARGO_FOREIGN_CALL_TIMEOUT=300000 nargo test --silence-warnings --oracle-resolver http://localhost:8080 ; \
kill $(cat /tmp/txe.pid)

format:
Expand Down
44 changes: 44 additions & 0 deletions noir-projects/aztec-nr/authwit/src/cheatcodes.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use dep::aztec::{
protocol_types::address::AztecAddress,
context::{public_context::PublicContext, call_interfaces::CallInterface}, test::helpers::cheatcodes,
hash::hash_args
};

use crate::auth::{compute_inner_authwit_hash, compute_outer_authwit_hash, set_authorized};

pub fn add_private_authwit_from_call_interface<C, M, T, P, Env>(
on_behalf_of: AztecAddress,
caller: AztecAddress,
call_interface: C
) where C: CallInterface<M, T, P, Env> {
let target = call_interface.get_contract_address();
let inputs = cheatcodes::get_private_context_inputs(cheatcodes::get_block_number());
let chain_id = inputs.tx_context.chain_id;
let version = inputs.tx_context.version;
let args_hash = hash_args(call_interface.get_args());
let selector = call_interface.get_selector();
let inner_hash = compute_inner_authwit_hash([caller.to_field(), selector.to_field(), args_hash]);
let message_hash = compute_outer_authwit_hash(target, chain_id, version, inner_hash);
cheatcodes::add_authwit(on_behalf_of, message_hash);
}

pub fn add_public_authwit_from_call_interface<C, M, T, P, Env>(
on_behalf_of: AztecAddress,
caller: AztecAddress,
call_interface: C
) where C: CallInterface<M, T, P, Env> {
let current_contract = cheatcodes::get_contract_address();
cheatcodes::set_contract_address(on_behalf_of);
let target = call_interface.get_contract_address();
let inputs = cheatcodes::get_private_context_inputs(cheatcodes::get_block_number());
let chain_id = inputs.tx_context.chain_id;
let version = inputs.tx_context.version;
let args_hash = hash_args(call_interface.get_args());
let selector = call_interface.get_selector();
let inner_hash = compute_inner_authwit_hash([caller.to_field(), selector.to_field(), args_hash]);
let message_hash = compute_outer_authwit_hash(target, chain_id, version, inner_hash);
let mut inputs = cheatcodes::get_public_context_inputs();
let mut context = PublicContext::new(inputs);
set_authorized(&mut context, message_hash, true);
cheatcodes::set_contract_address(current_contract);
}
1 change: 1 addition & 0 deletions noir-projects/aztec-nr/authwit/src/lib.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ mod account;
mod auth_witness;
mod auth;
mod entrypoint;
mod cheatcodes;
59 changes: 50 additions & 9 deletions noir-projects/aztec-nr/aztec/src/context/call_interfaces.nr
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ trait CallInterface<N, T, P, Env> {
fn get_selector(self) -> FunctionSelector;
fn get_name(self) -> str<N>;
fn get_contract_address(self) -> AztecAddress;
fn get_is_static(self) -> bool;
}

impl<N, T, P, Env> CallInterface<N, PrivateContextInputs, PrivateCircuitPublicInputs, Env> for PrivateCallInterface<N, T, Env> {
Expand All @@ -38,6 +39,10 @@ impl<N, T, P, Env> CallInterface<N, PrivateContextInputs, PrivateCircuitPublicIn
fn get_contract_address(self) -> AztecAddress {
self.target_contract
}

fn get_is_static(self) -> bool {
self.is_static
}
}

struct PrivateCallInterface<N, T, Env> {
Expand All @@ -46,7 +51,8 @@ struct PrivateCallInterface<N, T, Env> {
name: str<N>,
args_hash: Field,
args: [Field],
original: fn[Env](PrivateContextInputs) -> PrivateCircuitPublicInputs
original: fn[Env](PrivateContextInputs) -> PrivateCircuitPublicInputs,
is_static: bool
}

impl<N, T, Env> PrivateCallInterface<N, T, Env> {
Expand Down Expand Up @@ -93,6 +99,10 @@ impl<N, T, P, Env> CallInterface<N, PrivateContextInputs, PrivateCircuitPublicIn
fn get_contract_address(self) -> AztecAddress {
self.target_contract
}

fn get_is_static(self) -> bool {
self.is_static
}
}

struct PrivateVoidCallInterface<N, Env> {
Expand All @@ -101,7 +111,8 @@ struct PrivateVoidCallInterface<N, Env> {
name: str<N>,
args_hash: Field,
args: [Field],
original: fn[Env](PrivateContextInputs) -> PrivateCircuitPublicInputs
original: fn[Env](PrivateContextInputs) -> PrivateCircuitPublicInputs,
is_static: bool
}

impl<N, Env> PrivateVoidCallInterface<N, Env> {
Expand Down Expand Up @@ -144,6 +155,10 @@ impl<N, T, P, Env> CallInterface<N, PrivateContextInputs, PrivateCircuitPublicIn
fn get_contract_address(self) -> AztecAddress {
self.target_contract
}

fn get_is_static(self) -> bool {
self.is_static
}
}

struct PrivateStaticCallInterface<N, T, Env> {
Expand All @@ -152,7 +167,8 @@ struct PrivateStaticCallInterface<N, T, Env> {
name: str<N>,
args_hash: Field,
args: [Field],
original: fn[Env](PrivateContextInputs) -> PrivateCircuitPublicInputs
original: fn[Env](PrivateContextInputs) -> PrivateCircuitPublicInputs,
is_static: bool
}

impl<N, T, Env> PrivateStaticCallInterface<N, T, Env> {
Expand Down Expand Up @@ -182,6 +198,10 @@ impl<N, T, P, Env> CallInterface<N, PrivateContextInputs, PrivateCircuitPublicIn
fn get_contract_address(self) -> AztecAddress {
self.target_contract
}

fn get_is_static(self) -> bool {
self.is_static
}
}

struct PrivateStaticVoidCallInterface<N, Env> {
Expand All @@ -190,7 +210,8 @@ struct PrivateStaticVoidCallInterface<N, Env> {
name: str<N>,
args_hash: Field,
args: [Field],
original: fn[Env](PrivateContextInputs) -> PrivateCircuitPublicInputs
original: fn[Env](PrivateContextInputs) -> PrivateCircuitPublicInputs,
is_static: bool
}

impl<N, Env> PrivateStaticVoidCallInterface<N, Env> {
Expand Down Expand Up @@ -219,6 +240,10 @@ impl<N, T, P, Env> CallInterface<N, PublicContextInputs, T, Env> for PublicCallI
fn get_contract_address(self) -> AztecAddress {
self.target_contract
}

fn get_is_static(self) -> bool {
self.is_static
}
}

struct PublicCallInterface<N, T, Env> {
Expand All @@ -227,7 +252,8 @@ struct PublicCallInterface<N, T, Env> {
name: str<N>,
args: [Field],
gas_opts: GasOpts,
original: fn[Env](PublicContextInputs) -> T
original: fn[Env](PublicContextInputs) -> T,
is_static: bool
}

impl<N, T, Env> PublicCallInterface<N, T, Env> {
Expand Down Expand Up @@ -308,6 +334,10 @@ impl<N, T, P, Env> CallInterface<N, PublicContextInputs, (), Env> for PublicVoid
fn get_contract_address(self) -> AztecAddress {
self.target_contract
}

fn get_is_static(self) -> bool {
self.is_static
}
}

struct PublicVoidCallInterface<N, Env> {
Expand All @@ -316,7 +346,8 @@ struct PublicVoidCallInterface<N, Env> {
name: str<N>,
args: [Field],
gas_opts: GasOpts,
original: fn[Env](PublicContextInputs) -> ()
original: fn[Env](PublicContextInputs) -> (),
is_static: bool
}

impl<N, Env> PublicVoidCallInterface<N, Env> {
Expand Down Expand Up @@ -378,7 +409,7 @@ impl<N, Env> PublicVoidCallInterface<N, Env> {
}

impl<N, T, P, Env> CallInterface<N, PublicContextInputs, T, Env> for PublicStaticCallInterface<N, T, Env> {
fn get_args(self) -> [Field] {
fn get_args(self) -> [Field] {
self.args
}

Expand All @@ -397,6 +428,10 @@ impl<N, T, P, Env> CallInterface<N, PublicContextInputs, T, Env> for PublicStati
fn get_contract_address(self) -> AztecAddress {
self.target_contract
}

fn get_is_static(self) -> bool {
self.is_static
}
}

struct PublicStaticCallInterface<N, T, Env> {
Expand All @@ -405,7 +440,8 @@ struct PublicStaticCallInterface<N, T, Env> {
name: str<N>,
args: [Field],
gas_opts: GasOpts,
original: fn[Env](PublicContextInputs) -> T
original: fn[Env](PublicContextInputs) -> T,
is_static: bool
}

impl<N, T, Env> PublicStaticCallInterface<N, T, Env> {
Expand Down Expand Up @@ -453,6 +489,10 @@ impl<N, T, P, Env> CallInterface<N, PublicContextInputs, (), Env> for PublicStat
fn get_contract_address(self) -> AztecAddress {
self.target_contract
}

fn get_is_static(self) -> bool {
self.is_static
}
}

struct PublicStaticVoidCallInterface<N, Env> {
Expand All @@ -461,7 +501,8 @@ struct PublicStaticVoidCallInterface<N, Env> {
name: str<N>,
args: [Field],
gas_opts: GasOpts,
original: fn[Env](PublicContextInputs) -> ()
original: fn[Env](PublicContextInputs) -> (),
is_static: bool
}

impl<N, Env> PublicStaticVoidCallInterface<N, Env> {
Expand Down
6 changes: 2 additions & 4 deletions noir-projects/aztec-nr/aztec/src/note/lifecycle.nr
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ pub fn create_note<Note, N, M>(
let note_hash_counter = context.side_effect_counter;

let header = NoteHeader { contract_address, storage_slot, nonce: 0, note_hash_counter };
// TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed
Note::set_header(note, header);
note.set_header(header);
let inner_note_hash = compute_inner_note_hash(*note);

// TODO: Strong typing required because of https://github.com/noir-lang/noir/issues/4088
let serialized_note: [Field; N] = Note::serialize_content(*note);
let serialized_note = Note::serialize_content(*note);
assert(
notify_created_note(
storage_slot,
Expand Down
3 changes: 1 addition & 2 deletions noir-projects/aztec-nr/aztec/src/oracle/notes.nr
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ unconstrained pub fn get_notes<Note, N, NB, M, S, NS>(
let header = NoteHeader { contract_address, nonce, storage_slot, note_hash_counter };
let serialized_note = arr_copy_slice(fields, [0; N], read_offset + 2);
let mut note = Note::deserialize_content(serialized_note);
// TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed
Note::set_header(&mut note, header);
note.set_header(header);
placeholder_opt_notes[i] = Option::some(note);
};
}
Expand Down
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/test/helpers.nr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod test_environment;
mod cheatcodes;
mod types;
mod utils;
mod keys;
Loading

0 comments on commit bb38246

Please sign in to comment.