Skip to content

Commit 61885a9

Browse files
committed
refactor: drop world_state from AVM fuzzer harness
The fuzzer no longer hands a shared on-disk lmdb between the C++ and TS differential simulators. The C++ FuzzerWorldStateManager now seeds only an in-memory MemoryMerkleDB (genesis 128), and the TS simulator self-bootstraps a fresh NativeWorldStateService.tmp() per process. Both produce an identical genesis by construction (same 128 nullifier/public-data prefill and header-generator point), so the shared database is unnecessary. - FuzzerWorldStateManager: remove the world_state::WorldState member; setup methods apply only to the in-memory DB; fork() re-seeds the DB and checkpoint/commit/revert/reset_world_state become no-ops. - Drop wsDataDir/wsMapSizeKb from the serialized FuzzerSimulationRequest on both sides. - Remove world_state from the avm_fuzzer CMake dependencies.
1 parent 4ad87bc commit 61885a9

8 files changed

Lines changed: 36 additions & 124 deletions

File tree

barretenberg/cpp/src/barretenberg/avm_fuzzer/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ if(FUZZING_AVM)
3030
TEST_SOURCE_FILES ${TEST_SOURCE_FILES}
3131
BENCH_SOURCE_FILES ${BENCH_SOURCE_FILES}
3232
FUZZERS_SOURCE_FILES ${FUZZERS_SOURCE_FILES}
33-
DEPENDENCIES vm2 world_state
33+
DEPENDENCIES vm2
3434
)
3535

3636
# Add the harness subdirectory which will create the alu_fuzzer target

barretenberg/cpp/src/barretenberg/avm_fuzzer/common/interfaces/dbs.cpp

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
using namespace bb::avm2::simulation;
1616
using Poseidon2 = bb::crypto::Poseidon2<bb::crypto::Poseidon2Bn254ScalarFieldParams>;
17-
using namespace bb::world_state;
1817

1918
namespace bb::avm2::fuzzer {
2019

@@ -185,57 +184,25 @@ FuzzerWorldStateManager* FuzzerWorldStateManager::instance = nullptr;
185184

186185
void FuzzerWorldStateManager::initialize_world_state()
187186
{
188-
std::unordered_map<simulation::MerkleTreeId, uint32_t> tree_heights{
189-
{ simulation::MerkleTreeId::NULLIFIER_TREE, NULLIFIER_TREE_HEIGHT },
190-
{ simulation::MerkleTreeId::NOTE_HASH_TREE, NOTE_HASH_TREE_HEIGHT },
191-
{ simulation::MerkleTreeId::PUBLIC_DATA_TREE, PUBLIC_DATA_TREE_HEIGHT },
192-
{ simulation::MerkleTreeId::L1_TO_L2_MESSAGE_TREE, L1_TO_L2_MSG_TREE_HEIGHT },
193-
{ simulation::MerkleTreeId::ARCHIVE, ARCHIVE_HEIGHT },
194-
};
195-
std::unordered_map<simulation::MerkleTreeId, index_t> tree_prefill{
196-
{ simulation::MerkleTreeId::NULLIFIER_TREE, 128 },
197-
{ simulation::MerkleTreeId::PUBLIC_DATA_TREE, 128 },
198-
};
199-
uint32_t initial_header_generator_point = 2064783670; // DomainSeparator.BLOCK_HEADER_HASH
200-
ws = std::make_unique<world_state::WorldState>(
201-
/*thread_pool_size=*/4, DATA_DIR, MAP_SIZE_KB, tree_heights, tree_prefill, initial_header_generator_point);
202-
203187
mem_db = std::make_unique<simulation::MemoryMerkleDB>(
204188
/*nullifier_tree_prefill=*/128, /*public_data_tree_prefill=*/128);
205-
206-
fork_ids.push(ws->create_fork(std::nullopt));
207-
}
208-
209-
WorldStateRevision FuzzerWorldStateManager::get_current_revision() const
210-
{
211-
return WorldStateRevision{ .forkId = fork_ids.top(), .includeUncommitted = true };
212189
}
213190

214-
WorldStateRevision FuzzerWorldStateManager::fork()
191+
void FuzzerWorldStateManager::fork()
215192
{
216-
auto fork_id = ws->create_fork(std::nullopt);
217-
fork_ids.push(fork_id);
218-
// The fuzzer forks once per transaction before applying genesis state, so reset the mirror DB to a
219-
// fresh genesis here. This keeps it in lockstep with the freshly-forked world state.
193+
// The fuzzer forks once per transaction before applying genesis state, so reset the in-memory DB to a
194+
// fresh genesis here. This keeps each input starting from the same state.
220195
mem_db =
221196
std::make_unique<simulation::MemoryMerkleDB>(/*nullifier_tree_prefill=*/128, /*public_data_tree_prefill=*/128);
222-
return WorldStateRevision{ .forkId = fork_id, .includeUncommitted = true };
223-
}
224-
void FuzzerWorldStateManager::reset_world_state()
225-
{
226-
// We keep the initial fork, so pop until only one remains
227-
while (fork_ids.size() != 1) {
228-
ws->delete_fork(fork_ids.top());
229-
fork_ids.pop();
230-
}
231197
}
198+
199+
void FuzzerWorldStateManager::reset_world_state() {}
200+
232201
void FuzzerWorldStateManager::register_contract_address(const AztecAddress& contract_address)
233202
{
234203
NullifierLeafValue contract_nullifier =
235204
unconstrained_silo_nullifier(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, contract_address);
236205
fuzz_info("Registering contract address in world state: ", contract_nullifier.nullifier);
237-
auto fork_id = fork_ids.top();
238-
ws->insert_indexed_leaves<NullifierLeafValue>(MerkleTreeId::NULLIFIER_TREE, { contract_nullifier }, fork_id);
239206
mem_db->insert_indexed_leaves_nullifier_tree(contract_nullifier);
240207
}
241208

@@ -248,28 +215,18 @@ void FuzzerWorldStateManager::write_fee_payer_balance(const AztecAddress& fee_pa
248215
Poseidon2::hash({ DOM_SEP__PUBLIC_STORAGE_MAP_SLOT, FEE_JUICE_BALANCES_SLOT, fee_payer });
249216
FF leaf_slot = Poseidon2::hash({ DOM_SEP__PUBLIC_LEAF_SLOT, FF(FEE_JUICE_ADDRESS), fee_juice_balance_slot });
250217

251-
// Write to public data tree using current fork
252-
auto fork_id = fork_ids.top();
253-
ws->update_public_data(PublicDataLeafValue(leaf_slot, balance), fork_id);
254218
mem_db->insert_indexed_leaves_public_data_tree(PublicDataLeafValue(leaf_slot, balance));
255219
}
256220

257221
void FuzzerWorldStateManager::public_data_write(const bb::crypto::merkle_tree::PublicDataLeafValue& public_data)
258222
{
259-
auto fork_id = fork_ids.top();
260-
ws->update_public_data(public_data, fork_id);
261223
mem_db->insert_indexed_leaves_public_data_tree(public_data);
262224
}
263225

264226
void FuzzerWorldStateManager::append_note_hashes(const std::vector<FF>& note_hashes)
265227
{
266-
auto fork_id = fork_ids.top();
267-
268228
uint64_t padding_leaves = MAX_NOTE_HASHES_PER_TX - (note_hashes.size() % MAX_NOTE_HASHES_PER_TX);
269229

270-
ws->append_leaves(MerkleTreeId::NOTE_HASH_TREE, note_hashes, fork_id);
271-
ws->append_leaves(MerkleTreeId::NOTE_HASH_TREE, std::vector<FF>(padding_leaves, FF(0)), fork_id);
272-
273230
mem_db->append_leaves(simulation::MerkleTreeId::NOTE_HASH_TREE, note_hashes);
274231
mem_db->append_leaves(simulation::MerkleTreeId::NOTE_HASH_TREE, std::vector<FF>(padding_leaves, FF(0)));
275232
}

barretenberg/cpp/src/barretenberg/avm_fuzzer/common/interfaces/dbs.hpp

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
#include <memory>
44
#include <stack>
55

6+
#include "barretenberg/crypto/merkle_tree/indexed_tree/indexed_leaf.hpp"
67
#include "barretenberg/vm2/common/aztec_types.hpp"
78
#include "barretenberg/vm2/simulation/interfaces/db.hpp"
89
#include "barretenberg/vm2/simulation/lib/memory_merkle_db.hpp"
9-
#include "barretenberg/world_state/types.hpp"
10-
#include "barretenberg/world_state/world_state.hpp"
1110

1211
namespace bb::avm2::fuzzer {
1312

@@ -56,19 +55,13 @@ class FuzzerContractDB : public simulation::ContractDBInterface {
5655
std::stack<Checkpoint> checkpoints;
5756
};
5857

59-
// Set up and manage a world state for the fuzzer, the plan is to use this to set up different world states
60-
// This is a bit of hack since we need to access the world state in both cpp and ts. Normally, ws is instantiated
61-
// inside ts and we use napi to access it from cpp, but for the fuzzer we want to instantiate it in cpp and access it
62-
// from ts. The simplest way is to use the same database files from both cpp and ts, this is fine for now since we know
63-
// only one thing will be writing to it at a time.
64-
// FIXME(ilyas): This won't work with multiple concurrent fuzzing processes, but that's ok for now.
58+
// Seeds and manages the genesis state the fuzzer simulates against.
59+
// The C++ simulator runs against copies of the in-memory MemoryMerkleDB seeded here, and the TS
60+
// differential simulator self-bootstraps an identical genesis (a fresh NativeWorldStateService) on its
61+
// side. Both sides use the same 128 nullifier/public-data tree prefill and header-generator point, so the
62+
// genesis states match by construction without any shared on-disk database.
6563
class FuzzerWorldStateManager {
6664
public:
67-
// Shared constants for C++ and TypeScript to use the same database
68-
// Note: TypeScript expects trees in {DATA_DIR}/world_state/, so we include that subdirectory
69-
static constexpr const char* DATA_DIR = "/tmp/avm_fuzzer_ws/world_state";
70-
static constexpr uint64_t MAP_SIZE_KB = 10240; // 10 MB
71-
7265
// Static instance management (similar to JsSimulator pattern)
7366
static void initialize()
7467
{
@@ -92,33 +85,29 @@ class FuzzerWorldStateManager {
9285
void public_data_write(const bb::crypto::merkle_tree::PublicDataLeafValue& public_data);
9386
void append_note_hashes(const std::vector<FF>& note_hashes);
9487

95-
world_state::WorldStateRevision get_current_revision() const;
96-
world_state::WorldStateRevision fork();
97-
world_state::WorldState& get_world_state() { return *ws; }
88+
// Re-seeds the in-memory merkle DB to a fresh genesis. The fuzzer calls this once per transaction
89+
// (before applying that transaction's genesis state) so each input starts from the same state.
90+
void fork();
9891

99-
// The in-memory merkle DB mirrors every genesis mutation applied to the (file-backed) world state.
100-
// The C++ simulator runs against a copy of this DB (so the genesis state is preserved across the
101-
// fast and hint-collecting simulations), while the TS simulator reads the world state from disk.
92+
// The in-memory merkle DB holds the genesis state plus every mutation applied for the current
93+
// transaction. The C++ simulator runs against a copy of this DB so the genesis state is preserved
94+
// across the fast and hint-collecting simulations.
10295
const simulation::MemoryMerkleDB& get_memory_merkle_db() const { return *mem_db; }
10396

104-
void checkpoint() { ws->checkpoint(fork_ids.top()); }
105-
106-
void commit() { ws->commit_checkpoint(fork_ids.top()); }
107-
108-
void revert() { ws->revert_checkpoint(fork_ids.top()); }
97+
// The C++ simulators run against copies of mem_db and never mutate the seed, so the WorldState
98+
// checkpoint/commit/revert dance is no longer needed. Kept as no-ops to preserve the call sites.
99+
void checkpoint() {}
109100

110-
static const char* get_data_dir() { return DATA_DIR; }
101+
void commit() {}
111102

112-
static uint64_t get_map_size_kb() { return MAP_SIZE_KB; }
103+
void revert() {}
113104

114105
private:
115106
static FuzzerWorldStateManager* instance;
116107

117108
void initialize_world_state();
118109

119-
std::unique_ptr<world_state::WorldState> ws;
120110
std::unique_ptr<simulation::MemoryMerkleDB> mem_db;
121-
std::stack<uint64_t> fork_ids;
122111
};
123112

124113
} // namespace bb::avm2::fuzzer

barretenberg/cpp/src/barretenberg/avm_fuzzer/fuzz_lib/simulator.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,11 @@
2222
#include "barretenberg/vm2/simulation/lib/contract_crypto.hpp"
2323
#include "barretenberg/vm2/simulation/lib/serialization.hpp"
2424
#include "barretenberg/vm2/simulation_helper.hpp"
25-
#include "barretenberg/world_state/types.hpp"
26-
#include "barretenberg/world_state/world_state.hpp"
2725

2826
using bb::avm2::GlobalVariables;
2927
using namespace bb::avm2;
3028
using namespace bb::avm2::simulation;
3129
using namespace bb::avm2::fuzzer;
32-
using namespace bb::world_state;
3330

3431
constexpr auto MAX_RETURN_DATA_SIZE_IN_FIELDS = 1024;
3532

@@ -47,8 +44,6 @@ std::string serialize_simulation_request(
4744
std::vector<std::pair<AztecAddress, ContractInstance>> instances_vec = contract_db.get_contract_instances();
4845

4946
FuzzerSimulationRequest request{
50-
.ws_data_dir = FuzzerWorldStateManager::get_data_dir(),
51-
.ws_map_size_kb = FuzzerWorldStateManager::get_map_size_kb(),
5247
.tx = tx,
5348
.globals = globals,
5449
.contract_classes = std::move(classes_vec),

barretenberg/cpp/src/barretenberg/avm_fuzzer/fuzz_lib/simulator.hpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ using namespace bb::avm2;
1818
* Contains all data needed for the TS simulator to execute a transaction.
1919
*/
2020
struct FuzzerSimulationRequest {
21-
std::string ws_data_dir;
22-
uint64_t ws_map_size_kb;
2321
Tx tx;
2422
GlobalVariables globals;
2523
std::vector<ContractClass> contract_classes;
@@ -32,15 +30,8 @@ struct FuzzerSimulationRequest {
3230
// Protocol contracts mapping (canonical address index -> derived address)
3331
ProtocolContracts protocol_contracts;
3432

35-
MSGPACK_CAMEL_CASE_FIELDS(ws_data_dir,
36-
ws_map_size_kb,
37-
tx,
38-
globals,
39-
contract_classes,
40-
contract_instances,
41-
public_data_writes,
42-
note_hashes,
43-
protocol_contracts);
33+
MSGPACK_CAMEL_CASE_FIELDS(
34+
tx, globals, contract_classes, contract_instances, public_data_writes, note_hashes, protocol_contracts);
4435
};
4536

4637
struct SimulatorResult {

barretenberg/cpp/src/barretenberg/avm_fuzzer/fuzzer_lib.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
#include "barretenberg/vm2/tooling/stats.hpp"
2828
#include "barretenberg/vm2/tracegen_helper.hpp"
2929

30+
using namespace bb;
3031
using namespace bb::avm2::fuzzer;
3132
using namespace bb::avm2::simulation;
32-
using namespace bb::world_state;
3333

3434
extern size_t LLVMFuzzerMutate(uint8_t* Data, size_t Size, size_t MaxSize);
3535

yarn-project/simulator/src/public/fuzzing/avm_fuzzer_simulator.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ import { PublicTxSimulator } from '../public_tx_simulator/public_tx_simulator.js
4444
*/
4545
export class FuzzerSimulationRequest {
4646
constructor(
47-
public readonly wsDataDir: string,
48-
public readonly wsMapSizeKb: number,
4947
public readonly tx: AvmTxHint,
5048
public readonly globals: GlobalVariables,
5149
public readonly contractClasses: any[], // Raw, processed by addContractClassFromCpp
@@ -60,8 +58,6 @@ export class FuzzerSimulationRequest {
6058
return obj;
6159
}
6260
return new FuzzerSimulationRequest(
63-
obj.wsDataDir,
64-
obj.wsMapSizeKb,
6561
AvmTxHint.fromPlainObject(obj.tx),
6662
GlobalVariables.fromPlainObject(obj.globals),
6763
obj.contractClasses,

yarn-project/simulator/src/public/fuzzing/avm_simulator_bin.ts

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Fr } from '@aztec/foundation/curves/bn254';
2-
import { EthAddress } from '@aztec/foundation/eth-address';
32
import {
43
AvmCircuitPublicInputs,
54
type AvmTxHint,
@@ -27,31 +26,18 @@ function writeOutput(data: string): Promise<void> {
2726
});
2827
}
2928

30-
// This cache holds opened world states to avoid reopening them for each invocation.
31-
// It's a map so that in the future we could support multiple world states (if we had multiple fuzzers).
32-
const worldStateCache = new Map<string, NativeWorldStateService>();
29+
// The fuzzer self-bootstraps its own world state instead of reading a shared on-disk database written by
30+
// the C++ side. A fresh NativeWorldStateService produces a genesis identical to the C++ MemoryMerkleDB by
31+
// construction (same 128 nullifier/public-data tree prefill and header-generator point), and the dynamic
32+
// state is applied per-input below. The instance is opened once and reused across inputs; each input forks
33+
// from it (in AvmFuzzerSimulator.create).
34+
let worldStatePromise: Promise<NativeWorldStateService> | undefined;
3335

34-
async function openExistingWorldState(dataDir: string, mapSizeKb: number): Promise<NativeWorldStateService> {
35-
const cached = worldStateCache.get(dataDir);
36-
if (cached) {
37-
return cached;
38-
}
39-
40-
const ws = await NativeWorldStateService.new(EthAddress.ZERO, dataDir, {
41-
archiveTreeMapSizeKb: mapSizeKb,
42-
nullifierTreeMapSizeKb: mapSizeKb,
43-
noteHashTreeMapSizeKb: mapSizeKb,
44-
messageTreeMapSizeKb: mapSizeKb,
45-
publicDataTreeMapSizeKb: mapSizeKb,
46-
});
47-
48-
worldStateCache.set(dataDir, ws);
49-
return ws;
36+
function getWorldState(): Promise<NativeWorldStateService> {
37+
return (worldStatePromise ??= NativeWorldStateService.tmp());
5038
}
5139

5240
async function simulateWithFuzzer(
53-
dataDir: string,
54-
mapSizeKb: number,
5541
txHint: AvmTxHint,
5642
globals: GlobalVariables,
5743
rawContractClasses: any[], // Replace these when we are moving contract classes to TS
@@ -66,7 +52,7 @@ async function simulateWithFuzzer(
6652
publicInputs: AvmCircuitPublicInputs;
6753
publicTxEffect: PublicTxEffect;
6854
}> {
69-
const worldStateService = await openExistingWorldState(dataDir, mapSizeKb);
55+
const worldStateService = await getWorldState();
7056

7157
const simulator = await AvmFuzzerSimulator.create(worldStateService, globals, protocolContracts);
7258

@@ -110,8 +96,6 @@ async function execute(base64Line: string): Promise<void> {
11096

11197
// Run the TS simulation
11298
const result = await simulateWithFuzzer(
113-
request.wsDataDir,
114-
request.wsMapSizeKb,
11599
request.tx,
116100
request.globals,
117101
request.contractClasses,

0 commit comments

Comments
 (0)