Struct TestEnvironment
pub struct TestEnvironment
{ /* private fields */ }
Implementations
impl TestEnvironment
pub unconstrained fn new() -> Self
Creates a new TestEnvironment. This function should only be called once per test.
pub unconstrained fn public_context<Env, T>(
self,
f: unconstrained fn[Env](PublicContext) -> T,
) -> T
Creates a PublicContext, which allows using aztec-nr features as if inside a public contract function. Useful
for low-level testing of public state variables and utilities.
A new block is automatically mined once public_context returns, containing all of the side effects caused by
its execution (e.g. public storage writes). It is however NOT possible to make any contract calls from this
public context - use call_public for testing contract calls (though usage of call_public is forbidden while
inside public_context).
Receives a callback function which is called with the created PublicContext - this function is where testing
logic is expected to reside. Any values returned by it are bubbled-up and returned to the caller of
public_context. Do NOT return the PublicContext from the callback function, or use it in any way outside
of it - it becomes invalid once public_context returns.
See public_context_at for a variant that allows specifying the contract address.
Sample usage
env.public_context(|context| {
let state_var = PublicMutable::new(context, STORAGE_SLOT);
state_var.write(some_value);
assert_eq(state_var.read(), some_value);
});
Advanced usage with returns
let read_value = env.public_context(|context| {
let state_var = PublicMutable::new(context, STORAGE_SLOT);
state_var.read()
});
pub unconstrained fn public_context_at<Env, T>(
self,
addr: AztecAddress,
f: unconstrained fn[Env](PublicContext) -> T,
) -> T
Variant of public_context which allows specifying the contract address in which the public context will
execute, which will affect note and nullifier siloing, storage access, etc.
pub unconstrained fn private_context<Env, T>(
self,
f: unconstrained fn[Env](&mut PrivateContext) -> T,
) -> T
Creates a PrivateContext, which allows using aztec-nr features as if inside a private contract function.
Useful for low-level testing of private state variables and utilities.
A new block is automatically mined once private_context returns, containing all of the side effects caused by
its execution (e.g. note and nullifier emission). It is however NOT possible to make any contract calls from this
private context, neither private nor enqueued public calls - use call_private and call_public for testing
contract calls (though usage of these is forbidden while inside private_context).
Receives a callback function which is called with the created PrivateContext - this function is where testing
logic is expected to reside. Any values returned by it are bubbled-up and returned to the caller of
private_context. Do NOT return the PrivateContext from the callback function, or use it in any way
outside of it - it becomes invalid once private_context returns.
See private_context_at for a variant that allows specifying the contract address, or private_context_opts
for even more configurability.
Sample usage
env.private_context(|context| {
let state_var = PrivateMutable::new(context, STORAGE_SLOT);
let note = SampleNote::new(some_value);
state_var.initialize(note);
assert_eq(state_var.get_note(), note);
});
Advanced usage with returns
let note = env.private_context(|context| {
let state_var = PrivateMutable::new(context, STORAGE_SLOT);
state_var.get_note()
});
pub unconstrained fn private_context_at<Env, T>(
self,
addr: AztecAddress,
f: unconstrained fn[Env](&mut PrivateContext) -> T,
) -> T
Variant of private_context which allows specifying the contract address in which the private context will
execute, which will affect note and nullifier siloing, storage access, etc.
pub unconstrained fn private_context_opts<Env, T>(
_self: Self,
opts: PrivateContextOptions,
f: unconstrained fn[Env](&mut PrivateContext) -> T,
) -> T
Variant of private_context which allows specifying multiple configuration values via PrivateContextOptions.
pub unconstrained fn utility_context<Env, T>(
self,
f: unconstrained fn[Env](UtilityContext) -> T,
) -> T
Creates a UtilityContext, which allows using aztec-nr features as if inside a utility contract function.
Useful for low-level testing of private and public state variable utilities.
Receives a callback function which is called with the created Utility - this function is where testing
logic is expected to reside. Any values returned by it are bubbled-up and returned to the caller of
utility_context. Do NOT return the Utility from the callback function, or use it in any way outside of
it - it becomes invalid once utility_context returns.
See utility_context_at for a variant that allows specifying the contract address.
Sample usage
env.utility_context(|context| {
let state_var = PrivateMutable::new(context, STORAGE_SLOT);
let note = SampleNote::new(some_value);
assert_eq(state_var.view_note(), note);
});
Advanced usage with returns
let note = env.utility_context(|context| {
let state_var = PrivateMutable::new(context, STORAGE_SLOT);
state_var.view_note()
});
pub unconstrained fn utility_context_at<Env, T>(
self,
addr: AztecAddress,
f: unconstrained fn[Env](UtilityContext) -> T,
) -> T
Variant of utility_context which allows specifying the contract address in which the utility context will
execute, which will affect note and storage access.
pub unconstrained fn next_block_number(_self: Self) -> u32
Returns the number of the next block to be mined.
pub unconstrained fn last_block_number(_self: Self) -> u32
Returns the number of the last mined block. This is the default anchor block for private_context and
private_call.
pub unconstrained fn last_block_timestamp(_self: Self) -> u64
Returns the timestamp of the last mined block. Note that block timestamps do not automatically advance - this
must be done by calling mine_block_at or set_next_block_timestamp.
pub unconstrained fn mine_block_at(self, timestamp: u64)
Mines an empty block (i.e. with no transactions) at timestamp, causing followup public executions to occur at
that timestamp (e.g. via call_public or public_context), and making it possible to create private executions
at the specified timestamp (e.g. via call_private or private_context).
pub unconstrained fn set_next_block_timestamp(self, timestamp: u64)
Sets the timestamp of the next block to be mined, causing followup public executions to occur at that timestamp
(e.g. via call_public or public_context).
pub unconstrained fn mine_block(_self: Self)
Mines an empty block (i.e. with no transactions). Note that block timestamps do not automatically advance - this
must be done by calling mine_block_at or set_next_block_timestamp.
pub unconstrained fn advance_next_block_timestamp_by(_self: Self, duration: u64)
Sets the timestamp of the next block to be mined to be ahead of the last one by duration.
pub unconstrained fn create_contract_account(&mut self) -> AztecAddress
Creates a new account that can be used as the from parameter in contract calls, e.g. in private_call or
public_call, or be made the owner or recipient of notes in private_context.
The returned account has a full set of privacy keys, so it can nullify notes, receive messages, etc. It also has
an associated SchnorrAccount contract that can process authwit requests - the authwits can be added via the
add_private_authwit_from_call and add_public_authwit_from_call helper functions. If
authwits are not required, consider using create_light_account instead, which is a faster variant of this
function.
Each call to create_contract_account will return a different address, and so it can be called repeatedly to
generate multiple addresses. These addresses are also different from the ones that create_light_account
returns, and so these two functions can be mixed and match to create a set of unique accounts.
pub unconstrained fn create_light_account(&mut self) -> AztecAddress
Creates a new account that can be used as the from parameter in contract calls, e.g. in private_call or
public_call, or be made the owner or recipient of notes in private_context. This is a faster variant of
create_contract_account, but comes with reduced capabilities.
The returned account has a full set of privacy keys, so it can nullify notes, receive messages, etc. It doesn't
however have an associated account contract, so it cannot process private authwit requests. If calling contracts
that rely on private authwits, use create_contract_account instead.
Each call to create_light_account will return a different address, and so it can be called repeatedly to
generate multiple addresses. These addresses are also different from the ones that create_contract_account
returns, and so these two functions can be mixed and match to create a set of unique accounts.
pub unconstrained fn deploy<let N: u32>(
&mut self,
path: str<N>,
) -> ContractDeployment<N>
Prepares a contract for deployment, so that its private, public and utility functions can be called. The contract must be already compiled before tests are run, and must be recompiled if changed for the tests to deploy the updated version.
In order to finalize the deployment, the proper initializer function must be specified via one of the associated methods. For more information on how to specify the path and initialization, read the sections below.
Path
Contracts can be deployed from either the same crate as the test, from a different crate in the same workspace, or from an altogether independent crate.
If deploying contracts from the same crate as the test, just refer to it by its name:
TestEnvironment::new().deploy("MyContract");
If deploying contracts from a different crate in the same workspace, use @crate_name/contract_name:
TestEnvironment::new().deploy("@my_contract_crate/MyContract");
If deploying contracts from a crate not in the workspace, use path_to_crate/contract_name, with the crate path
relative to the current workspace:
TestEnvironment::new().deploy("../my_other_crate/MyContract");
Initialization
If no initializer function needs to be called, use without_initializer:
let my_contract = TestEnvironment::new().deploy("MyContract").without_initializer();
For private initializers, use with_private_initializer:
let my_contract = TestEnvironment::new().deploy("MyContract").with_private_initializer(
PrivateInitContract::interface().private_init_fn(init_args)
);
For public initializers, use with_public_initializer:
let my_contract = TestEnvironment::new().deploy("MyContract").with_public_initializer(
PublicInitContract::interface().public_init_fn(init_args)
);
pub unconstrained fn call_private<let M: u32, let N: u32, T>(
_self: Self,
from: AztecAddress,
call: PrivateCall<M, N, T>,
) -> T
where
T: Deserialize
Performs a private contract function call, including the processing of any nested private calls and enqueued public calls. Returns the result of the called function.
The function is called by the from address - use create_contract_account or create_light_account to
generate sender addresses, depending on whether support for private authwit verification is required or not.
Note that execution will begin directly in the called function - no entrypoint function in from will be
executed.
A transaction is created containing all side effects of the call, which is then included in a block that gets
mined by the time call_private returns. It is therefore possible to chain multiple private or public function
calls that operate on the result of prior calls.
The call value can be obtained by calling the appropriate method on a contract type. E.g.:
let caller = env.create_light_account();
let contract_addr = env.deploy("SampleContract").without_initializer();
let return_value = env.call_private(caller, SampleContract::at(contract_addr).sample_private_function());
pub unconstrained fn view_private<let M: u32, let N: u32, T>(
_self: Self,
call: PrivateStaticCall<M, N, T>,
) -> T
where
T: Deserialize
Variant of call_private for private #[view] functions.
Unlike call_private, no transaction is created and no block is mined (since #[view] functions are only
executable in a static context, and these produce no side effects).
pub unconstrained fn simulate_utility<let M: u32, let N: u32, T>(
_self: Self,
call: UtilityCall<M, N, T>,
) -> T
where
T: Deserialize
Performs a utility contract function call and returns the result of the called function.
The call value can be obtained by calling the appropriate method on a contract type. E.g.:
let caller = env.create_light_account();
let contract_addr = env.deploy("SampleContract").without_initializer();
let return_value = env.simulate_utility(SampleContract::at(contract_addr).sample_utility_function());
pub unconstrained fn call_public<let M: u32, let N: u32, T>(
_self: Self,
from: AztecAddress,
call: PublicCall<M, N, T>,
) -> T
where
T: Deserialize
Performs a public contract function call, including the processing of any nested public calls. Returns the result of the called function.
The function is called by the from address - use create_contract_account or create_light_account to
generate sender addresses. Note that execution will begin directly in the called function - no private
entrypoint function in from will be executed - in fact no private execution of any kind will be performed.
A transaction is created containing all side effects of the call, which is then included in a block that gets
mined by the time call_public returns. It is therefore possible to chain multiple private or public function
calls that operate on the result of prior calls.
The call value can be obtained by calling the appropriate method on a contract type. E.g.:
let caller = env.create_light_account();
let contract_addr = env.deploy("SampleContract").without_initializer();
let return_value = env.call_public(caller, SampleContract::at(contract_addr).sample_public_function());
pub unconstrained fn call_public_incognito<let M: u32, let N: u32, T>(
_self: Self,
from: AztecAddress,
call: PublicCall<M, N, T>,
) -> T
where
T: Deserialize
Performs a public contract function call, including the processing of any nested public calls. Returns the
result of the called function.
Variant of call_public, but the from address (msg_sender) is set to "null".
pub unconstrained fn view_public<let M: u32, let N: u32, T>(
_self: Self,
call: PublicStaticCall<M, N, T>,
) -> T
where
T: Deserialize
Variant of call_public for public #[view] functions.
Unlike call_public, no transaction is created and no block is mined (since #[view] functions are only
executable in a static context, and these produce no side effects).
pub unconstrained fn view_public_incognito<let M: u32, let N: u32, T>(
_self: Self,
call: PublicStaticCall<M, N, T>,
) -> T
where
T: Deserialize
Variant of view_public, but the from address (msg_sender) is set to "null"
Unlike call_public, no transaction is created and no block is mined (since #[view] functions are only
executable in a static context, and these produce no side effects).
pub unconstrained fn discover_note<Note>(self, emission: NoteEmission<Note>)
Discovers a note wrapped in a NoteEmission value, which is expected to have been created in the last
transaction (typically via private_context()) so that it can be retrieved in later transactions. This mimics
the normal note discovery process that takes places automatically in contracts.
NoteEmission values are typically returned by aztec-nr state variables that create notes and need to notify a
recipient of their existence. Instead of going through the message encoding, encryption and emission that would
regularly take place in a contract, discover_note simply takes the NoteEmission and processes it as needed
to discover the underlying note.
See discover_note_at for a variant that allows specifying the contract address the note belongs to.
Sample usage
The most common way to invoke this function is to obtain an emission created during the execution of a
private_context:
let emission = env.private_context(|context| create_note(context, storage_slot, note));
env.discover_note(emission);
env.private_context(|context| { let (retrieved_note, _) = get_note::<MockNote>(context, storage_slot); });
pub unconstrained fn discover_note_at<Note>(
self,
addr: AztecAddress,
emission: NoteEmission<Note>,
)
Variant of discover_note which allows specifying the contract address the note belongs to, which is required
when the note was not emitted in the default address used by private_context.
let emission = env.private_context_at(contract_address, |context| {
create_note(context, storage_slot, note)
});
env.discover_note_at(contract_address, emission);
env.private_context_at(contract_address, |context| {
let (retrieved_note, _) = get_note::<MockNote>(context, storage_slot);
});
This represents an Aztec test run, and contains all the methods utilized during one to interact with the network and manipulate its state (e.g. create accounts, make contract calls, etc.). Each test is expected to have its own instance of
TestEnvironment, as tests execute in parallel and so cannot share this object.Most tests will begin by creating a
TestEnvironmentvariable, and then make multiple calls to its different methods. E.g.: