28#include <unordered_map>
37 const std::string& data_dir,
39 const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
40 const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
42 uint32_t initial_header_generator_point)
44 , _tree_heights(tree_heights)
45 , _initial_tree_size(tree_prefill)
47 , _initial_header_generator_point(initial_header_generator_point)
54 }
catch (std::exception& e) {
60 const std::string& data_dir,
62 const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
63 const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
64 uint32_t initial_header_generator_point)
71 initial_header_generator_point)
75 const std::string& data_dir,
77 const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
78 const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
80 uint32_t initial_header_generator_point)
92 prefilled_public_data,
93 initial_header_generator_point)
97 const std::string& data_dir,
99 const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
100 const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
101 uint32_t initial_header_generator_point)
108 initial_header_generator_point)
119 std::filesystem::path directory = dataDir;
121 std::filesystem::create_directories(directory);
171 _forks[fork->_forkId] = fork;
177 std::filesystem::path directory = dstPath;
178 directory /= store->get_name();
179 std::filesystem::create_directories(directory);
180 store->copy_store(directory, compact);
188 std::unique_lock lock(
mtx);
189 auto it =
_forks.find(forkId);
191 throw std::runtime_error(
"Fork not found");
198 if (!blockNumber.has_value()) {
204 blockNumberForFork = blockNumber.value();
207 std::unique_lock lock(
mtx);
209 fork->_forkId = forkId;
219 std::unique_lock lock(
mtx);
221 if (it->second->_blockNumber == blockNumber) {
222 forks.push_back(it->second);
235 throw std::runtime_error(
"Unable to delete canonical fork");
241 std::unique_lock lock(
mtx);
249 fork->_blockNumber = blockNumber;
296 [=](
auto&& wrapper) {
313 throw std::runtime_error(local.
message);
317 fork->_trees.at(tree_id));
329 Signal signal(
static_cast<uint32_t
>(tree_ids.size()));
333 for (
auto id : tree_ids) {
334 const auto& tree = fork->_trees.at(
id);
343 [&callback, &revision](
auto&& wrapper) {
345 wrapper.tree->get_meta_data(revision.blockNumber, revision.includeUncommitted, callback);
347 wrapper.tree->get_meta_data(revision.includeUncommitted, callback);
355 for (
auto tree_id : tree_ids) {
356 auto& m = local[tree_id];
358 throw std::runtime_error(m.message);
380 if (fork->_forkId != revision.
forkId) {
381 throw std::runtime_error(
"Fork does not match revision");
391 Signal signal(
static_cast<uint32_t
>(tree_ids.size()));
394 std::mutex state_ref_mutex;
396 for (
auto id : tree_ids) {
397 const auto& tree = fork->_trees.at(
id);
406 [&callback, &revision](
auto&& wrapper) {
408 wrapper.tree->get_meta_data(revision.blockNumber, revision.includeUncommitted, callback);
410 wrapper.tree->get_meta_data(revision.includeUncommitted, callback);
418 for (
auto tree_id : tree_ids) {
419 auto& m = local[tree_id];
421 throw std::runtime_error(m.message);
424 state_reference[tree_id] =
std::make_pair(m.inner.meta.initialRoot, m.inner.meta.initialSize);
427 state_reference[tree_id] =
std::make_pair(m.inner.meta.root, m.inner.meta.size);
430 return state_reference;
440 [leaf_index, revision](
auto&& wrapper) {
457 throw std::runtime_error(local.
message);
459 return local.
inner.path;
461 fork->_trees.at(tree_id));
466 const std::vector<index_t>& leafIndices,
472 [&leafIndices, revision, &blockNumbers](
auto&& wrapper) {
482 wrapper.tree->find_block_numbers(leafIndices, revision.
blockNumber, callback);
484 wrapper.tree->find_block_numbers(leafIndices, callback);
489 throw std::runtime_error(local.
message);
493 fork->_trees.at(tree_id));
499 if (
const auto* wrapper =
502 wrapper->tree->add_or_update_value(
507 throw std::runtime_error(
"Invalid tree type for PublicDataTree");
512 const bb::fr& block_header_hash,
518 throw std::runtime_error(
"Can't update archive tree: Block state does not match world state");
528 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
571 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
572 for (
auto& [
id, tree] : fork->_trees) {
574 [&signal](
auto&& wrapper) {
583 const bb::fr& block_header_hash,
595 throw std::runtime_error(result.second);
603 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
605 std::string err_message;
606 auto decr = [&signal, &success, &err_message](
const auto& resp) {
608 bool expected =
true;
609 if (!resp.success && success.compare_exchange_strong(expected,
false)) {
610 err_message = resp.message;
620 bool expected =
true;
621 if (!resp.success && success.compare_exchange_strong(expected,
false)) {
622 err_message = resp.message;
627 wrapper.tree->add_or_update_values(nullifiers, 0, completion);
632 wrapper.tree->add_values(notes, decr);
637 wrapper.tree->add_values(l1_to_l2_messages, decr);
642 wrapper.tree->add_value(block_header_hash, decr);
649 bool expected =
true;
650 if (!resp.success && success.compare_exchange_strong(expected,
false)) {
651 err_message = resp.message;
656 wrapper.tree->add_or_update_values_sequentially(public_writes, completion);
662 throw std::runtime_error(
"Failed to sync block: " + err_message);
666 throw std::runtime_error(
"Can't synch block: block header hash is not the tip of the archive tree");
670 throw std::runtime_error(
"Can't synch block: block state does not match world state");
675 throw std::runtime_error(result.second);
683 const bb::fr& leaf_key)
const
708 throw std::runtime_error(
"Invalid tree type for find_low_leaf");
714 throw std::runtime_error(low_leaf_info.
message);
716 return low_leaf_info.
inner;
742 auto*
const it =
std::max_element(std::begin(unfinalizedBlockNumbers), std::end(unfinalizedBlockNumbers));
745 if (toBlockNumber >= highestUnfinalizedBlock) {
746 throw std::runtime_error(
format(
"Unable to unwind blocks to block number ",
748 ", current pending block ",
749 highestUnfinalizedBlock));
753 for (
block_number_t blockNumber = highestUnfinalizedBlock; blockNumber > toBlockNumber; blockNumber--) {
773 auto*
const it =
std::min_element(std::begin(historicalBlockNumbers), std::end(historicalBlockNumbers));
775 if (toBlockNumber <= oldestHistoricBlock) {
776 throw std::runtime_error(
format(
"Unable to remove historical blocks to block number ",
778 ", blocks not found. Current oldest block: ",
779 oldestHistoricBlock));
782 for (
block_number_t blockNumber = oldestHistoricBlock; blockNumber < toBlockNumber; blockNumber++) {
793 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
796 for (
auto& [
id, tree] : fork->_trees) {
798 [&signal, &local, blockNumber,
id, &
mtx](
auto&& wrapper) {
799 wrapper.tree->finalize_block(blockNumber, [&signal, &local, &
mtx,
id](
Response& resp) {
810 for (
auto& m : local) {
812 throw std::runtime_error(m.message);
822 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
878 throw std::runtime_error(message);
888 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
944 throw std::runtime_error(message);
993 }
catch (std::runtime_error&) {
996 if (indices.empty() || !indices[0].has_value()) {
1001 return archive_state.
meta.
size == indices[0].value() + 1;
1046 throw std::runtime_error(
"World state trees are out of sync");
1052 block_number_t blockNumber = metaResponses[0].unfinalizedBlockHeight;
1053 block_number_t finalizedBlockNumber = metaResponses[0].finalizedBlockHeight;
1054 for (
size_t i = 1; i < metaResponses.size(); i++) {
1055 if (blockNumber != metaResponses[i].unfinalizedBlockHeight) {
1058 if (finalizedBlockNumber != metaResponses[i].finalizedBlockHeight) {
1068 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1071 for (
auto& [
id, tree] : fork->_trees) {
1073 [&signal, &local,
id, &
mtx](
auto&& wrapper) {
1074 wrapper.tree->checkpoint([&signal, &local, &
mtx,
id](
Response& resp) {
1085 for (
auto& m : local) {
1087 throw std::runtime_error(m.message);
1095 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1098 for (
auto& [
id, tree] : fork->_trees) {
1100 [&signal, &local,
id, &
mtx](
auto&& wrapper) {
1101 wrapper.tree->commit_checkpoint([&signal, &local, &
mtx,
id](
Response& resp) {
1112 for (
auto& m : local) {
1114 throw std::runtime_error(m.message);
1122 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1125 for (
auto& [
id, tree] : fork->_trees) {
1127 [&signal, &local,
id, &
mtx](
auto&& wrapper) {
1128 wrapper.tree->revert_checkpoint([&signal, &local, &
mtx,
id](
Response& resp) {
1139 for (
auto& m : local) {
1141 throw std::runtime_error(m.message);
1149 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1152 for (
auto& [
id, tree] : fork->_trees) {
1154 [&signal, &local,
id, &
mtx](
auto&& wrapper) {
1155 wrapper.tree->commit_all_checkpoints([&signal, &local, &
mtx,
id](
Response& resp) {
1166 for (
auto& m : local) {
1168 throw std::runtime_error(m.message);
1176 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1179 for (
auto& [
id, tree] : fork->_trees) {
1181 [&signal, &local,
id, &
mtx](
auto&& wrapper) {
1182 wrapper.tree->revert_all_checkpoints([&signal, &local, &
mtx,
id](
Response& resp) {
1193 for (
auto& m : local) {
1195 throw std::runtime_error(m.message);
1230 auto historicBlockRange =
std::minmax_element(std::begin(historicalBlockNumbers), std::end(historicalBlockNumbers));
1232 auto unfinalizedBlockRange =
1233 std::minmax_element(std::begin(unfinalizedBlockNumbers), std::end(unfinalizedBlockNumbers));
1235 auto finalizedBlockRange =
std::minmax_element(std::begin(finalizedBlockNumbers), std::end(finalizedBlockNumbers));
1244 while (blockToUnwind > *unfinalizedBlockRange.first) {
1249 if (*finalizedBlockRange.first != *finalizedBlockRange.second) {
1254 while (blockToRemove < *historicBlockRange.second) {
bb::bbapi::CommandResponse responses
std::function< void(TypedResponse< AddDataResponse > &)> AddCompletionCallback
std::shared_ptr< LMDBTreeStore > SharedPtr
Used in parallel insertions in the the IndexedTree. Workers signal to other following workes as they ...
void signal_level(uint32_t level=0)
Signals that the given level has been passed.
void signal_decrement(uint32_t delta=1)
void wait_for_level(uint32_t level=0)
Causes the thread to wait until the required level has been signalled.
Holds the Merkle trees responsible for storing the state of the Aztec protocol.
WorldStateStatusFull remove_historical_blocks(const block_number_t &toBlockNumber)
std::shared_ptr< bb::ThreadPool > _workers
void remove_forks_for_block(const block_number_t &blockNumber)
bool unwind_block(const block_number_t &blockNumber, WorldStateStatusFull &status)
static void get_status_summary_from_meta_responses(WorldStateStatusSummary &status, std::array< TreeMeta, NUM_TREES > &metaResponses)
void commit_tree(TreeDBStats &dbStats, Signal &signal, TreeType &tree, std::atomic_bool &success, std::string &message, TreeMeta &meta)
StateReference get_initial_state_reference() const
Gets the initial state reference for all the trees in the world state.
void revert_checkpoint(const uint64_t &forkId)
WorldStateStatusFull attempt_tree_resync()
crypto::merkle_tree::TreeMetaResponse get_tree_info(const WorldStateRevision &revision, MerkleTreeId tree_id) const
Get tree metadata for a particular tree.
static void populate_status_summary(WorldStateStatusFull &status)
WorldState(uint64_t thread_pool_size, const std::string &data_dir, uint64_t map_size, const std::unordered_map< MerkleTreeId, uint32_t > &tree_heights, const std::unordered_map< MerkleTreeId, index_t > &tree_prefill, uint32_t initial_header_generator_point)
void unwind_tree(TreeDBStats &dbStats, Signal &signal, TreeType &tree, std::atomic_bool &success, std::string &message, TreeMeta &meta, const block_number_t &blockNumber)
std::unordered_map< uint64_t, Fork::SharedPtr > _forks
void create_canonical_fork(const std::string &dataDir, const std::unordered_map< MerkleTreeId, uint64_t > &dbSize, const std::vector< PublicDataLeafValue > &prefilled_public_data, uint64_t maxReaders)
std::pair< bool, std::string > commit(WorldStateStatusFull &status)
Commits the current state of the world state.
void remove_historic_block_for_tree(TreeDBStats &dbStats, Signal &signal, TreeType &tree, std::atomic_bool &success, std::string &message, TreeMeta &meta, const block_number_t &blockNumber)
void get_block_numbers_for_leaf_indices(const WorldStateRevision &revision, MerkleTreeId tree_id, const std::vector< index_t > &leafIndices, std::vector< std::optional< block_number_t > > &blockNumbers) const
StateReference get_state_reference(const WorldStateRevision &revision) const
Gets the state reference for all the trees in the world state.
WorldStateStatusFull unwind_blocks(const block_number_t &toBlockNumber)
uint32_t _initial_header_generator_point
bool is_archive_tip(const WorldStateRevision &revision, const bb::fr &block_header_hash) const
static bool determine_if_synched(std::array< TreeMeta, NUM_TREES > &metaResponses)
void update_public_data(const crypto::merkle_tree::PublicDataLeafValue &new_value, Fork::Id fork_id=CANONICAL_FORK_ID)
Updates a leaf in an existing Merkle Tree.
void commit_checkpoint(const uint64_t &forkId)
Fork::SharedPtr create_new_fork(const block_number_t &blockNumber)
void get_status_summary(WorldStateStatusSummary &status) const
void revert_all_checkpoints(const uint64_t &forkId)
void rollback()
Rolls back any uncommitted changes made to the world state.
void commit_all_checkpoints(const uint64_t &forkId)
WorldStateStatusFull sync_block(const StateReference &block_state_ref, const bb::fr &block_header_hash, const std::vector< bb::fr > ¬es, const std::vector< bb::fr > &l1_to_l2_messages, const std::vector< crypto::merkle_tree::NullifierLeafValue > &nullifiers, const std::vector< crypto::merkle_tree::PublicDataLeafValue > &public_writes)
WorldStateStatusSummary set_finalized_blocks(const block_number_t &toBlockNumber)
static bb::fr compute_initial_block_header_hash(const StateReference &initial_state_ref, uint32_t generator_point)
std::unordered_map< MerkleTreeId, index_t > _initial_tree_size
void delete_fork(const uint64_t &forkId)
bool remove_historical_block(const block_number_t &blockNumber, WorldStateStatusFull &status)
std::unordered_map< MerkleTreeId, uint32_t > _tree_heights
uint64_t create_fork(const std::optional< block_number_t > &blockNumber)
crypto::merkle_tree::fr_sibling_path get_sibling_path(const WorldStateRevision &revision, MerkleTreeId tree_id, index_t leaf_index) const
Get the sibling path object for a leaf in a tree.
void validate_trees_are_equally_synched()
void checkpoint(const uint64_t &forkId)
bool is_same_state_reference(const WorldStateRevision &revision, const StateReference &state_ref) const
crypto::merkle_tree::GetLowIndexedLeafResponse find_low_leaf_index(const WorldStateRevision &revision, MerkleTreeId tree_id, const bb::fr &leaf_key) const
Finds the leaf that would have its nextIdx/nextValue fields modified if the target leaf were to be in...
void copy_stores(const std::string &dstPath, bool compact) const
Copies all underlying LMDB stores to the target directory while acquiring a write lock.
void update_archive(const StateReference &block_state_ref, const bb::fr &block_header_hash, Fork::Id fork_id=CANONICAL_FORK_ID)
Updates the archive tree with a new block.
bool set_finalized_block(const block_number_t &blockNumber)
WorldStateStores::Ptr _persistentStores
Fork::SharedPtr retrieve_fork(const uint64_t &forkId) const
void get_all_tree_info(const WorldStateRevision &revision, std::array< TreeMeta, NUM_TREES > &responses) const
std::string format(Args... args)
std::vector< fr > fr_sibling_path
const uint64_t DEFAULT_MIN_NUMBER_OF_READERS
const uint64_t CANONICAL_FORK_ID
std::string getMerkleTreeName(MerkleTreeId id)
std::unordered_map< MerkleTreeId, TreeStateReference > StateReference
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
static fr hash(const std::vector< fr > &inputs)
std::shared_ptr< Fork > SharedPtr
TreeDBStats nullifierTreeStats
TreeDBStats noteHashTreeStats
TreeDBStats archiveTreeStats
TreeDBStats publicDataTreeStats
TreeDBStats messageTreeStats
block_number_t blockNumber
static WorldStateRevision committed()
static WorldStateRevision uncommitted()
WorldStateDBStats dbStats
WorldStateStatusSummary summary
index_t unfinalizedBlockNumber
index_t finalizedBlockNumber
index_t oldestHistoricalBlock