Skip to content

Commit 8437b40

Browse files
authored
Merge pull request #246 from AztecProtocol/feat/debug-log-utility-script
Add debug_game_state utility function and read-logs script
2 parents e108230 + 501918d commit 8437b40

File tree

4 files changed

+187
-1
lines changed

4 files changed

+187
-1
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"get-block::devnet": "NODE_NO_WARNINGS=1 AZTEC_ENV=devnet node --loader ts-node/esm scripts/get_block.ts",
2727
"profile": "NODE_NO_WARNINGS=1 node --loader ts-node/esm scripts/profile_deploy.ts",
2828
"profile::devnet": "NODE_NO_WARNINGS=1 AZTEC_ENV=devnet node --loader ts-node/esm scripts/profile_deploy.ts",
29+
"read-logs": "NODE_NO_WARNINGS=1 LOG_LEVEL='info; debug:contract_log' node --loader ts-node/esm scripts/read_debug_logs.ts",
30+
"read-logs::devnet": "NODE_NO_WARNINGS=1 LOG_LEVEL='info; debug:contract_log' AZTEC_ENV=devnet node --loader ts-node/esm scripts/read_debug_logs.ts",
2931
"test": "yarn test:js && yarn test:nr",
3032
"test::devnet": "AZTEC_ENV=devnet yarn test:js",
3133
"test:js": "rm -rf store/pxe && NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --runInBand --config jest.integration.config.json",

scripts/read_debug_logs.ts

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Reads debug logs from PodRacing contract transactions.
2+
//
3+
// debug_log_format calls in both contract functions and utility functions emit
4+
// through the PXE oracle during .simulate() and through the node during .send().
5+
// Set LOG_LEVEL to see them in stdout:
6+
//
7+
// LOG_LEVEL='info; debug:contract_log' yarn read-logs
8+
//
9+
// Or for maximum verbosity:
10+
//
11+
// LOG_LEVEL=debug yarn read-logs
12+
13+
import { PodRacingContract } from "../src/artifacts/PodRacing.js";
14+
import { createLogger } from "@aztec/foundation/log";
15+
import { SponsoredFeePaymentMethod } from "@aztec/aztec.js/fee";
16+
import { SponsoredFPCContractArtifact } from "@aztec/noir-contracts.js/SponsoredFPC";
17+
import { AztecAddress } from "@aztec/aztec.js/addresses";
18+
import { Fr } from "@aztec/aztec.js/fields";
19+
import { GrumpkinScalar } from "@aztec/foundation/curves/grumpkin";
20+
import { setupWallet } from "../src/utils/setup_wallet.js";
21+
import { getSponsoredFPCInstance } from "../src/utils/sponsored_fpc.js";
22+
import { getTimeouts } from "../config/config.js";
23+
24+
async function main() {
25+
const logger = createLogger('aztec:aztec-starter:debug-logs');
26+
const timeouts = getTimeouts();
27+
28+
// Setup
29+
logger.info('Setting up wallet and accounts...');
30+
const wallet = await setupWallet();
31+
32+
const sponsoredFPC = await getSponsoredFPCInstance();
33+
await wallet.registerContract(sponsoredFPC, SponsoredFPCContractArtifact);
34+
const paymentMethod = new SponsoredFeePaymentMethod(sponsoredFPC.address);
35+
36+
// Create two player accounts
37+
const p1Account = await wallet.createSchnorrAccount(Fr.random(), Fr.random(), GrumpkinScalar.random());
38+
await (await p1Account.getDeployMethod()).send({
39+
from: AztecAddress.ZERO,
40+
fee: { paymentMethod },
41+
wait: { timeout: timeouts.deployTimeout },
42+
});
43+
44+
const p2Account = await wallet.createSchnorrAccount(Fr.random(), Fr.random(), GrumpkinScalar.random());
45+
await (await p2Account.getDeployMethod()).send({
46+
from: AztecAddress.ZERO,
47+
fee: { paymentMethod },
48+
wait: { timeout: timeouts.deployTimeout },
49+
});
50+
51+
await wallet.registerSender(p1Account.address, 'player1');
52+
await wallet.registerSender(p2Account.address, 'player2');
53+
logger.info(`Player 1: ${p1Account.address}`);
54+
logger.info(`Player 2: ${p2Account.address}`);
55+
56+
// Deploy contract — constructor has debug_log_format
57+
logger.info('\n--- Deploying PodRacing contract (constructor logs) ---');
58+
const deployRequest = PodRacingContract.deploy(wallet, p1Account.address);
59+
await deployRequest.simulate({ from: p1Account.address });
60+
const contract = await deployRequest.send({
61+
from: p1Account.address,
62+
fee: { paymentMethod },
63+
wait: { timeout: timeouts.deployTimeout },
64+
});
65+
logger.info(`Contract deployed at: ${contract.address}`);
66+
67+
const gameId = Fr.random();
68+
const sendOpts = (from: AztecAddress) => ({
69+
from,
70+
fee: { paymentMethod },
71+
wait: { timeout: timeouts.txTimeout },
72+
});
73+
74+
// create_game (public) — logs: "Creating game {0} by player {1}"
75+
logger.info('\n--- create_game (public function logs) ---');
76+
await contract.methods.create_game(gameId).simulate({ from: p1Account.address });
77+
await contract.methods.create_game(gameId).send(sendOpts(p1Account.address));
78+
logger.info('create_game complete');
79+
80+
// join_game (public) — logs: "Player {0} joining game {1}"
81+
logger.info('\n--- join_game (public function logs) ---');
82+
await contract.methods.join_game(gameId).simulate({ from: p2Account.address });
83+
await contract.methods.join_game(gameId).send(sendOpts(p2Account.address));
84+
logger.info('join_game complete');
85+
86+
// play_round (private -> enqueues public) — logs track allocations + validation
87+
const allocations = [
88+
[3, 2, 2, 1, 1],
89+
[1, 1, 3, 2, 2],
90+
[2, 2, 1, 2, 2],
91+
];
92+
93+
for (let round = 1; round <= 3; round++) {
94+
const [t1, t2, t3, t4, t5] = allocations[round - 1];
95+
96+
logger.info(`\n--- play_round ${round} player 1 (private + public logs) ---`);
97+
await contract.methods.play_round(gameId, round, t1, t2, t3, t4, t5).simulate({ from: p1Account.address });
98+
await contract.methods.play_round(gameId, round, t1, t2, t3, t4, t5).send(sendOpts(p1Account.address));
99+
100+
logger.info(`\n--- play_round ${round} player 2 (private + public logs) ---`);
101+
await contract.methods.play_round(gameId, round, t5, t4, t3, t2, t1).simulate({ from: p2Account.address });
102+
await contract.methods.play_round(gameId, round, t5, t4, t3, t2, t1).send(sendOpts(p2Account.address));
103+
}
104+
105+
// finish_game (private -> enqueues public) — logs computed totals + reveal
106+
logger.info('\n--- finish_game player 1 (private + public logs) ---');
107+
await contract.methods.finish_game(gameId).simulate({ from: p1Account.address });
108+
await contract.methods.finish_game(gameId).send(sendOpts(p1Account.address));
109+
110+
logger.info('\n--- finish_game player 2 (private + public logs) ---');
111+
await contract.methods.finish_game(gameId).simulate({ from: p2Account.address });
112+
await contract.methods.finish_game(gameId).send(sendOpts(p2Account.address));
113+
114+
// debug_game_state (utility function) — runs client-side in PXE, not on-chain.
115+
// Calls Race.log_race_state which uses debug_log_format.
116+
// Utility function logs go through the UtilityExecutionOracle and are emitted
117+
// immediately through the structured logger, just like private function logs.
118+
logger.info('\n--- debug_game_state (utility function — runs in PXE) ---');
119+
await contract.methods.debug_game_state(gameId).simulate({ from: p1Account.address });
120+
logger.info('Utility function simulation complete');
121+
122+
logger.info('\n=== Done ===');
123+
logger.info('Utility function debug_log_format calls (debug_game_state) run client-side in');
124+
logger.info('the PXE and their logs appear in stdout via the UtilityExecutionOracle.');
125+
}
126+
127+
main()
128+
.then(() => process.exit(0))
129+
.catch((error) => {
130+
const logger = createLogger('aztec:aztec-starter:debug-logs');
131+
logger.error(`Failed: ${error.message}`);
132+
logger.error(error.stack);
133+
process.exit(1);
134+
});

src/main.nr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,4 +276,14 @@ pub contract PodRacing {
276276
);
277277
self.storage.win_history.at(winner).write(previous_wins + 1);
278278
}
279+
280+
// Utility function: runs client-side in the PXE, not on-chain.
281+
// Reads the public game state and logs it via debug_log_format.
282+
#[external("utility")]
283+
unconstrained fn debug_game_state(game_id: Field) {
284+
let race = self.storage.races.at(game_id).read();
285+
debug_log_format("=== debug_game_state utility for game {0} ===", [game_id]);
286+
race.log_race_state(game_id);
287+
debug_log_format("=== end debug_game_state ===", [game_id]);
288+
}
279289
}

src/race.nr

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use ::aztec::oracle::logging::debug_log_format;
12
use ::aztec::protocol::{
23
address::AztecAddress,
3-
traits::{Deserialize, Serialize, Packable},
4+
traits::{Deserialize, Serialize, Packable, ToField},
45
};
56

67
// Race struct stores the public state of a game
@@ -210,6 +211,45 @@ impl Race {
210211
ret.unwrap()
211212
}
212213

214+
// Logs the full state of a race for debugging
215+
pub fn log_race_state(self, label: Field) {
216+
debug_log_format("=== Race State ({0}) ===", [label]);
217+
debug_log_format(
218+
"Players: p1={0}, p2={1}",
219+
[self.player1.to_field(), self.player2.to_field()],
220+
);
221+
debug_log_format(
222+
"Rounds: p1={0}/{1}, p2={2}/{3}",
223+
[
224+
self.player1_round as Field,
225+
self.total_rounds as Field,
226+
self.player2_round as Field,
227+
self.total_rounds as Field,
228+
],
229+
);
230+
debug_log_format(
231+
"P1 tracks: {0}, {1}, {2}, {3}, {4}",
232+
[
233+
self.player1_track1_final as Field,
234+
self.player1_track2_final as Field,
235+
self.player1_track3_final as Field,
236+
self.player1_track4_final as Field,
237+
self.player1_track5_final as Field,
238+
],
239+
);
240+
debug_log_format(
241+
"P2 tracks: {0}, {1}, {2}, {3}, {4}",
242+
[
243+
self.player2_track1_final as Field,
244+
self.player2_track2_final as Field,
245+
self.player2_track3_final as Field,
246+
self.player2_track4_final as Field,
247+
self.player2_track5_final as Field,
248+
],
249+
);
250+
debug_log_format("End block: {0}", [self.end_block as Field]);
251+
}
252+
213253
// Determines the game winner by comparing track scores
214254
// Winner is whoever won more tracks (best of 5)
215255
//

0 commit comments

Comments
 (0)