2#include "barretenberg/aztec/aztec_constants.hpp"
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 const std::vector<bb::fr>& prefilled_nullifiers,
43 uint32_t initial_header_generator_point,
44 uint64_t genesis_timestamp,
47 , _tree_heights(tree_heights)
48 , _initial_tree_size(tree_prefill)
50 , _initial_header_generator_point(initial_header_generator_point)
51 , _genesis_timestamp(genesis_timestamp)
55 create_canonical_fork(data_dir, map_size, prefilled_public_data, prefilled_nullifiers, maxReaders, ephemeral);
58 }
catch (std::exception& e) {
64 const std::string& data_dir,
66 const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
67 const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
68 uint32_t initial_header_generator_point,
69 uint64_t genesis_timestamp,
78 initial_header_generator_point,
84 const std::string& data_dir,
86 const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
87 const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
89 const std::vector<bb::fr>& prefilled_nullifiers,
90 uint32_t initial_header_generator_point,
91 uint64_t genesis_timestamp,
104 prefilled_public_data,
105 prefilled_nullifiers,
106 initial_header_generator_point,
112 const std::string& data_dir,
114 const std::unordered_map<MerkleTreeId, uint32_t>& tree_heights,
115 const std::unordered_map<MerkleTreeId, index_t>& tree_prefill,
116 uint32_t initial_header_generator_point,
117 uint64_t genesis_timestamp,
126 initial_header_generator_point,
134 const std::vector<bb::fr>& prefilled_nullifiers,
141 std::filesystem::path directory = dataDir;
143 std::filesystem::create_directories(directory);
158 prefilled_nullifier_leaves.reserve(prefilled_nullifiers.size());
159 for (
const auto& nullifier : prefilled_nullifiers) {
160 prefilled_nullifier_leaves.emplace_back(nullifier);
201 _forks[fork->_forkId] = fork;
207 std::filesystem::path directory = dstPath;
208 directory /= store->get_name();
209 std::filesystem::create_directories(directory);
210 store->copy_store(directory, compact);
218 std::unique_lock lock(
mtx);
219 auto it =
_forks.find(forkId);
221 throw std::runtime_error(
"Fork not found");
228 if (!blockNumber.has_value()) {
234 blockNumberForFork = blockNumber.value();
237 std::unique_lock lock(
mtx);
239 fork->_forkId = forkId;
249 std::unique_lock lock(
mtx);
251 if (it->second->_blockNumber == blockNumber) {
252 forks.push_back(it->second);
265 throw std::runtime_error(
"Unable to delete canonical fork");
271 std::unique_lock lock(
mtx);
279 fork->_blockNumber = blockNumber;
326 [=](
auto&& wrapper) {
343 throw std::runtime_error(local.
message);
347 fork->_trees.at(tree_id));
359 Signal signal(
static_cast<uint32_t
>(tree_ids.size()));
363 for (
auto id : tree_ids) {
364 const auto& tree = fork->_trees.at(
id);
373 [&callback, &revision](
auto&& wrapper) {
375 wrapper.tree->get_meta_data(revision.blockNumber, revision.includeUncommitted, callback);
377 wrapper.tree->get_meta_data(revision.includeUncommitted, callback);
385 for (
auto tree_id : tree_ids) {
386 auto& m = local[tree_id];
388 throw std::runtime_error(m.message);
410 if (fork->_forkId != revision.
forkId) {
411 throw std::runtime_error(
"Fork does not match revision");
421 Signal signal(
static_cast<uint32_t
>(tree_ids.size()));
424 std::mutex state_ref_mutex;
426 for (
auto id : tree_ids) {
427 const auto& tree = fork->_trees.at(
id);
436 [&callback, &revision](
auto&& wrapper) {
438 wrapper.tree->get_meta_data(revision.blockNumber, revision.includeUncommitted, callback);
440 wrapper.tree->get_meta_data(revision.includeUncommitted, callback);
448 for (
auto tree_id : tree_ids) {
449 auto& m = local[tree_id];
451 throw std::runtime_error(m.message);
454 state_reference[tree_id] =
std::make_pair(m.inner.meta.initialRoot, m.inner.meta.initialSize);
457 state_reference[tree_id] =
std::make_pair(m.inner.meta.root, m.inner.meta.size);
460 return state_reference;
470 [leaf_index, revision](
auto&& wrapper) {
487 throw std::runtime_error(local.
message);
489 return local.
inner.path;
491 fork->_trees.at(tree_id));
502 [&leafIndices, revision, &blockNumbers](
auto&& wrapper) {
512 wrapper.tree->find_block_numbers(leafIndices, revision.
blockNumber, callback);
514 wrapper.tree->find_block_numbers(leafIndices, callback);
519 throw std::runtime_error(local.
message);
523 fork->_trees.at(tree_id));
529 if (
const auto* wrapper =
532 wrapper->tree->add_or_update_value(
537 throw std::runtime_error(
"Invalid tree type for PublicDataTree");
542 const bb::fr& block_header_hash,
548 throw std::runtime_error(
"Can't update archive tree: Block state does not match world state");
558 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
601 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
602 for (
auto& [
id, tree] : fork->_trees) {
604 [&signal](
auto&& wrapper) {
613 const bb::fr& block_header_hash,
614 const std::vector<bb::fr>& notes,
615 const std::vector<bb::fr>& l1_to_l2_messages,
631 if (expected_previous_archive_root.has_value()) {
632 const bb::fr actual_previous_archive_root =
634 if (actual_previous_archive_root != expected_previous_archive_root.value()) {
635 throw std::runtime_error(
636 format(
"Can't sync block: local archive root ",
637 actual_previous_archive_root,
638 " does not match the block's previous archive root ",
639 expected_previous_archive_root.value(),
640 "; world state has diverged from the canonical chain and must be resynced"));
645 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
647 std::string err_message;
648 auto decr = [&signal, &success, &err_message](
const auto& resp) {
650 bool expected =
true;
651 if (!resp.success && success.compare_exchange_strong(expected,
false)) {
652 err_message = resp.message;
662 bool expected =
true;
663 if (!resp.success && success.compare_exchange_strong(expected,
false)) {
664 err_message = resp.message;
669 wrapper.tree->add_or_update_values(nullifiers, 0, completion);
674 wrapper.tree->add_values(notes, decr);
679 wrapper.tree->add_values(l1_to_l2_messages, decr);
684 wrapper.tree->add_value(block_header_hash, decr);
691 bool expected =
true;
692 if (!resp.success && success.compare_exchange_strong(expected,
false)) {
693 err_message = resp.message;
698 wrapper.tree->add_or_update_values_sequentially(public_writes, completion);
707 throw std::runtime_error(
"Failed to sync block: " + err_message);
711 throw std::runtime_error(
"Can't synch block: block header hash is not the tip of the archive tree");
715 throw std::runtime_error(
"Can't synch block: block state does not match world state");
720 if (expected_archive_root.has_value()) {
721 const bb::fr actual_archive_root =
723 if (actual_archive_root != expected_archive_root.value()) {
724 throw std::runtime_error(
725 format(
"Can't sync block: resulting archive root ",
727 " does not match the block's archive root ",
728 expected_archive_root.value(),
729 "; world state has diverged from the canonical chain and must be resynced"));
735 throw std::runtime_error(
result.second);
737 }
catch (
const std::exception& e) {
750 const bb::fr& leaf_key)
const
775 throw std::runtime_error(
"Invalid tree type for find_low_leaf");
781 throw std::runtime_error(low_leaf_info.
message);
783 return low_leaf_info.
inner;
812 auto*
const it =
std::max_element(std::begin(unfinalizedBlockNumbers), std::end(unfinalizedBlockNumbers));
815 if (toBlockNumber >= highestUnfinalizedBlock) {
816 throw std::runtime_error(
format(
"Unable to unwind blocks to block number ",
818 ", current pending block ",
819 highestUnfinalizedBlock));
823 for (
block_number_t blockNumber = highestUnfinalizedBlock; blockNumber > toBlockNumber; blockNumber--) {
843 auto*
const it =
std::min_element(std::begin(historicalBlockNumbers), std::end(historicalBlockNumbers));
845 if (toBlockNumber <= oldestHistoricBlock) {
846 throw std::runtime_error(
format(
"Unable to remove historical blocks to block number ",
848 ", blocks not found. Current oldest block: ",
849 oldestHistoricBlock));
852 for (
block_number_t blockNumber = oldestHistoricBlock; blockNumber < toBlockNumber; blockNumber++) {
863 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
866 for (
auto& [
id, tree] : fork->_trees) {
868 [&signal, &local, blockNumber,
id, &
mtx](
auto&& wrapper) {
869 wrapper.tree->finalize_block(blockNumber, [&signal, &local, &
mtx,
id](
Response& resp) {
880 for (
auto& m : local) {
882 throw std::runtime_error(m.message);
892 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
948 throw std::runtime_error(message);
958 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1014 throw std::runtime_error(message);
1021 uint32_t generator_point,
1022 uint64_t genesis_timestamp)
1047 bb::fr(genesis_timestamp),
1064 }
catch (std::runtime_error&) {
1067 if (indices.empty() || !indices[0].has_value()) {
1072 return archive_state.
meta.
size == indices[0].value() + 1;
1117 throw std::runtime_error(
"World state trees are out of sync");
1123 block_number_t blockNumber = metaResponses[0].unfinalizedBlockHeight;
1124 block_number_t finalizedBlockNumber = metaResponses[0].finalizedBlockHeight;
1125 for (
size_t i = 1; i < metaResponses.size(); i++) {
1126 if (blockNumber != metaResponses[i].unfinalizedBlockHeight) {
1129 if (finalizedBlockNumber != metaResponses[i].finalizedBlockHeight) {
1139 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1142 for (
auto& [
id, tree] : fork->_trees) {
1144 [&signal, &local,
id, &
mtx](
auto&& wrapper) {
1156 for (
auto& m : local) {
1158 throw std::runtime_error(m.message);
1162 return local[0].inner.depth;
1168 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1171 for (
auto& [
id, tree] : fork->_trees) {
1173 [&signal, &local,
id, &
mtx](
auto&& wrapper) {
1174 wrapper.tree->commit_checkpoint([&signal, &local, &
mtx,
id](
Response& resp) {
1185 for (
auto& m : local) {
1187 throw std::runtime_error(m.message);
1195 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1198 for (
auto& [
id, tree] : fork->_trees) {
1200 [&signal, &local,
id, &
mtx](
auto&& wrapper) {
1201 wrapper.tree->revert_checkpoint([&signal, &local, &
mtx,
id](
Response& resp) {
1212 for (
auto& m : local) {
1214 throw std::runtime_error(m.message);
1222 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1225 for (
auto& [
id, tree] : fork->_trees) {
1227 [&signal, &local,
id, &
mtx, depth](
auto&& wrapper) {
1228 auto callback = [&signal, &local, &
mtx, id](
Response& resp) {
1235 wrapper.tree->commit_to_depth(depth, callback);
1240 for (
auto& m : local) {
1242 throw std::runtime_error(m.message);
1250 Signal signal(
static_cast<uint32_t
>(fork->_trees.size()));
1253 for (
auto& [
id, tree] : fork->_trees) {
1255 [&signal, &local,
id, &
mtx, depth](
auto&& wrapper) {
1256 auto callback = [&signal, &local, &
mtx, id](
Response& resp) {
1263 wrapper.tree->revert_to_depth(depth, callback);
1268 for (
auto& m : local) {
1270 throw std::runtime_error(m.message);
1305 auto historicBlockRange =
std::minmax_element(std::begin(historicalBlockNumbers), std::end(historicalBlockNumbers));
1307 auto unfinalizedBlockRange =
1308 std::minmax_element(std::begin(unfinalizedBlockNumbers), std::end(unfinalizedBlockNumbers));
1310 auto finalizedBlockRange =
std::minmax_element(std::begin(finalizedBlockNumbers), std::end(finalizedBlockNumbers));
1319 while (blockToUnwind > *unfinalizedBlockRange.first) {
1324 if (*finalizedBlockRange.first != *finalizedBlockRange.second) {
1329 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.
uint32_t checkpoint(const uint64_t &forkId)
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)
void commit_all_checkpoints_to(const uint64_t &forkId, uint32_t depth)
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
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
uint64_t _genesis_timestamp
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
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, uint64_t genesis_timestamp=0, bool ephemeral=false)
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)
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, const std::optional< bb::fr > &expected_archive_root=std::nullopt, const std::optional< bb::fr > &expected_previous_archive_root=std::nullopt)
Fork::SharedPtr create_new_fork(const block_number_t &blockNumber)
void get_status_summary(WorldStateStatusSummary &status) const
void rollback()
Rolls back any uncommitted changes made to the world state.
WorldStateStatusSummary set_finalized_blocks(const block_number_t &toBlockNumber)
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)
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
static bb::fr compute_initial_block_header_hash(const StateReference &initial_state_ref, uint32_t generator_point, uint64_t genesis_timestamp=0)
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 revert_all_checkpoints_to(const uint64_t &forkId, uint32_t depth)
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
Entry point for Barretenberg command-line interface.
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()
bool is_historical() const
static WorldStateRevision uncommitted()
WorldStateDBStats dbStats
WorldStateStatusSummary summary
index_t unfinalizedBlockNumber
index_t finalizedBlockNumber
index_t oldestHistoricalBlock