Skip to content

Commit 1c44c09

Browse files
committed
feat: migrate to the C++ AVM simulator
1 parent fb72ed0 commit 1c44c09

File tree

25 files changed

+564
-532
lines changed

25 files changed

+564
-532
lines changed

barretenberg/cpp/src/barretenberg/vm2/avm_api.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,38 @@ using namespace bb::avm2::simulation;
1313
std::pair<AvmAPI::AvmProof, AvmAPI::AvmVerificationKey> AvmAPI::prove(const AvmAPI::ProvingInputs& inputs)
1414
{
1515
// Simulate.
16-
info("Simulating...");
16+
vinfo("Simulating...");
1717
AvmSimulationHelper simulation_helper;
1818

1919
auto events = AVM_TRACK_TIME_V("simulation/all", simulation_helper.simulate_for_witgen(inputs.hints));
2020

2121
// Generate trace.
22-
info("Generating trace...");
22+
vinfo("Generating trace...");
2323
AvmTraceGenHelper tracegen_helper;
2424
auto trace =
2525
AVM_TRACK_TIME_V("tracegen/all", tracegen_helper.generate_trace(std::move(events), inputs.public_inputs));
2626

2727
// Prove.
28-
info("Proving...");
28+
vinfo("Proving...");
2929
AvmProvingHelper proving_helper;
3030
auto [proof, vk] = AVM_TRACK_TIME_V("proving/all", proving_helper.prove(std::move(trace)));
3131

32-
info("Done!");
32+
vinfo("Done!");
3333
return { std::move(proof), std::move(vk) };
3434
}
3535

3636
bool AvmAPI::check_circuit(const AvmAPI::ProvingInputs& inputs)
3737
{
3838
// Simulate.
39-
info("Simulating...");
39+
vinfo("Simulating...");
4040
AvmSimulationHelper simulation_helper;
4141

4242
auto events = AVM_TRACK_TIME_V("simulation/all", simulation_helper.simulate_for_witgen(inputs.hints));
4343

4444
// Generate trace.
4545
// In contrast to proving, we do this step by step since it's usually more useful to debug
4646
// before trying to run the interaction builders.
47-
info("Generating trace...");
47+
vinfo("Generating trace...");
4848
AvmTraceGenHelper tracegen_helper;
4949
tracegen::TraceContainer trace;
5050
AVM_TRACK_TIME("tracegen/all", tracegen_helper.fill_trace_columns(trace, std::move(events), inputs.public_inputs));
@@ -58,25 +58,25 @@ bool AvmAPI::check_circuit(const AvmAPI::ProvingInputs& inputs)
5858
AVM_TRACK_TIME("tracegen/all", tracegen_helper.fill_trace_interactions(trace));
5959

6060
// Check circuit.
61-
info("Checking circuit...");
61+
vinfo("Checking circuit...");
6262
AvmProvingHelper proving_helper;
6363
return proving_helper.check_circuit(std::move(trace));
6464
}
6565

6666
bool AvmAPI::verify(const AvmProof& proof, const PublicInputs& pi, const AvmVerificationKey& vk_data)
6767
{
68-
info("Verifying...");
68+
vinfo("Verifying...");
6969
AvmProvingHelper proving_helper;
7070
return AVM_TRACK_TIME_V("verifing/all", proving_helper.verify(proof, pi, vk_data));
7171
}
7272

7373
AvmAPI::AvmVerificationKey AvmAPI::get_verification_key()
7474
{
75-
info("Generating trace...");
75+
vinfo("Generating trace...");
7676
AvmTraceGenHelper tracegen_helper;
7777
auto trace = tracegen_helper.generate_precomputed_columns();
7878

79-
info("Computing verification key...");
79+
vinfo("Computing verification key...");
8080
AvmProvingHelper proving_helper;
8181
return proving_helper.compute_verification_key(trace);
8282
}

barretenberg/cpp/src/barretenberg/vm2/avm_sim_api.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ TxSimulationResult AvmSimAPI::simulate(const FastSimulationInputs& inputs,
1212
simulation::ContractDBInterface& contract_db,
1313
world_state::WorldState& ws)
1414
{
15-
info("Simulating...");
15+
vinfo("Simulating...");
1616
AvmSimulationHelper simulation_helper;
1717
// TODO(MW): Add hint checks here
1818
return AVM_TRACK_TIME_V("simulation/all",
@@ -27,7 +27,7 @@ TxSimulationResult AvmSimAPI::simulate(const FastSimulationInputs& inputs,
2727

2828
TxSimulationResult AvmSimAPI::simulate_with_hinted_dbs(const ProvingInputs& inputs)
2929
{
30-
info("Simulating...");
30+
vinfo("Simulating...");
3131
AvmSimulationHelper simulation_helper;
3232
auto result = AVM_TRACK_TIME_V("simulation/all", simulation_helper.simulate_fast_with_hinted_dbs(inputs.hints));
3333

barretenberg/cpp/src/barretenberg/vm2/simulation/lib/call_stack_metadata_collector.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,24 +163,23 @@ ReturnDataProvider make_return_data_provider(const ContextInterface& context, ui
163163
try {
164164
const auto& memory = context.get_memory();
165165
std::vector<FF> data;
166-
info("Collecting returndata rd_offset:", rd_offset, " rd_size:", rd_size, " max_size:", max_size, ")");
167166
data.reserve(std::min(max_size, rd_size));
168167
for (uint32_t i = 0; i < std::min(max_size, rd_size); i++) {
169168
data.push_back(memory.get(rd_offset + i).as_ff());
170169
}
171170
return data;
172171
} catch (...) {
173-
info("Failed to collect returndata (to:",
174-
context.get_address(),
175-
" pc:",
176-
context.get_pc(),
177-
" rd_offset:",
178-
rd_offset,
179-
" rd_size:",
180-
rd_size,
181-
" max_size:",
182-
max_size,
183-
")");
172+
vinfo("Failed to collect returndata (to:",
173+
context.get_address(),
174+
" pc:",
175+
context.get_pc(),
176+
" rd_offset:",
177+
rd_offset,
178+
" rd_size:",
179+
rd_size,
180+
" max_size:",
181+
max_size,
182+
")");
184183
return {};
185184
}
186185
};
Binary file not shown.

yarn-project/bb-prover/src/avm_proving_tests/avm_proving_tester.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
type TestPrivateInsertions,
99
} from '@aztec/simulator/public/fixtures';
1010
import type { PublicTxResult } from '@aztec/simulator/server';
11-
import { AvmCircuitInputs, AvmCircuitPublicInputs } from '@aztec/stdlib/avm';
11+
import { AvmCircuitInputs, AvmCircuitPublicInputs, PublicSimulatorConfig } from '@aztec/stdlib/avm';
1212
import { AztecAddress } from '@aztec/stdlib/aztec-address';
1313
import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
1414
import type { GlobalVariables } from '@aztec/stdlib/tx';
@@ -88,6 +88,15 @@ class InterceptingLogger implements Logger {
8888
}
8989
}
9090

91+
// Config with collectHints enabled for proving tests
92+
const provingConfig: PublicSimulatorConfig = PublicSimulatorConfig.from({
93+
skipFeeEnforcement: false,
94+
collectCallMetadata: true,
95+
collectDebugLogs: false,
96+
collectHints: true, // Required for proving!
97+
collectStatistics: false,
98+
});
99+
91100
export class AvmProvingTester extends PublicTxSimulationTester {
92101
private bbWorkingDirectory: string = '';
93102

@@ -98,7 +107,7 @@ export class AvmProvingTester extends PublicTxSimulationTester {
98107
globals?: GlobalVariables,
99108
metrics?: TestExecutorMetrics,
100109
) {
101-
super(merkleTrees, contractDataSource, globals, metrics);
110+
super(merkleTrees, contractDataSource, globals, metrics, undefined, provingConfig);
102111
}
103112

104113
static async new(

yarn-project/end-to-end/src/e2e_avm_simulator.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ describe('e2e_avm_simulator', () => {
197197
// The nested call reverts and by default caller rethrows
198198
await expect(
199199
avmContract.methods.nested_call_to_nothing().simulate({ from: defaultAccountAddress }),
200-
).rejects.toThrow(/No bytecode/);
200+
).rejects.toThrow(/not deployed/);
201201
});
202202

203203
it('Nested CALL instruction to non-existent contract returns failure, but caller can recover', async () => {

yarn-project/end-to-end/src/e2e_block_building.test.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ import { StatefulTestContract } from '@aztec/noir-test-contracts.js/StatefulTest
1616
import { TestContract } from '@aztec/noir-test-contracts.js/Test';
1717
import type { BlockBuilder, SequencerClient } from '@aztec/sequencer-client';
1818
import type { TestSequencerClient } from '@aztec/sequencer-client/test';
19-
import { Set } from '@aztec/simulator/public/avm/opcodes';
20-
import { type PublicTxResult, PublicTxSimulator } from '@aztec/simulator/server';
19+
import type { PublicTxResult, PublicTxSimulatorInterface } from '@aztec/simulator/server';
2120
import { getProofSubmissionDeadlineEpoch } from '@aztec/stdlib/epoch-helpers';
2221
import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
2322
import { TX_ERROR_EXISTING_NULLIFIER, type Tx } from '@aztec/stdlib/tx';
@@ -558,30 +557,31 @@ describe('e2e_block_building', () => {
558557
]);
559558
const batches = times(2, makeBatch);
560559

561-
// This is embarrassingly brittle. What we want to do here is: we want the sequencer to wait until both
562-
// txs have arrived (so minTxsPerBlock=2), but agree to build a block with 1 tx only, so we change the config
563-
// to minTxsPerBlock=1 as soon as we start processing. We also want to simulate an AVM failure in tx processing
564-
// for only one of the txs, and near the end so all nullifiers have been emitted. So we throw on one of the last
565-
// calls to SET. Note that this will break on brillig or AVM changes that change how many SET operations we use.
566-
let setCount = 0;
567-
const origExecute = Set.prototype.execute;
568-
const spy = jest.spyOn(Set.prototype, 'execute').mockImplementation(async function (...args: any[]) {
569-
setCount++;
570-
if (setCount === 1) {
571-
context.sequencer?.updateConfig({ minTxsPerBlock: 1 });
572-
} else if (setCount === 48) {
573-
throw new Error('Simulated failure in AVM opcode SET');
574-
}
575-
// @ts-expect-error: eslint-be-happy
576-
await origExecute.call(this, ...args);
577-
});
560+
// We want the sequencer to wait until both txs have arrived (so minTxsPerBlock=2), but agree to build
561+
// a block with 1 tx only, so we change the config to minTxsPerBlock=1 as soon as we start processing.
562+
// We also want to simulate an AVM failure in tx processing for only one of the txs.
563+
let simulateCount = 0;
564+
interceptTxProcessorSimulate(
565+
aztecNode as AztecNodeService,
566+
async (tx: Tx, originalSimulate: (tx: Tx) => Promise<PublicTxResult>) => {
567+
simulateCount++;
568+
if (simulateCount === 1) {
569+
context.sequencer?.updateConfig({ minTxsPerBlock: 1 });
570+
}
571+
const result = await originalSimulate(tx);
572+
if (simulateCount === 2) {
573+
throw new Error('Simulated failure in public tx simulation');
574+
}
575+
return result;
576+
},
577+
);
578578

579579
const txs = await Promise.all(batches.map(batch => batch.send({ from: ownerAddress })));
580580
logger.warn(`Sent two txs to test contract`, { txs: await Promise.all(txs.map(tx => tx.getTxHash())) });
581581
await Promise.race(txs.map(tx => tx.wait({ timeout: 60 })));
582582

583-
logger.warn(`At least one tx has been mined (after ${spy.mock.calls.length} AVM SET invocations)`);
584-
expect(setCount).toBeGreaterThanOrEqual(48);
583+
logger.warn(`At least one tx has been mined (after ${simulateCount} public tx simulations)`);
584+
expect(simulateCount).toBeGreaterThanOrEqual(2);
585585
const lastBlock = await context.aztecNode.getBlockHeader();
586586
expect(lastBlock).toBeDefined();
587587

@@ -692,7 +692,7 @@ describe('e2e_block_building', () => {
692692
.mockImplementation(async (...args: Parameters<BlockBuilder['makeBlockBuilderDeps']>) => {
693693
logger.warn('Creating mocked public tx simulator');
694694
const deps = await originalCreateDeps(...args);
695-
const simulator: PublicTxSimulator = (deps.processor as any).publicTxSimulator;
695+
const simulator: PublicTxSimulatorInterface = (deps.processor as any).publicTxSimulator;
696696
const originalSimulate = simulator.simulate.bind(simulator);
697697
jest.spyOn(simulator, 'simulate').mockImplementation((tx: Tx) => stub(tx, originalSimulate));
698698
return deps;

yarn-project/end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ describe('e2e_deploy_contract contract class registration', () => {
311311
// Confirm that the tx reverts with the expected message
312312
await expect(
313313
instance.methods.increment_public_value_no_init_check(whom, 10).simulate({ from: defaultAccountAddress }),
314-
).rejects.toThrow(/No bytecode/);
314+
).rejects.toThrow(/not deployed/);
315315
// This time, don't throw on revert and confirm that the tx is included
316316
// despite reverting in app logic because of the call to a non-existent contract
317317
const tx = await instance.methods

yarn-project/end-to-end/src/e2e_p2p/reex.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { sleep } from '@aztec/foundation/sleep';
77
import { unfreeze } from '@aztec/foundation/types';
88
import type { LibP2PService, P2PClient } from '@aztec/p2p';
99
import type { BlockBuilder } from '@aztec/sequencer-client';
10-
import type { PublicTxResult, PublicTxSimulator } from '@aztec/simulator/server';
10+
import type { CppPublicTxSimulator, PublicTxResult } from '@aztec/simulator/server';
1111
import { BlockProposal, SignatureDomainSeparator, getHashedSignaturePayload } from '@aztec/stdlib/p2p';
1212
import { ReExFailedTxsError, ReExStateMismatchError, ReExTimeoutError } from '@aztec/stdlib/validators';
1313
import type { ValidatorClient, ValidatorKeyStore } from '@aztec/validator-client';
@@ -167,7 +167,7 @@ describe('e2e_p2p_reex', () => {
167167
.mockImplementation(async (...args: Parameters<BlockBuilder['makeBlockBuilderDeps']>) => {
168168
const deps = await originalCreateDeps(...args);
169169
t.logger.warn('Creating mocked processor factory');
170-
const simulator: PublicTxSimulator = (deps.processor as any).publicTxSimulator;
170+
const simulator: CppPublicTxSimulator = (deps.processor as any).publicTxSimulator;
171171
const originalSimulate = simulator.simulate.bind(simulator);
172172
// We only stub the simulate method if it's NOT the first time we see the tx
173173
// so the proposer works fine, but we cause the failure in the validators.

yarn-project/sequencer-client/src/sequencer/block_builder.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
GuardedMerkleTreeOperations,
1212
PublicContractsDB,
1313
PublicProcessor,
14-
TelemetryPublicTxSimulator,
14+
TelemetryCppPublicTxSimulator,
1515
} from '@aztec/simulator/server';
1616
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
1717
import type { ContractDataSource } from '@aztec/stdlib/contract';
@@ -121,7 +121,7 @@ export class FullNodeBlockBuilder implements IFullNodeBlockBuilder {
121121
const contractsDB = new PublicContractsDB(this.contractDataSource);
122122
const guardedFork = new GuardedMerkleTreeOperations(fork);
123123

124-
const publicTxSimulator = new TelemetryPublicTxSimulator(
124+
const publicTxSimulator = new TelemetryCppPublicTxSimulator(
125125
guardedFork,
126126
contractsDB,
127127
globalVariables,

0 commit comments

Comments
 (0)