Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions barretenberg/cpp/src/barretenberg/world_state/world_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ WorldState::WorldState(uint64_t thread_pool_size,
const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
const std::vector<PublicDataLeafValue>& prefilled_public_data,
const std::vector<bb::fr>& prefilled_nullifiers,
uint32_t initial_header_generator_point,
uint64_t genesis_timestamp,
bool ephemeral)
Expand All @@ -51,7 +52,7 @@ WorldState::WorldState(uint64_t thread_pool_size,
{
// We set the max readers to be high, at least the number of given threads or the default if higher
uint64_t maxReaders = std::max(thread_pool_size, DEFAULT_MIN_NUMBER_OF_READERS);
create_canonical_fork(data_dir, map_size, prefilled_public_data, maxReaders, ephemeral);
create_canonical_fork(data_dir, map_size, prefilled_public_data, prefilled_nullifiers, maxReaders, ephemeral);
try {
attempt_tree_resync();
} catch (std::exception& e) {
Expand All @@ -73,6 +74,7 @@ WorldState::WorldState(uint64_t thread_pool_size,
tree_heights,
tree_prefill,
std::vector<PublicDataLeafValue>(),
std::vector<bb::fr>(),
initial_header_generator_point,
genesis_timestamp,
ephemeral)
Expand All @@ -84,6 +86,7 @@ WorldState::WorldState(uint64_t thread_pool_size,
const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
const std::vector<PublicDataLeafValue>& prefilled_public_data,
const std::vector<bb::fr>& prefilled_nullifiers,
uint32_t initial_header_generator_point,
uint64_t genesis_timestamp,
bool ephemeral)
Expand All @@ -99,6 +102,7 @@ WorldState::WorldState(uint64_t thread_pool_size,
tree_heights,
tree_prefill,
prefilled_public_data,
prefilled_nullifiers,
initial_header_generator_point,
genesis_timestamp,
ephemeral)
Expand All @@ -118,6 +122,7 @@ WorldState::WorldState(uint64_t thread_pool_size,
tree_heights,
tree_prefill,
std::vector<PublicDataLeafValue>(),
std::vector<bb::fr>(),
initial_header_generator_point,
genesis_timestamp,
ephemeral)
Expand All @@ -126,6 +131,7 @@ WorldState::WorldState(uint64_t thread_pool_size,
void WorldState::create_canonical_fork(const std::string& dataDir,
const std::unordered_map<MerkleTreeId, uint64_t>& dbSize,
const std::vector<PublicDataLeafValue>& prefilled_public_data,
const std::vector<bb::fr>& prefilled_nullifiers,
uint64_t maxReaders,
bool ephemeral)
{
Expand All @@ -148,9 +154,15 @@ void WorldState::create_canonical_fork(const std::string& dataDir,
{
uint32_t levels = _tree_heights.at(MerkleTreeId::NULLIFIER_TREE);
index_t initial_size = _initial_tree_size.at(MerkleTreeId::NULLIFIER_TREE);
std::vector<NullifierLeafValue> prefilled_nullifier_leaves;
prefilled_nullifier_leaves.reserve(prefilled_nullifiers.size());
for (const auto& nullifier : prefilled_nullifiers) {
prefilled_nullifier_leaves.emplace_back(nullifier);
}
auto store = std::make_unique<NullifierStore>(
getMerkleTreeName(MerkleTreeId::NULLIFIER_TREE), levels, _persistentStores->nullifierStore);
auto tree = std::make_unique<NullifierTree>(std::move(store), _workers, initial_size);
auto tree =
std::make_unique<NullifierTree>(std::move(store), _workers, initial_size, prefilled_nullifier_leaves);
fork->_trees.insert({ MerkleTreeId::NULLIFIER_TREE, TreeWithStore(std::move(tree)) });
}
{
Expand Down
6 changes: 6 additions & 0 deletions barretenberg/cpp/src/barretenberg/world_state/world_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,15 @@ class WorldState {
const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
const std::vector<PublicDataLeafValue>& prefilled_public_data,
const std::vector<bb::fr>& prefilled_nullifiers,
uint32_t initial_header_generator_point,
uint64_t genesis_timestamp = 0,
bool ephemeral = false);

/**
* @param prefilled_nullifiers Nullifier leaves to pre-insert into the genesis nullifier tree (e.g. the protocol
* contract registration nullifiers). Must be unique and strictly increasing in field value, and
* distinct from the padding leaves implied by the nullifier tree prefill size.
* @param ephemeral When true, every underlying LMDB env opens with `MDB_NOSYNC |
* MDB_NOMETASYNC`. Commits return without waiting for fsync; the kernel
* flushes lazily, files stay sparse. Intended for throwaway scratch
Expand All @@ -99,6 +103,7 @@ class WorldState {
const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
const std::vector<PublicDataLeafValue>& prefilled_public_data,
const std::vector<bb::fr>& prefilled_nullifiers,
uint32_t initial_header_generator_point,
uint64_t genesis_timestamp = 0,
bool ephemeral = false);
Expand Down Expand Up @@ -326,6 +331,7 @@ class WorldState {
void create_canonical_fork(const std::string& dataDir,
const std::unordered_map<MerkleTreeId, uint64_t>& dbSize,
const std::vector<PublicDataLeafValue>& prefilled_public_data,
const std::vector<bb::fr>& prefilled_nullifiers,
uint64_t maxReaders,
bool ephemeral);

Expand Down
52 changes: 52 additions & 0 deletions barretenberg/cpp/src/barretenberg/world_state/world_state.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,57 @@ TEST_F(WorldStateTest, GetInitialTreeInfoForAllTrees)
}
}

TEST_F(WorldStateTest, GetInitialTreeInfoWithPrefilledNullifiers)
{
// Prefilled nullifier leaves must be unique and strictly increasing, and larger than the padding leaves that fill
// the initial 128-leaf prefill region (whose keys are the low integers 0..127), so we use full-size field values.
std::vector<bb::fr> prefilled_nullifiers = {
bb::fr("0x073b5e41abe9d7f8466bca9c81c9572b558f953bbd70081317f6a80ac65f3dd5"),
bb::fr("0x0d99507b7ecac720c73bf197a0e7366a5ed80c1c1b0afe8ff8c6ecc7b5a7aefe"),
bb::fr("0x1c0bf82e0c51834780e61ef091b17e3a1d39ae891db7a70bfdb5221f134996ac"),
};

std::string data_dir_prefilled = random_temp_directory();
std::filesystem::create_directories(data_dir_prefilled);

WorldState ws_prefilled(thread_pool_size,
data_dir_prefilled,
map_size,
tree_heights,
tree_prefill,
std::vector<PublicDataLeafValue>(),
prefilled_nullifiers,
initial_header_generator_point);

// Baseline world state with no prefilled nullifiers (the canonical empty genesis).
WorldState ws(thread_pool_size, data_dir, map_size, tree_heights, tree_prefill, initial_header_generator_point);

auto prefilled = ws_prefilled.get_tree_info(WorldStateRevision::committed(), MerkleTreeId::NULLIFIER_TREE);
auto info = ws.get_tree_info(WorldStateRevision::committed(), MerkleTreeId::NULLIFIER_TREE);

// The prefilled nullifiers occupy the last slots of the 128-leaf initial prefill region (they replace padding
// leaves rather than being appended), so the tree size stays 128 for both.
EXPECT_EQ(prefilled.meta.size, 128);
EXPECT_EQ(info.meta.size, 128);

// Seeding the nullifiers changes the nullifier-tree root away from the empty-genesis baseline.
EXPECT_NE(prefilled.meta.root, info.meta.root);
// The empty-genesis baseline root is unchanged from the canonical value, confirming that a default (empty)
// prefilled-nullifiers list leaves the genesis nullifier-tree root bit-identical to today.
EXPECT_EQ(info.meta.root, bb::fr("0x18935581a8ed73d08ffd00386fba55ba6c89f3ab848a76b8fedfa9034cee0454"));

// The seeded nullifiers are present in the tree.
for (const auto& nullifier : prefilled_nullifiers) {
assert_leaf_exists<NullifierLeafValue>(ws_prefilled,
WorldStateRevision::committed(),
MerkleTreeId::NULLIFIER_TREE,
NullifierLeafValue(nullifier),
true);
}

std::filesystem::remove_all(data_dir_prefilled);
}

TEST_F(WorldStateTest, GetInitialTreeInfoWithPrefilledPublicData)
{
std::string data_dir_prefilled = random_temp_directory();
Expand All @@ -225,6 +276,7 @@ TEST_F(WorldStateTest, GetInitialTreeInfoWithPrefilledPublicData)
tree_heights,
tree_prefill,
prefilled_values,
std::vector<bb::fr>(),
initial_header_generator_point);

WorldState ws(thread_pool_size, data_dir, map_size, tree_heights, tree_prefill, initial_header_generator_point);
Expand Down
6 changes: 6 additions & 0 deletions barretenberg/cpp/src/barretenberg/wsdb/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ int parse_and_run_wsdb(int argc, char* argv[])
msgpack_run_command->add_option(
"--prefilled-public-data", prefilled_public_data_json, "Prefilled public data as JSON array");

// Prefilled nullifiers as JSON array of nullifier_hex strings
std::string prefilled_nullifiers_json;
msgpack_run_command->add_option(
"--prefilled-nullifiers", prefilled_nullifiers_json, "Prefilled genesis nullifiers as JSON array");

uint64_t genesis_timestamp = 0;
msgpack_run_command->add_option("--genesis-timestamp", genesis_timestamp, "Genesis block timestamp (default: 0)");

Expand Down Expand Up @@ -98,6 +103,7 @@ int parse_and_run_wsdb(int argc, char* argv[])
threads,
initial_header_generator_point,
prefilled_public_data_json,
prefilled_nullifiers_json,
genesis_timestamp,
request_ring_size,
response_ring_size);
Expand Down
38 changes: 38 additions & 0 deletions barretenberg/cpp/src/barretenberg/wsdb/wsdb_ipc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,34 @@ static std::vector<PublicDataLeafValue> parse_prefilled_public_data(const std::s
return result;
}

// ---------------------------------------------------------------------------
// Parse prefilled nullifiers from JSON: ["nullifier_hex",...]
// Each hex string is a 64-char (32-byte) hex-encoded field element.
// ---------------------------------------------------------------------------

static std::vector<fr> parse_prefilled_nullifiers(const std::string& json)
{
std::vector<fr> result;
if (json.empty() || json == "[]") {
return result;
}

std::string current;
bool in_string = false;

for (char c : json) {
if (c == '"') {
in_string = !in_string;
} else if (in_string) {
current += c;
} else if ((c == ',' || c == ']') && !current.empty()) {
result.push_back(hex_to_fr(current));
current.clear();
}
}
return result;
}

// ---------------------------------------------------------------------------
// IPC server execution
// ---------------------------------------------------------------------------
Expand All @@ -142,6 +170,7 @@ int execute_wsdb_server(const std::string& input_path,
uint32_t threads,
uint32_t initial_header_generator_point,
const std::string& prefilled_public_data_json,
const std::string& prefilled_nullifiers_json,
uint64_t genesis_timestamp,
size_t request_ring_size,
size_t response_ring_size)
Expand Down Expand Up @@ -173,6 +202,14 @@ int execute_wsdb_server(const std::string& input_path,
std::cerr << "Parsed " << prefilled_public_data.size() << " prefilled public data entries" << '\n';
}

// Parse prefilled nullifiers: JSON array of "nullifier_hex" strings. The caller (TS world-state) passes the same
// canonical genesis nullifiers it seeds via the napi path, so the IPC genesis nullifier-tree root matches.
std::vector<bb::fr> prefilled_nullifiers;
if (!prefilled_nullifiers_json.empty()) {
prefilled_nullifiers = parse_prefilled_nullifiers(prefilled_nullifiers_json);
std::cerr << "Parsed " << prefilled_nullifiers.size() << " prefilled nullifiers" << '\n';
}

// Create WorldState
std::cerr << "Creating WorldState at " << data_dir << " with " << threads << " threads" << '\n';
auto ws = std::make_unique<WorldState>(threads,
Expand All @@ -181,6 +218,7 @@ int execute_wsdb_server(const std::string& input_path,
tree_height,
tree_prefill,
prefilled_public_data,
prefilled_nullifiers,
initial_header_generator_point,
genesis_timestamp);

Expand Down
1 change: 1 addition & 0 deletions barretenberg/cpp/src/barretenberg/wsdb/wsdb_ipc_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ int execute_wsdb_server(const std::string& input_path,
uint32_t threads,
uint32_t initial_header_generator_point,
const std::string& prefilled_public_data_json,
const std::string& prefilled_nullifiers_json,
uint64_t genesis_timestamp,
size_t request_ring_size,
size_t response_ring_size);
Expand Down
2 changes: 0 additions & 2 deletions docs/docs-developers/docs/resources/migration_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,6 @@ Registering classes and instances are now separate, unvalidated operations. `reg
The new class is used automatically once the upgrade takes effect on chain; no further PXE action is needed. Registering it beforehand is harmless: until the update activates, the node still resolves the contract's current class to the previous one, so it keeps running its old code.

- `pxe.getContractInstance(address)` and `wallet.getContractMetadata(address).instance` now return the contract's **address preimage**, which no longer includes `currentContractClassId`.


### [Aztec.js] `AccountWithSecretKey` removed, read account keys from the `AccountManager` or PXE

`AccountWithSecretKey` was a thin wrapper that bundled an account's transaction signer with its master secret key, used mainly to print or export the secret. It has been removed, and `AccountManager.getAccount()` now returns the plain `Account` signer. The wrapper's extra methods are no longer available on that value:
Expand Down
11 changes: 11 additions & 0 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -538,11 +538,22 @@ impl PrivateContext {
/// Only one contract per transaction can declare itself as the fee payer, and it must have sufficient fee-juice
/// balance (>= the gas limits specified in the TxContext) by the time we reach the public setup phase of the tx.
///
/// The fee payer must be elected during the setup (non-revertible) phase, i.e. before
/// [`end_setup`](PrivateContext::end_setup) is called - this function asserts so. This is because any compensation
/// collected by the fee payer during the revertible phase can be discarded if a public call later reverts, while
/// the protocol still debits the fee payer's fee-juice balance. Note that `end_setup` does not need to be called
/// by the electing function itself: it can be called later in the transaction (e.g. by the fee-juice contract when
/// claiming fee juice that pays for the very same transaction).
pub fn set_as_fee_payer(&mut self) {
assert(!self.in_revertible_phase(), "fee payer must be elected during the setup phase");
aztecnr_trace_log_format!("Setting {0} as fee payer")([self.this_address().to_field()]);
self.is_fee_payer = true;
}

/// Returns whether execution is currently in the revertible (app) phase of the transaction.
///
/// A transaction is in the revertible phase if [`end_setup`](PrivateContext::end_setup) has already been called -
/// potentially by a different function of the same transaction.
pub fn in_revertible_phase(&mut self) -> bool {
let current_counter = self.side_effect_counter;

Expand Down
Loading
Loading