22#include <unordered_map>
23#include <unordered_set>
51template <
typename Store,
typename HashingPolicy>
101 uint32_t subtree_depth,
123 uint32_t subtree_depth,
151 bool includeUncommitted,
159 bool includeUncommitted,
193 const index_t& num_leaves_to_be_inserted,
194 const uint32_t& root_level,
207 uint32_t subtree_depth,
209 bool capture_witness);
219 bool capture_witness);
281template <
typename Store,
typename HashingPolicy>
283 std::unique_ptr<Store> store,
289 if (initial_size < 2) {
290 throw std::runtime_error(
"Indexed trees must have initial size > 1");
292 if (prefilled_values.size() > initial_size) {
293 throw std::runtime_error(
"Number of prefilled values can't be more than initial size");
295 zero_hashes_.resize(depth_ + 1);
299 for (uint32_t i = depth_; i > 0; --i) {
300 zero_hashes_[i] = current;
301 current = HashingPolicy::hash_pair(current, current);
303 zero_hashes_[0] = current;
306 store_->get_meta(meta);
313 std::vector<IndexedLeafValueType> appended_leaves;
316 auto num_default_values =
static_cast<uint32_t
>(initial_size - prefilled_values.size());
317 for (uint32_t i = 0; i < num_default_values; ++i) {
320 initial_set.insert(initial_set.end(), prefilled_values.begin(), prefilled_values.end());
321 for (uint32_t i = num_default_values; i < initial_size; ++i) {
323 const auto* msg = i == num_default_values ?
"Prefilled values must not be the same as the default values"
324 :
"Prefilled values must be unique and sorted";
325 throw std::runtime_error(msg);
329 for (uint32_t i = 0; i < initial_size; ++i) {
330 uint32_t next_index = i == (initial_size - 1) ? 0 : i + 1;
331 auto initial_leaf = IndexedLeafValueType(initial_set[i], next_index, initial_set[next_index].
get_key());
332 fr leaf_hash = HashingPolicy::hash(initial_leaf.get_hash_inputs());
333 appended_leaves.push_back(initial_leaf);
334 appended_hashes.push_back(leaf_hash);
335 store_->set_leaf_key_at_index(i, initial_leaf);
336 store_->put_leaf_by_hash(leaf_hash, initial_leaf);
338 store_->put_leaf_by_hash(0, IndexedLeafValueType::empty());
340 TypedResponse<AddDataResponse> result;
342 AppendCompletionCallback completion = [&](
const TypedResponse<AddDataResponse>& _result) ->
void {
344 signal.signal_level(0);
347 signal.wait_for_level(0);
348 if (!result.success) {
349 throw std::runtime_error(
format(
"Failed to initialize tree: ", result.message));
351 store_->get_meta(meta);
352 meta.initialRoot = result.inner.root;
353 meta.initialSize = result.inner.size;
354 store_->put_meta(meta);
355 store_->commit_genesis_state();
358template <
typename Store,
typename HashingPolicy>
360 bool includeUncommitted,
363 auto job = [=,
this]() {
364 execute_and_report<GetIndexedLeafResponse<LeafValueType>>(
369 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
371 if (!leaf_hash.has_value()) {
372 response.success =
false;
373 response.message =
"Failed to find leaf hash for current root";
377 store_->get_leaf_by_hash(leaf_hash.value(), *tx, includeUncommitted);
378 if (!leaf.has_value()) {
379 response.success =
false;
380 response.message =
"Failed to find leaf by it's hash";
383 response.success =
true;
384 response.inner.indexed_leaf = leaf.value();
388 workers_->enqueue(job);
391template <
typename Store,
typename HashingPolicy>
394 bool includeUncommitted,
397 auto job = [=,
this]() {
398 execute_and_report<GetIndexedLeafResponse<LeafValueType>>(
400 if (blockNumber == 0) {
401 throw std::runtime_error(
"Unable to get leaf for block number 0");
405 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
406 throw std::runtime_error(
format(
"Unable to get leaf at index ",
410 ", failed to get block data."));
415 requestContext.
root = blockData.
root;
417 if (!leaf_hash.has_value()) {
418 response.success =
false;
419 response.message =
format(
"Failed to find leaf hash for root of block ", blockNumber);
423 store_->get_leaf_by_hash(leaf_hash.value(), *tx, includeUncommitted);
424 if (!leaf.has_value()) {
425 response.success =
false;
426 response.message =
format(
"Unable to get leaf at index ", index,
" for block ", blockNumber);
429 response.success =
true;
430 response.inner.indexed_leaf = leaf.value();
434 workers_->enqueue(job);
437template <
typename Store,
typename HashingPolicy>
439 bool includeUncommitted,
442 auto job = [=,
this]() {
443 execute_and_report<GetLowIndexedLeafResponse>(
448 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
450 response.
inner.index = result.second;
451 response.
inner.is_already_present = result.first;
456 workers_->enqueue(job);
459template <
typename Store,
typename HashingPolicy>
462 bool includeUncommitted,
465 auto job = [=,
this]() {
466 execute_and_report<GetLowIndexedLeafResponse>(
468 if (blockNumber == 0) {
469 throw std::runtime_error(
"Unable to find low leaf for block 0");
473 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
474 throw std::runtime_error(
475 format(
"Unable to find low leaf for block ", blockNumber,
", failed to get block data."));
480 requestContext.
root = blockData.
root;
483 response.
inner.index = result.second;
484 response.
inner.is_already_present = result.first;
489 workers_->enqueue(job);
492template <
typename Store,
typename HashingPolicy>
499template <
typename Store,
typename HashingPolicy>
506template <
typename Store,
typename HashingPolicy>
510 add_or_update_values(values, 0, completion);
513template <
typename Store,
typename HashingPolicy>
517 add_or_update_values(values, 0, completion);
520template <
typename Store,
typename HashingPolicy>
523 uint32_t subtree_depth,
526 add_or_update_values_internal(values, subtree_depth, completion,
true);
529template <
typename Store,
typename HashingPolicy>
531 uint32_t subtree_depth,
536 response.
success = add_data_response.success;
537 response.
message = add_data_response.message;
538 if (add_data_response.success) {
539 response.
inner = add_data_response.inner.add_data_result;
542 completion(response);
544 add_or_update_values_internal(values, subtree_depth, final_completion,
false);
547template <
typename Store,
typename HashingPolicy>
550 uint32_t subtree_depth,
552 bool capture_witness)
557 for (
size_t i = 0; i < values.size(); ++i) {
562 struct IntermediateResults {
568 std::atomic<uint32_t> count;
573 IntermediateResults()
582 auto on_error = [=](
const std::string& message) {
587 completion(response);
588 }
catch (std::exception&) {
595 response.
success = add_data_response.success;
596 response.
message = add_data_response.message;
597 if (add_data_response.success) {
598 if (capture_witness) {
601 response.
inner.low_leaf_witness_data =
std::move(results->low_leaf_witness_data);
603 response.
inner.add_data_result =
std::move(add_data_response.inner);
606 completion(response);
610 if (!response.success) {
611 results->status.set_failure(response.message);
613 if (capture_witness) {
614 results->subtree_path =
std::move(response.inner.path);
617 (*results->hashes_to_append), final_completion,
false);
624 if (!hashes_response.success) {
625 results->status.set_failure(hashes_response.message);
627 results->hashes_to_append = hashes_response.inner.hashes;
630 if (results->count.fetch_sub(1) == 1) {
631 if (!results->status.success) {
632 on_error(results->status.message);
635 if (capture_witness) {
637 subtree_depth, sibling_path_completion,
true);
643 sibling_path_completion(response);
651 if (!updates_response.success) {
652 results->status.set_failure(updates_response.message);
653 }
else if (capture_witness) {
654 results->low_leaf_witness_data = updates_response.inner.update_witnesses;
657 if (results->count.fetch_sub(1) == 1) {
658 if (!results->status.success) {
659 on_error(results->status.message);
662 if (capture_witness) {
664 subtree_depth, sibling_path_completion,
true);
670 sibling_path_completion(response);
678 if (!insertion_response.success) {
679 on_error(insertion_response.message);
682 workers_->enqueue([=,
this]() {
683 generate_hashes_for_appending(insertion_response.inner.leaves_to_append, hash_completion);
685 if (capture_witness) {
686 perform_updates(values.size(), insertion_response.inner.low_leaf_updates, updates_completion);
689 perform_updates_without_witness(
690 insertion_response.inner.highest_index, insertion_response.inner.low_leaf_updates, updates_completion);
694 workers_->enqueue([=,
this]() { generate_insertions(values_to_be_sorted, insertion_generation_completed); });
700template <
typename Store,
typename HashingPolicy>
709 if (updates->size() == 0) {
712 response.
inner.update_witnesses = update_witnesses;
713 completion(response);
728 for (
size_t i = 0; i < updates->size(); ++i) {
735 std::queue<std::function<void()>> operations;
736 std::mutex enqueueMutex;
740 std::unique_lock lock(enqueueMutex);
741 if (operations.empty()) {
744 auto nextOp = operations.front();
749 void enqueue_initial(
ThreadPool& workers,
size_t numJobs)
751 std::unique_lock lock(enqueueMutex);
752 for (
size_t i = 0; i < numJobs && !operations.empty(); ++i) {
753 auto nextOp = operations.front();
759 void add_job(std::function<
void()>& job) { operations.push(job); }
764 for (uint32_t i = 0; i < updates->size(); ++i) {
765 std::function<void()> op = [=,
this]() {
767 Signal& leaderSignal = *(*signals)[i];
768 Signal& followerSignal = *(*signals)[i + 1];
770 auto& current_witness_data = update_witnesses->at(i);
772 current_witness_data.index = update.
leaf_index;
773 current_witness_data.path.clear();
775 update_leaf_and_hash_to_root(update.
leaf_index,
779 current_witness_data.path);
780 }
catch (std::exception& e) {
781 status->set_failure(e.what());
788 enqueuedOperations->enqueue_next(*workers_);
791 if (i == updates->size() - 1) {
793 response.
success = status->success;
794 response.
message = status->message;
796 response.
inner.update_witnesses = update_witnesses;
798 completion(response);
801 enqueuedOperations->add_job(op);
807 size_t initialSize = std::min(workers_->num_threads(),
static_cast<size_t>(depth_));
808 enqueuedOperations->enqueue_initial(*workers_, initialSize);
816template <
typename Store,
typename HashingPolicy>
823 if (updates->size() == 0) {
826 completion(response);
832 auto log2Ceil = [=](uint64_t
value) {
834 uint64_t temp =
static_cast<uint64_t
>(1) << log;
835 return temp ==
value ? log : log + 1;
838 uint64_t indexPower2Ceil = log2Ceil(highest_index + 1);
839 index_t span =
static_cast<index_t>(std::pow(2UL, indexPower2Ceil));
841 index_t numBatches =
static_cast<index_t>(std::pow(2UL, numBatchesPower2Floor));
842 index_t batchSize = span / numBatches;
845 indexPower2Ceil = log2Ceil(batchSize);
846 uint32_t rootLevel = depth_ -
static_cast<uint32_t
>(indexPower2Ceil);
852 struct BatchInsertResults {
856 BatchInsertResults(uint32_t
init)
863 for (uint32_t i = 0; i < numBatches; ++i) {
864 std::function<void()> op = [=,
this]() {
866 bool withinRange = startIndex <= highest_index;
868 opCount->roots[i] = sparse_batch_update(startIndex, batchSize, rootLevel, *updates);
870 }
catch (std::exception& e) {
871 status->set_failure(e.what());
874 if (opCount->count.fetch_sub(1) == 1) {
876 for (
size_t i = 0; i < opCount->roots.size(); i++) {
877 if (opCount->roots[i].first) {
878 hashes_at_level.push_back(
std::make_pair(i, opCount->roots[i].second));
881 sparse_batch_update(hashes_at_level, rootLevel);
885 completion(response);
888 startIndex += batchSize;
889 workers_->enqueue(op);
893template <
typename Store,
typename HashingPolicy>
895 std::shared_ptr<std::vector<IndexedLeafValueType>> leaves_to_hash,
const HashGenerationCallback& completion)
897 execute_and_report<HashGenerationResponse>(
900 std::vector<IndexedLeafValueType>& leaves = *leaves_to_hash;
901 for (uint32_t i = 0; i < leaves.size(); ++i) {
903 fr hash = leaf.is_empty() ?
fr::zero() : HashingPolicy::hash(leaf.get_hash_inputs());
905 store_->put_leaf_by_hash(
hash, leaf);
911template <
typename Store,
typename HashingPolicy>
916 execute_and_report<InsertionGenerationResponse>(
925 return aValue == bValue ?
a.second <
b.second : aValue > bValue;
928 std::sort(values_to_be_sorted->begin(), values_to_be_sorted->end(), comp);
936 response.
inner.highest_index = 0;
938 response.
inner.low_leaf_updates->reserve(values.size());
939 response.
inner.leaves_to_append =
941 index_t num_leaves_to_be_inserted = values.size();
947 store_->get_meta(meta);
951 index_t new_total_size = num_leaves_to_be_inserted + meta.
size;
952 if (new_total_size > max_size_) {
953 throw std::runtime_error(
format(
"Unable to insert values into tree ",
960 for (
size_t i = 0; i < values.size(); ++i) {
962 size_t index_into_appended_leaves = value_pair.second;
963 index_t index_of_new_leaf =
static_cast<index_t>(index_into_appended_leaves) + meta.
size;
964 if (value_pair.first.is_empty()) {
967 fr value = value_pair.first.get_key();
968 auto it = unique_values.insert(
value);
970 throw std::runtime_error(
format(
971 "Duplicate key not allowed in same batch, key value: ",
value,
", tree: ", meta.
name));
976 bool is_already_present =
false;
978 requestContext.
root = store_->get_current_root(*tx,
true);
979 std::tie(is_already_present, low_leaf_index) =
980 store_->find_low_value(value_pair.first.get_key(), requestContext, *tx);
986 store_->get_cached_leaf_by_index(low_leaf_index);
989 if (optional_low_leaf.has_value()) {
990 low_leaf = optional_low_leaf.value();
995 std::optional<fr> low_leaf_hash = find_leaf_hash(low_leaf_index, requestContext, *tx,
true);
997 if (!low_leaf_hash.has_value()) {
999 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1001 ", failed to find low leaf at index ",
1009 store_->get_leaf_by_hash(low_leaf_hash.value(), *tx,
true);
1011 if (!low_leaf_option.has_value()) {
1013 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1015 " failed to get leaf pre-image by hash for index ",
1019 low_leaf = low_leaf_option.value();
1024 .updated_leaf = IndexedLeafValueType::empty(),
1030 if (!is_already_present) {
1035 low_leaf.nextIndex = index_of_new_leaf;
1037 store_->set_leaf_key_at_index(index_of_new_leaf, new_leaf);
1045 store_->put_cached_leaf_by_index(low_leaf_index,
low_leaf);
1050 (*response.
inner.leaves_to_append)[index_into_appended_leaves] = new_leaf;
1051 }
else if (IndexedLeafValueType::is_updateable()) {
1060 store_->put_cached_leaf_by_index(low_leaf_index, replacement_leaf);
1065 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1068 IndexedLeafValueType::name(),
1069 " is not updateable and ",
1070 value_pair.first.get_key(),
1071 " is already present"));
1073 response.
inner.highest_index =
std::max(response.
inner.highest_index, low_leaf_index);
1075 response.
inner.low_leaf_updates->push_back(low_update);
1082template <
typename Store,
typename HashingPolicy>
1093 bool success = store_->get_cached_node_by_index(level, index,
value);
1102 uint32_t level = depth_;
1103 fr new_hash = leaf.leaf.is_empty() ?
fr::zero() : HashingPolicy::hash(leaf.get_hash_inputs());
1107 uint32_t leader_level = depth_ - 1;
1111 store_->put_cached_node_by_index(level, index, new_hash);
1113 store_->put_leaf_by_hash(new_hash, leaf);
1123 leader_level = level - 1;
1129 bool is_right =
static_cast<bool>(index & 0x01);
1130 std::optional<fr> new_right_option = is_right ? new_hash : get_optional_node(level, index + 1);
1131 std::optional<fr> new_left_option = is_right ? get_optional_node(level, index - 1) : new_hash;
1132 fr new_right_value = new_right_option.has_value() ? new_right_option.value() : zero_hashes_[level];
1133 fr new_left_value = new_left_option.has_value() ? new_left_option.value() : zero_hashes_[level];
1135 previous_sibling_path.emplace_back(is_right ? new_left_value : new_right_value);
1136 new_hash = HashingPolicy::hash_pair(new_left_value, new_right_value);
1142 leader_level = level - 1;
1147 store_->put_cached_node_by_index(level, index, new_hash);
1148 store_->put_node_by_hash(new_hash, { .left = new_left_option, .right = new_right_option, .ref = 1 });
1158template <
typename Store,
typename HashingPolicy>
1165 bool success = store_->get_cached_node_by_index(level, index,
value);
1169 std::vector<index_t> indices;
1170 indices.reserve(hashes_at_level.size());
1173 for (
size_t i = 0; i < hashes_at_level.size(); ++i) {
1174 index_t index = hashes_at_level[i].first;
1175 fr hash = hashes_at_level[i].second;
1176 hashes[index] =
hash;
1177 indices.push_back(index);
1182 std::vector<index_t> next_indices;
1184 for (
index_t index : indices) {
1185 index_t parent_index = index >> 1;
1186 auto it = unique_indices.insert(parent_index);
1190 next_indices.push_back(parent_index);
1191 bool is_right =
static_cast<bool>(index & 0x01);
1192 fr new_hash = hashes[index];
1193 std::optional<fr> new_right_option = is_right ? new_hash : get_optional_node(level, index + 1);
1194 std::optional<fr> new_left_option = is_right ? get_optional_node(level, index - 1) : new_hash;
1195 fr new_right_value = new_right_option.has_value() ? new_right_option.value() : zero_hashes_[level];
1196 fr new_left_value = new_left_option.has_value() ? new_left_option.value() : zero_hashes_[level];
1198 new_hash = HashingPolicy::hash_pair(new_left_value, new_right_value);
1199 store_->put_cached_node_by_index(level - 1, parent_index, new_hash);
1200 store_->put_node_by_hash(new_hash, { .left = new_left_option, .right = new_right_option, .ref = 1 });
1201 next_hashes[parent_index] = new_hash;
1205 unique_indices.clear();
1210template <
typename Store,
typename HashingPolicy>
1213 const index_t& num_leaves_to_be_inserted,
1214 const uint32_t& root_level,
1220 bool success = store_->get_cached_node_by_index(level, index,
value);
1224 uint32_t level = depth_;
1226 std::vector<index_t> indices;
1227 indices.reserve(updates.size());
1233 index_t end_index = start_index + num_leaves_to_be_inserted;
1235 for (
size_t i = 0; i < updates.size(); ++i) {
1244 : HashingPolicy::hash(update.
updated_leaf.get_hash_inputs());
1250 store_->put_cached_node_by_index(level, update.
leaf_index, new_hash);
1252 store_->put_leaf_by_hash(new_hash, update.
updated_leaf);
1260 if (indices.empty()) {
1264 while (level > root_level) {
1265 std::vector<index_t> next_indices;
1267 for (
index_t index : indices) {
1268 index_t parent_index = index >> 1;
1269 auto it = unique_indices.insert(parent_index);
1273 next_indices.push_back(parent_index);
1274 bool is_right =
static_cast<bool>(index & 0x01);
1275 new_hash = hashes[index];
1276 std::optional<fr> new_right_option = is_right ? new_hash : get_optional_node(level, index + 1);
1277 std::optional<fr> new_left_option = is_right ? get_optional_node(level, index - 1) : new_hash;
1278 fr new_right_value = new_right_option.has_value() ? new_right_option.value() : zero_hashes_[level];
1279 fr new_left_value = new_left_option.has_value() ? new_left_option.value() : zero_hashes_[level];
1281 new_hash = HashingPolicy::hash_pair(new_left_value, new_right_value);
1282 store_->put_cached_node_by_index(level - 1, parent_index, new_hash);
1283 store_->put_node_by_hash(new_hash, { .left = new_left_option, .right = new_right_option, .ref = 1 });
1284 next_hashes[parent_index] = new_hash;
1290 unique_indices.clear();
1297template <
typename Store,
typename HashingPolicy>
1301 add_or_update_values_sequentially_internal(values, completion,
true);
1304template <
typename Store,
typename HashingPolicy>
1308 auto final_completion =
1311 response.
success = add_data_response.success;
1312 response.
message = add_data_response.message;
1313 if (add_data_response.success) {
1314 response.
inner = add_data_response.inner.add_data_result;
1317 completion(response);
1319 add_or_update_values_sequentially_internal(values, final_completion,
false);
1322template <
typename Store,
typename HashingPolicy>
1326 bool capture_witness)
1330 struct IntermediateResults {
1332 size_t appended_leaves = 0;
1336 auto on_error = [=](
const std::string& message) {
1341 completion(response);
1342 }
catch (std::exception&) {
1349 response.
success = updates_completion_response.success;
1350 response.
message = updates_completion_response.message;
1351 if (updates_completion_response.success) {
1355 store_->get_meta(meta);
1357 index_t new_total_size = results->appended_leaves + meta.
size;
1358 meta.
size = new_total_size;
1359 meta.
root = store_->get_current_root(*tx,
true);
1361 store_->put_meta(meta);
1364 if (capture_witness) {
1366 response.
inner.insertion_witness_data =
1368 response.
inner.insertion_witness_data->reserve(results->updates_to_perform.size());
1370 response.
inner.low_leaf_witness_data =
1372 response.
inner.low_leaf_witness_data->reserve(results->updates_to_perform.size());
1374 size_t current_witness_index = 0;
1375 for (
size_t i = 0; i < results->updates_to_perform.size(); ++i) {
1377 updates_completion_response.inner.update_witnesses->at(current_witness_index++);
1378 response.
inner.low_leaf_witness_data->push_back(low_leaf_witness);
1381 if (results->updates_to_perform.at(i).new_leaf.has_value()) {
1383 updates_completion_response.inner.update_witnesses->at(current_witness_index++);
1384 response.
inner.insertion_witness_data->push_back(insertion_witness);
1388 IndexedLeafValueType::empty(), 0, std::vector<fr>(depth_)));
1394 completion(response);
1401 if (!insertion_response.success) {
1402 on_error(insertion_response.message);
1407 flat_updates->reserve(insertion_response.inner.updates_to_perform.size() * 2);
1409 for (
size_t i = 0; i < insertion_response.inner.updates_to_perform.size(); ++i) {
1410 InsertionUpdates& insertion_update = insertion_response.inner.updates_to_perform.at(i);
1412 if (insertion_update.
new_leaf.has_value()) {
1413 results->appended_leaves++;
1416 std::tie(new_leaf, new_leaf_index) = insertion_update.
new_leaf.value();
1419 .updated_leaf = new_leaf,
1420 .original_leaf = IndexedLeafValueType::empty(),
1425 results->updates_to_perform =
std::move(insertion_response.inner.updates_to_perform);
1426 assert(insertion_response.inner.updates_to_perform.size() == 0);
1427 if (capture_witness) {
1428 perform_updates(flat_updates->size(), flat_updates, final_completion);
1431 perform_updates_without_witness(insertion_response.inner.highest_index, flat_updates, final_completion);
1435 workers_->enqueue([=,
this]() { generate_sequential_insertions(values, insertion_generation_completed); });
1438template <
typename Store,
typename HashingPolicy>
1442 execute_and_report<SequentialInsertionGenerationResponse>(
1446 store_->get_meta(meta);
1450 requestContext.
root = store_->get_current_root(*tx,
true);
1454 if (meta.
size > 0) {
1455 find_leaf_hash(meta.size - 1, requestContext, *tx, true);
1460 for (
size_t i = 0; i < values.size(); ++i) {
1464 if (new_payload.is_empty()) {
1467 fr value = new_payload.get_key();
1471 bool is_already_present =
false;
1473 std::tie(is_already_present, low_leaf_index) =
1474 store_->find_low_value(new_payload.get_key(), requestContext, *tx);
1479 store_->get_cached_leaf_by_index(low_leaf_index);
1482 if (optional_low_leaf.has_value()) {
1483 low_leaf = optional_low_leaf.value();
1485 std::optional<fr> low_leaf_hash = find_leaf_hash(low_leaf_index, requestContext, *tx,
true);
1487 if (!low_leaf_hash.has_value()) {
1488 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1490 ", failed to find low leaf at index ",
1495 store_->get_leaf_by_hash(low_leaf_hash.value(), *tx,
true);
1497 if (!low_leaf_option.has_value()) {
1498 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1500 " failed to get leaf pre-image by hash for index ",
1503 low_leaf = low_leaf_option.value();
1510 .updated_leaf = IndexedLeafValueType::empty(),
1516 if (!is_already_present) {
1520 index_t index_of_new_leaf = current_size;
1521 low_leaf.nextIndex = index_of_new_leaf;
1525 store_->set_leaf_key_at_index(index_of_new_leaf, new_leaf);
1526 store_->put_cached_leaf_by_index(index_of_new_leaf, new_leaf);
1528 store_->put_cached_leaf_by_index(low_leaf_index,
low_leaf);
1531 insertion_update.
new_leaf = std::pair(new_leaf, index_of_new_leaf);
1532 }
else if (IndexedLeafValueType::is_updateable()) {
1537 store_->put_cached_leaf_by_index(low_leaf_index, replacement_leaf);
1540 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1543 IndexedLeafValueType::name(),
1544 " is not updateable and ",
1545 new_payload.get_key(),
1546 " is already present"));
1549 response.
inner.updates_to_perform.push_back(insertion_update);
1553 if (current_size > max_size_) {
1554 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1562 response.
inner.highest_index = current_size - 1;
void enqueue(const std::function< void()> &task)
Implements a simple append-only merkle tree All methods are asynchronous unless specified as otherwis...
void get_sibling_path(const index_t &index, const HashPathCallback &on_completion, bool includeUncommitted) const
Returns the sibling path from the leaf at the given index to the root.
void add_values_internal(std::shared_ptr< std::vector< fr > > values, fr &new_root, index_t &new_size, bool update_index)
std::shared_ptr< ThreadPool > workers_
std::vector< fr > zero_hashes_
virtual void add_values(const std::vector< fr > &values, const AppendCompletionCallback &on_completion)
Adds the given set of values to the end of the tree.
std::unique_ptr< Store > store_
std::function< void(TypedResponse< AddDataResponse > &)> AppendCompletionCallback
virtual void add_value(const fr &value, const AppendCompletionCallback &on_completion)
Adds a single value to the end of the tree.
std::optional< fr > find_leaf_hash(const index_t &leaf_index, const RequestContext &requestContext, ReadTransaction &tx, bool updateNodesByIndexCache=false) const
void get_subtree_sibling_path(uint32_t subtree_depth, const HashPathCallback &on_completion, bool includeUncommitted) const
Get the subtree sibling path object.
Serves as a key-value node store for merkle trees. Caches all changes in memory before persisting the...
IndexedLeaf< LeafValueType > IndexedLeafValueType
std::unique_ptr< ReadTransaction > ReadTransactionPtr
typename PersistedStoreType::ReadTransaction ReadTransaction
Implements a parallelized batch insertion indexed tree Accepts template argument of the type of store...
ContentAddressedIndexedTree(ContentAddressedIndexedTree const &other)=delete
ContentAddressedIndexedTree(ContentAddressedIndexedTree &&other)=delete
std::function< void(TypedResponse< GetLowIndexedLeafResponse > &)> FindLowLeafCallback
void find_low_leaf(const fr &leaf_key, bool includeUncommitted, const FindLowLeafCallback &on_completion) const
Find the leaf with the value immediately lower then the value provided.
void add_or_update_value(const LeafValueType &value, const AddCompletionCallbackWithWitness &completion)
Adds or updates a single value in the tree.
std::pair< bool, fr > sparse_batch_update(const index_t &start_index, const index_t &num_leaves_to_be_inserted, const uint32_t &root_level, const std::vector< LeafUpdate > &updates)
std::function< void(TypedResponse< SequentialInsertionGenerationResponse > &)> SequentialInsertionGenerationCallback
typename Store::ReadTransaction ReadTransaction
std::function< void(const TypedResponse< InsertionGenerationResponse > &)> InsertionGenerationCallback
std::function< void(TypedResponse< AddIndexedDataSequentiallyResponse< LeafValueType > > &)> AddSequentiallyCompletionCallbackWithWitness
void add_or_update_values_sequentially(const std::vector< LeafValueType > &values, const AddSequentiallyCompletionCallbackWithWitness &completion)
Adds or updates the given set of values in the tree one by one, fetching witnesses at every step.
void add_or_update_values(const std::vector< LeafValueType > &values, const AddCompletionCallbackWithWitness &completion)
Adds or updates the given set of values in the tree using subtree insertion.
ContentAddressedIndexedTree(std::unique_ptr< Store > store, std::shared_ptr< ThreadPool > workers, const index_t &initial_size)
void perform_updates_without_witness(const index_t &highest_index, std::shared_ptr< std::vector< LeafUpdate > > updates, const UpdatesCompletionCallback &completion)
void generate_insertions(const std::shared_ptr< std::vector< std::pair< LeafValueType, index_t > > > &values_to_be_sorted, const InsertionGenerationCallback &completion)
std::function< void(const TypedResponse< UpdatesCompletionResponse > &)> UpdatesCompletionCallback
ContentAddressedIndexedTree & operator=(const ContentAddressedIndexedTree &other)=delete
~ContentAddressedIndexedTree()=default
ContentAddressedIndexedTree(std::unique_ptr< Store > store, std::shared_ptr< ThreadPool > workers, const index_t &initial_size, const std::vector< LeafValueType > &prefilled_values)
void generate_sequential_insertions(const std::vector< LeafValueType > &values, const SequentialInsertionGenerationCallback &completion)
std::function< void(TypedResponse< AddDataResponse > &)> AddCompletionCallback
std::function< void(TypedResponse< AddIndexedDataResponse< LeafValueType > > &)> AddCompletionCallbackWithWitness
std::function< void(TypedResponse< GetIndexedLeafResponse< LeafValueType > > &)> LeafCallback
std::function< void(const TypedResponse< HashGenerationResponse > &)> HashGenerationCallback
void add_or_update_values_internal(const std::vector< LeafValueType > &values, uint32_t subtree_depth, const AddCompletionCallbackWithWitness &completion, bool capture_witness)
Adds or updates the given set of values in the tree.
void update_leaf_and_hash_to_root(const index_t &index, const IndexedLeafValueType &leaf, Signal &leader, Signal &follower, fr_sibling_path &previous_sibling_path)
void get_leaf(const index_t &index, bool includeUncommitted, const LeafCallback &completion) const
void add_or_update_values_sequentially_internal(const std::vector< LeafValueType > &values, const AddSequentiallyCompletionCallbackWithWitness &completion, bool capture_witness)
Adds or updates the given set of values in the tree, capturing sequential insertion witnesses.
typename Store::IndexedLeafValueType IndexedLeafValueType
typename Store::LeafType LeafValueType
void perform_updates(size_t total_leaves, std::shared_ptr< std::vector< LeafUpdate > > updates, const UpdatesCompletionCallback &completion)
ContentAddressedIndexedTree & operator=(ContentAddressedIndexedTree &&other)=delete
void generate_hashes_for_appending(std::shared_ptr< std::vector< IndexedLeafValueType > > leaves_to_hash, const HashGenerationCallback &completion)
typename Store::ReadTransactionPtr ReadTransactionPtr
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 wait_for_level(uint32_t level=0)
Causes the thread to wait until the required level has been signalled.
std::string format(Args... args)
NullifierTreeLeafPreimage low_leaf
ContentAddressedCachedTreeStore< bb::fr > Store
void hash(State &state) noexcept
std::vector< fr > fr_sibling_path
Key get_key(int64_t keyCount)
constexpr T get_msb(const T in)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::shared_ptr< std::vector< fr > > hashes
std::shared_ptr< std::vector< IndexedLeafValueType > > leaves_to_append
std::shared_ptr< std::vector< LeafUpdate > > low_leaf_updates
std::optional< std::pair< IndexedLeafValueType, index_t > > new_leaf
LeafUpdate low_leaf_update
IndexedLeafValueType updated_leaf
IndexedLeafValueType original_leaf
std::vector< InsertionUpdates > updates_to_perform
void set_failure(const std::string &msg)
std::shared_ptr< std::vector< LeafUpdateWitnessData< LeafValueType > > > update_witnesses
static PublicDataLeafValue padding(index_t i)
std::optional< index_t > maxIndex
std::optional< block_number_t > blockNumber
static constexpr field zero()