Skip to content

Commit 32207bf

Browse files
authored
docs: align counter tutorial example with the aztec init template and add TXE tests (#23517)
## Summary Align the counter contract tutorial's example with the canonical `aztec init` counter template, add TXE tests, and run them in docs CI. - **Naming aligned with the template.** The docs example's initializer is renamed from `initialize`/`headstart` to `constructor`/`initial_value` to match the counter scaffold that `aztec init` generates (`yarn-project/aztec/scripts/templates/counter/`). The `increment(owner)` and `get_counter(owner)` signatures already match the template and are unchanged. This PR does not modify the CLI template itself; the docs example follows it. - **TXE tests.** Adds a `counter_contract_test` package (mirroring `logging_example_test`) with tests for the constructor and increment, matching the template's test layout. - **CI.** A new `test-contracts` step in `docs/examples/bootstrap.sh` starts a TXE and runs `nargo test` for both `counter_contract_test` and `logging_example_test`, so these tests run in docs CI rather than sitting unexecuted. - **Tutorial polish.** Sentence-case headings, a more accurate privacy description (the count is confidential; dropped the overstated "no one knows when you increment"), and prose updated for the `constructor` naming. ## What's not in scope - No change to the `aztec init` counter template; the docs example is aligned to it. - No change to the example's authorization model: `increment(owner)` matches the template. ## Test plan - CI's `docs/examples/bootstrap.sh compile` builds `counter_contract` against the `constructor` signature. - The new `docs/examples/bootstrap.sh test-contracts` step runs `nargo test` for `counter_contract_test` and `logging_example_test` against a TXE. This could not be run locally (stale in-repo nargo, and the step needs a built `yarn-project/txe`), so the first real validation is this PR's CI run. - Docusaurus dev build renders the updated tutorial without `#include_code` errors.
2 parents 5fb7528 + af8019f commit 32207bf

7 files changed

Lines changed: 102 additions & 11 deletions

File tree

docs/Nargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
members = [
33
"examples/circuits/hello_circuit",
44
"examples/contracts/counter_contract",
5+
"examples/contracts/counter_contract_test",
56
"examples/contracts/bob_token_contract",
67
"examples/contracts/nft",
78
"examples/contracts/nft_bridge",

docs/docs-developers/docs/tutorials/contract_tutorials/counter_contract.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
---
2-
title: Counter Contract
2+
title: Counter contract
33
description: Code-along tutorial for creating a simple counter contract on Aztec.
44
sidebar_position: 0
55
references: ["docs/examples/contracts/counter_contract/src/main.nr"]
66
---
77

88
import Image from "@theme/IdealImage";
99

10-
In this guide, we will create our first Aztec.nr smart contract. We will build a simple private counter, where you can keep your own private counter - so no one knows what ID you are at or when you increment! This contract will get you started with the basic setup and syntax of Aztec.nr, but doesn't showcase all of the awesome stuff Aztec is capable of.
10+
In this guide, we will create our first Aztec.nr smart contract. We will build a simple private counter, where each account keeps its own counter as encrypted private state, so the count stays known only to you. This contract will get you started with the basic setup and syntax of Aztec.nr, but doesn't showcase all of the awesome stuff Aztec is capable of.
1111

1212
This tutorial is compatible with the Aztec version `#include_aztec_version`. Install the correct version with `VERSION=#include_version_without_prefix bash -i <(curl -sL https://install.aztec.network/#include_version_without_prefix)`. Or if you'd like to use a different version, you can find the relevant tutorial by clicking the version dropdown at the top of the page.
1313

@@ -104,11 +104,11 @@ Add this below the imports. It declares the storage variables for our contract.
104104

105105
Now we’ve got a mechanism for storing our private state, we can start using it to ensure the privacy of balances.
106106

107-
Let’s create a constructor method to run on deployment that assigns an initial count to a specified owner. This function is called `initialize`, but behaves like a constructor. It is the `#[initializer]` decorator that specifies that this function behaves like a constructor. Write this:
107+
Let’s create a constructor method to run on deployment that assigns an initial count to a specified owner. We name it `constructor` here, but the name is arbitrary; it is the `#[initializer]` decorator that marks it to run once when the contract is deployed. Write this:
108108

109109
#include_code constructor /docs/examples/contracts/counter_contract/src/main.nr rust
110110

111-
This function accesses the counters from storage. It adds the `headstart` value to the `owner`'s counter using `at().add()`, then calls `.deliver(MessageDelivery::onchain_constrained())` to ensure the note is delivered onchain.
111+
This function accesses the counters from storage. It adds the `initial_value` to the `owner`'s counter using `at().add()`, then calls `.deliver(MessageDelivery::onchain_constrained())` to ensure the note is delivered onchain.
112112

113113
We have annotated this and other functions with `#[external("private")]` which are ABI macros so the compiler understands it will handle private inputs.
114114

@@ -118,7 +118,7 @@ Now let's implement an `increment` function to increase the counter.
118118

119119
#include_code increment /docs/examples/contracts/counter_contract/src/main.nr rust
120120

121-
The `increment` function works similarly to the `initialize` function. It logs a debug message, then adds 1 to the owner's counter and delivers the note onchain.
121+
The `increment` function works similarly to the `constructor`. It logs a debug message, then adds 1 to the `owner`'s counter and delivers the note onchain.
122122

123123
## Getting a counter
124124

@@ -152,8 +152,8 @@ aztec codegen -o src/artifacts target
152152

153153
You can now use the artifact and/or the TS class in your Aztec.js!
154154

155-
## Next Steps
155+
## Next steps
156156

157-
### Optional: Learn more about concepts mentioned here
157+
### Optional: learn more about concepts mentioned here
158158

159159
- [Functions and annotations like `#[external("private")]`](../../aztec-nr/framework-description/functions/function_transforms.md#private-functions)

docs/examples/bootstrap.sh

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,56 @@ function execute-examples {
209209
run_compose_test "docs_examples" "docs-examples" "$COMPOSE_DIR"
210210
}
211211

212+
# Runs the Noir TXE tests for the example test packages (the type = "lib" packages
213+
# that the `compile` step skips). A local TXE server resolves the foreign calls the
214+
# tests make: account creation, deployment, and private/utility execution.
215+
function test-contracts {
216+
echo_header "Testing example contracts (TXE)"
217+
local test_packages=("counter_contract_test" "logging_example_test")
218+
local txe_port=${TXE_PORT:-14745}
219+
220+
# Run in a subshell so the EXIT trap that stops the TXE is scoped to this step.
221+
(
222+
set -euo pipefail
223+
if command -v check_port >/dev/null 2>&1; then
224+
check_port "$txe_port" || {
225+
echo_stderr "Cannot start TXE: port $txe_port is already in use."
226+
exit 1
227+
}
228+
fi
229+
cd "$REPO_ROOT/yarn-project/txe"
230+
UV_THREADPOOL_SIZE=8 LOG_LEVEL=silent TXE_PORT="$txe_port" yarn start >/dev/null &
231+
txe_pid=$!
232+
trap 'kill "$txe_pid" &>/dev/null || true' EXIT
233+
234+
echo_stderr "Waiting for TXE to start on port $txe_port..."
235+
j=0
236+
while ! nc -z 127.0.0.1 "$txe_port" &>/dev/null; do
237+
[ "$j" -ge 60 ] && {
238+
echo_stderr "TXE failed to start on port $txe_port after 60s."
239+
exit 1
240+
}
241+
sleep 1
242+
j=$((j + 1))
243+
done
244+
245+
export RAYON_NUM_THREADS=1
246+
export NARGO_FOREIGN_CALL_TIMEOUT=300000
247+
cd "$REPO_ROOT/docs"
248+
for pkg in "${test_packages[@]}"; do
249+
echo_stderr "Running $pkg..."
250+
$NARGO test --silence-warnings --skip-brillig-constraints-check \
251+
--oracle-resolver "http://127.0.0.1:$txe_port" --package "$pkg"
252+
done
253+
)
254+
}
255+
212256
function test_cmds {
213257
# Bumped from the default 600s by ~50% (now 15m) to absorb cumulative-runtime growth
214258
# under merge-queue load — example_swap's `wait-for-proven` poll was tipping SIGTERM
215259
# near the old limit. See PR #23253 dequeue log http://ci.aztec-labs.com/b08ac48286302949.
216260
echo "$hash:ONLY_TERM_PARENT=1:TIMEOUT=15m docs/examples/bootstrap.sh execute"
261+
echo "$hash:ONLY_TERM_PARENT=1 docs/examples/bootstrap.sh test-contracts"
217262
}
218263

219264
function test {
@@ -393,6 +438,9 @@ case "$cmd" in
393438
execute)
394439
execute-examples
395440
;;
441+
test-contracts)
442+
test-contracts
443+
;;
396444
*)
397445
default_cmd_handler "$@"
398446
;;

docs/examples/contracts/counter_contract/src/main.nr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ pub contract Counter {
2525
// docs:start:constructor
2626
#[initializer]
2727
#[external("private")]
28-
// We can name our initializer anything we want as long as it's marked as aztec(initializer)
29-
fn initialize(headstart: u128, owner: AztecAddress) {
30-
self.storage.counters.at(owner).add(headstart).deliver(
28+
// We can name our initializer anything we want as long as it's marked as #[initializer]
29+
fn constructor(initial_value: u128, owner: AztecAddress) {
30+
self.storage.counters.at(owner).add(initial_value).deliver(
3131
MessageDelivery::onchain_constrained(),
3232
);
3333
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "counter_contract_test"
3+
authors = [""]
4+
compiler_version = ">=0.25.0"
5+
type = "lib"
6+
7+
[dependencies]
8+
aztec = { path = "../../../../noir-projects/aztec-nr/aztec" }
9+
counter_contract = { path = "../counter_contract" }
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use counter_contract::Counter;
2+
use aztec::{protocol::address::AztecAddress, test::helpers::test_environment::TestEnvironment};
3+
4+
pub unconstrained fn setup(initial_value: u128) -> (TestEnvironment, AztecAddress, AztecAddress) {
5+
let mut env = TestEnvironment::new();
6+
let owner = env.create_light_account();
7+
8+
let initializer = Counter::interface().constructor(initial_value, owner);
9+
let contract_address =
10+
env.deploy("@counter_contract/Counter").with_private_initializer(owner, initializer);
11+
(env, contract_address, owner)
12+
}
13+
14+
#[test]
15+
unconstrained fn test_constructor_sets_initial_value() {
16+
let initial_value = 5;
17+
let (env, contract_address, owner) = setup(initial_value);
18+
19+
let value = env.execute_utility(Counter::at(contract_address).get_counter(owner));
20+
assert(value == initial_value, f"Expected {initial_value} but got {value}");
21+
}
22+
23+
#[test]
24+
unconstrained fn test_increment() {
25+
let initial_value = 5;
26+
let (mut env, contract_address, owner) = setup(initial_value);
27+
28+
env.call_private(owner, Counter::at(contract_address).increment(owner));
29+
30+
let expected = initial_value + 1;
31+
let value = env.execute_utility(Counter::at(contract_address).get_counter(owner));
32+
assert(value == expected, f"Expected {expected} but got {value}");
33+
}

docs/examples/contracts/logging_example_test/src/lib.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ unconstrained fn test_public_logging() {
2424
#[test]
2525
unconstrained fn test_all_log_levels() {
2626
let (env, contract_address, owner) = setup();
27-
env.call_private(owner, LoggingExample::at(contract_address).log_all_levels());
27+
env.call_private(owner, LoggingExample::at(contract_address).log_all_levels(42));
2828
}
2929

3030
#[test]

0 commit comments

Comments
 (0)