Skip to content

Commit 92b1a23

Browse files
committed
docs: align counter scaffold with tutorial and run example TXE tests in CI
- Fix the `aztec init` counter scaffold so `increment()` reads `self.msg_sender()` instead of taking an `owner` param, matching the tutorial's auth fix. The CLI no longer scaffolds the "anyone can increment anyone's counter" default. Updates the scaffold's test to match. - Rename the docs counter example's initializer from `initialize`/`headstart` to `constructor`/`initial_value` to match the scaffold; update the tutorial prose and TXE tests accordingly, and fix a stale `aztec(initializer)` comment. - Tighten the tutorial's privacy claim (drop the inaccurate "no one knows when you increment") and explain why only `increment` derives the owner from the caller while `constructor` and `get_counter` take an explicit owner. - Wire the example TXE test packages (counter_contract_test, logging_example_test) into docs CI via a new `test-contracts` step that starts a TXE and runs `nargo test`; drop the unused `balance_set` dependency.
1 parent 8b1769d commit 92b1a23

7 files changed

Lines changed: 86 additions & 26 deletions

File tree

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ references: ["docs/examples/contracts/counter_contract/src/main.nr"]
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

@@ -120,6 +120,8 @@ Now let's implement an `increment` function to increase the counter.
120120

121121
The `increment` function uses `self.msg_sender()` so each caller can only increment the counter mapped to their own address. It logs a debug message, then adds 1 to that counter and delivers the note onchain.
122122

123+
Only this mutating action derives the owner from the caller. The one-time `constructor` and the `get_counter` read still take an explicit `owner`: the constructor can seed a chosen account, and a read selects which counter to view (only its owner can decrypt it).
124+
123125
## Getting a counter
124126

125127
The last thing we need to implement is a function to retrieve a counter value.

docs/examples/bootstrap.sh

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,53 @@ 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
echo "$hash:ONLY_TERM_PARENT=1 docs/examples/bootstrap.sh execute"
258+
echo "$hash:ONLY_TERM_PARENT=1 docs/examples/bootstrap.sh test-contracts"
214259
}
215260

216261
function test {
@@ -390,6 +435,9 @@ case "$cmd" in
390435
execute)
391436
execute-examples
392437
;;
438+
test-contracts)
439+
test-contracts
440+
;;
393441
*)
394442
default_cmd_handler "$@"
395443
;;

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
}

docs/examples/contracts/counter_contract_test/Nargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,4 @@ type = "lib"
66

77
[dependencies]
88
aztec = { path = "../../../../noir-projects/aztec-nr/aztec" }
9-
balance_set = { path = "../../../../noir-projects/aztec-nr/balance-set" }
109
counter_contract = { path = "../counter_contract" }
Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,55 @@
11
use counter_contract::Counter;
22
use aztec::{protocol::address::AztecAddress, test::helpers::test_environment::TestEnvironment};
33

4-
pub unconstrained fn setup(headstart: u128) -> (TestEnvironment, AztecAddress, AztecAddress) {
4+
pub unconstrained fn setup(initial_value: u128) -> (TestEnvironment, AztecAddress, AztecAddress) {
55
let mut env = TestEnvironment::new();
66
let owner = env.create_light_account();
77

8-
let initializer = Counter::interface().initialize(headstart, owner);
8+
let initializer = Counter::interface().constructor(initial_value, owner);
99
let contract_address =
1010
env.deploy("@counter_contract/Counter").with_private_initializer(owner, initializer);
1111
(env, contract_address, owner)
1212
}
1313

1414
#[test]
15-
unconstrained fn test_initialize_sets_headstart() {
16-
let headstart = 5;
17-
let (env, contract_address, owner) = setup(headstart);
15+
unconstrained fn test_constructor_sets_initial_value() {
16+
let initial_value = 5;
17+
let (env, contract_address, owner) = setup(initial_value);
1818

1919
let value = env.execute_utility(Counter::at(contract_address).get_counter(owner));
20-
assert(value == headstart, f"Expected {headstart} but got {value}");
20+
assert(value == initial_value, f"Expected {initial_value} but got {value}");
2121
}
2222

2323
#[test]
2424
unconstrained fn test_increment_increases_caller_counter() {
25-
let headstart = 5;
26-
let (mut env, contract_address, owner) = setup(headstart);
25+
let initial_value = 5;
26+
let (mut env, contract_address, owner) = setup(initial_value);
2727

2828
env.call_private(owner, Counter::at(contract_address).increment());
2929

30-
let expected = headstart + 1;
30+
let expected = initial_value + 1;
3131
let value = env.execute_utility(Counter::at(contract_address).get_counter(owner));
3232
assert(value == expected, f"Expected {expected} but got {value}");
3333
}
3434

3535
#[test]
36-
unconstrained fn test_increment_does_not_affect_other_account() {
37-
let headstart = 5;
38-
let (mut env, contract_address, owner) = setup(headstart);
39-
let other = env.create_light_account();
36+
unconstrained fn test_stranger_increment_does_not_affect_owner() {
37+
let initial_value = 5;
38+
let (mut env, contract_address, owner) = setup(initial_value);
39+
let stranger = env.create_light_account();
4040

41-
env.call_private(other, Counter::at(contract_address).increment());
41+
// `increment` derives the owner from msg_sender, so a different caller can
42+
// only ever touch its own counter, never the owner's.
43+
env.call_private(stranger, Counter::at(contract_address).increment());
4244

45+
// The stranger's increment lands on their own counter, which started at 0.
46+
let stranger_value = env.execute_utility(Counter::at(contract_address).get_counter(stranger));
47+
assert(stranger_value == 1, f"Expected stranger counter at 1 but got {stranger_value}");
48+
49+
// The owner's counter is untouched by another account's increment.
4350
let owner_value = env.execute_utility(Counter::at(contract_address).get_counter(owner));
4451
assert(
45-
owner_value == headstart,
46-
f"Expected owner counter unchanged at {headstart} but got {owner_value}",
52+
owner_value == initial_value,
53+
f"Expected owner counter unchanged at {initial_value} but got {owner_value}",
4754
);
4855
}

yarn-project/aztec/scripts/templates/counter/contract/src/main.nr

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ pub contract Counter {
3131
);
3232
}
3333

34-
// Adds 1 to the owner's counter.
34+
// Adds 1 to the caller's own counter.
35+
//
36+
// The owner is read from self.msg_sender(), so a caller can only ever
37+
// increment the counter mapped to their own address.
3538
#[external("private")]
36-
fn increment(owner: AztecAddress) {
39+
fn increment() {
40+
let owner = self.msg_sender();
3741
self.storage.counters.at(owner).add(1).deliver(MessageDelivery.ONCHAIN_CONSTRAINED);
3842
}
3943

yarn-project/aztec/scripts/templates/counter/test/src/lib.nr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ unconstrained fn test_increment() {
2525
let initial_value = 5;
2626
let (mut env, contract_address, owner) = setup(initial_value);
2727

28-
env.call_private(owner, Counter::at(contract_address).increment(owner));
28+
env.call_private(owner, Counter::at(contract_address).increment());
2929

3030
let counter = env.execute_utility(Counter::at(contract_address).get_counter(owner));
3131
assert_eq(counter, initial_value + 1);

0 commit comments

Comments
 (0)