22#include <unordered_map>
23#include <unordered_set>
45template <
typename Store,
typename HashingPolicy>
struct ContentAddressedIndexedTreeTestAccess;
53template <
typename Store,
typename HashingPolicy>
104 uint32_t subtree_depth,
126 uint32_t subtree_depth,
154 bool includeUncommitted,
162 bool includeUncommitted,
198 const index_t& num_leaves_to_be_inserted,
199 const uint32_t& root_level,
212 uint32_t subtree_depth,
214 bool capture_witness);
224 bool capture_witness);
286template <
typename Store,
typename HashingPolicy>
288 std::unique_ptr<Store> store,
294 if (initial_size < 2) {
295 throw std::runtime_error(
"Indexed trees must have initial size > 1");
297 if (prefilled_values.size() > initial_size) {
298 throw std::runtime_error(
"Number of prefilled values can't be more than initial size");
300 zero_hashes_.resize(depth_ + 1);
304 for (uint32_t i = depth_; i > 0; --i) {
305 zero_hashes_[i] = current;
306 current = HashingPolicy::hash_pair(current, current);
308 zero_hashes_[0] = current;
311 store_->get_meta(meta);
318 std::vector<IndexedLeafValueType> appended_leaves;
319 std::vector<bb::fr> appended_hashes;
321 auto num_default_values =
static_cast<uint32_t
>(initial_size - prefilled_values.size());
322 for (uint32_t i = 0; i < num_default_values; ++i) {
325 initial_set.insert(initial_set.end(), prefilled_values.begin(), prefilled_values.end());
326 for (uint32_t i = num_default_values; i < initial_size; ++i) {
328 const auto* msg = i == num_default_values ?
"Prefilled values must not be the same as the default values"
329 :
"Prefilled values must be unique and sorted";
330 throw std::runtime_error(msg);
334 for (uint32_t i = 0; i < initial_size; ++i) {
335 uint32_t next_index = i == (initial_size - 1) ? 0 : i + 1;
336 auto initial_leaf = IndexedLeafValueType(initial_set[i], next_index, initial_set[next_index].
get_key());
337 fr leaf_hash = HashingPolicy::hash(initial_leaf.get_hash_inputs());
338 appended_leaves.push_back(initial_leaf);
339 appended_hashes.push_back(leaf_hash);
340 store_->set_leaf_key_at_index(i, initial_leaf);
341 store_->put_leaf_by_hash(leaf_hash, initial_leaf);
343 store_->put_leaf_by_hash(0, IndexedLeafValueType::empty());
345 TypedResponse<AddDataResponse> result;
347 AppendCompletionCallback completion = [&](
const TypedResponse<AddDataResponse>& _result) ->
void {
349 signal.signal_level(0);
352 signal.wait_for_level(0);
353 if (!result.success) {
354 throw std::runtime_error(
format(
"Failed to initialize tree: ", result.message));
356 store_->get_meta(meta);
357 meta.initialRoot = result.inner.root;
358 meta.initialSize = result.inner.size;
359 store_->put_meta(meta);
360 store_->commit_genesis_state();
363template <
typename Store,
typename HashingPolicy>
365 bool includeUncommitted,
368 auto job = [=,
this]() {
369 execute_and_report<GetIndexedLeafResponse<LeafValueType>>(
374 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
376 if (!leaf_hash.has_value()) {
377 response.success =
false;
378 response.message =
"Failed to find leaf hash for current root";
382 store_->get_leaf_by_hash(leaf_hash.value(), *tx, includeUncommitted);
383 if (!leaf.has_value()) {
384 response.success =
false;
385 response.message =
"Failed to find leaf by it's hash";
388 response.success =
true;
389 response.inner.indexed_leaf = leaf.value();
393 workers_->enqueue(job);
396template <
typename Store,
typename HashingPolicy>
399 bool includeUncommitted,
402 auto job = [=,
this]() {
403 execute_and_report<GetIndexedLeafResponse<LeafValueType>>(
407 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
408 throw std::runtime_error(
format(
"Unable to get leaf at index ",
412 ", failed to get block data."));
417 requestContext.
root = blockData.
root;
419 if (!leaf_hash.has_value()) {
420 response.success =
false;
421 response.message =
format(
"Failed to find leaf hash for root of block ", blockNumber);
425 store_->get_leaf_by_hash(leaf_hash.value(), *tx, includeUncommitted);
426 if (!leaf.has_value()) {
427 response.success =
false;
428 response.message =
format(
"Unable to get leaf at index ",
index,
" for block ", blockNumber);
431 response.success =
true;
432 response.inner.indexed_leaf = leaf.value();
436 workers_->enqueue(job);
439template <
typename Store,
typename HashingPolicy>
441 bool includeUncommitted,
444 auto job = [=,
this]() {
445 execute_and_report<GetLowIndexedLeafResponse>(
450 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
452 response.
inner.index = result.second;
453 response.
inner.is_already_present = result.first;
458 workers_->enqueue(job);
461template <
typename Store,
typename HashingPolicy>
464 bool includeUncommitted,
467 auto job = [=,
this]() {
468 execute_and_report<GetLowIndexedLeafResponse>(
472 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
473 throw std::runtime_error(
474 format(
"Unable to find low leaf for block ", blockNumber,
", failed to get block data."));
477 requestContext.blockNumber = blockNumber;
478 requestContext.includeUncommitted = includeUncommitted;
479 requestContext.root = blockData.
root;
480 requestContext.maxIndex = blockData.
size;
482 response.
inner.index = result.second;
483 response.
inner.is_already_present = result.first;
488 workers_->enqueue(job);
491template <
typename Store,
typename HashingPolicy>
498template <
typename Store,
typename HashingPolicy>
505template <
typename Store,
typename HashingPolicy>
509 add_or_update_values(values, 0, completion);
512template <
typename Store,
typename HashingPolicy>
516 add_or_update_values(values, 0, completion);
519template <
typename Store,
typename HashingPolicy>
522 uint32_t subtree_depth,
525 add_or_update_values_internal(values, subtree_depth, completion,
true);
528template <
typename Store,
typename HashingPolicy>
530 uint32_t subtree_depth,
535 response.
success = add_data_response.success;
536 response.
message = add_data_response.message;
537 if (add_data_response.success) {
538 response.
inner = add_data_response.inner.add_data_result;
541 completion(response);
543 add_or_update_values_internal(values, subtree_depth, final_completion,
false);
546template <
typename Store,
typename HashingPolicy>
549 uint32_t subtree_depth,
551 bool capture_witness)
556 for (
size_t i = 0; i < values.size(); ++i) {
561 struct IntermediateResults {
567 std::atomic<uint32_t> count;
572 IntermediateResults()
581 auto on_error = [=](
const std::string& message) {
586 completion(response);
587 }
catch (std::exception&) {
594 response.
success = add_data_response.success;
595 response.
message = add_data_response.message;
596 if (add_data_response.success) {
597 if (capture_witness) {
600 response.
inner.low_leaf_witness_data =
std::move(results->low_leaf_witness_data);
602 response.
inner.add_data_result =
std::move(add_data_response.inner);
605 completion(response);
609 if (!response.success) {
610 results->status.set_failure(response.message);
612 if (capture_witness) {
613 results->subtree_path =
std::move(response.inner.path);
616 (*results->hashes_to_append), final_completion,
false);
623 if (!hashes_response.success) {
624 results->status.set_failure(hashes_response.message);
626 results->hashes_to_append = hashes_response.inner.hashes;
629 if (results->count.fetch_sub(1) == 1) {
630 if (!results->status.success) {
631 on_error(results->status.message);
634 if (capture_witness) {
636 subtree_depth, sibling_path_completion,
true);
642 sibling_path_completion(response);
650 if (!updates_response.success) {
651 results->status.set_failure(updates_response.message);
652 }
else if (capture_witness) {
653 results->low_leaf_witness_data = updates_response.inner.update_witnesses;
656 if (results->count.fetch_sub(1) == 1) {
657 if (!results->status.success) {
658 on_error(results->status.message);
661 if (capture_witness) {
663 subtree_depth, sibling_path_completion,
true);
669 sibling_path_completion(response);
677 if (!insertion_response.success) {
678 on_error(insertion_response.message);
681 workers_->enqueue([=,
this]() {
682 generate_hashes_for_appending(insertion_response.inner.leaves_to_append, hash_completion);
684 if (capture_witness) {
685 perform_updates(values.size(), insertion_response.inner.low_leaf_updates, updates_completion);
688 perform_updates_without_witness(
689 insertion_response.inner.highest_index, insertion_response.inner.low_leaf_updates, updates_completion);
693 workers_->enqueue([=,
this]() { generate_insertions(values_to_be_sorted, insertion_generation_completed); });
699template <
typename Store,
typename HashingPolicy>
708 if (updates->size() == 0) {
711 response.
inner.update_witnesses = update_witnesses;
712 completion(response);
727 for (
size_t i = 0; i < updates->size(); ++i) {
734 std::queue<std::function<void()>> operations;
735 std::mutex enqueueMutex;
739 std::unique_lock lock(enqueueMutex);
740 if (operations.empty()) {
743 auto nextOp = operations.front();
748 void enqueue_initial(
ThreadPool& workers,
size_t numJobs)
750 std::unique_lock lock(enqueueMutex);
751 for (
size_t i = 0; i < numJobs && !operations.empty(); ++i) {
752 auto nextOp = operations.front();
758 void add_job(std::function<
void()>& job) { operations.push(job); }
763 for (uint32_t i = 0; i < updates->size(); ++i) {
764 std::function<void()> op = [=,
this]() {
766 Signal& leaderSignal = *(*signals)[i];
767 Signal& followerSignal = *(*signals)[i + 1];
769 auto& current_witness_data = update_witnesses->at(i);
771 current_witness_data.index = update.
leaf_index;
772 current_witness_data.path.clear();
774 update_leaf_and_hash_to_root(update.
leaf_index,
778 current_witness_data.path);
779 }
catch (std::exception& e) {
780 status->set_failure(e.what());
787 enqueuedOperations->enqueue_next(*workers_);
790 if (i == updates->size() - 1) {
792 response.
success = status->success;
793 response.
message = status->message;
795 response.
inner.update_witnesses = update_witnesses;
797 completion(response);
800 enqueuedOperations->add_job(op);
806 size_t initialSize = std::min(workers_->num_threads(),
static_cast<size_t>(depth_));
807 enqueuedOperations->enqueue_initial(*workers_, initialSize);
815template <
typename Store,
typename HashingPolicy>
822 if (updates->size() == 0) {
825 completion(response);
831 auto log2Ceil = [=](uint64_t
value) {
833 uint64_t temp =
static_cast<uint64_t
>(1) << log;
834 return temp ==
value ? log : log + 1;
837 uint64_t indexPower2Ceil = log2Ceil(highest_index + 1);
838 index_t span =
static_cast<index_t>(std::pow(2UL, indexPower2Ceil));
840 index_t numBatches =
static_cast<index_t>(std::pow(2UL, numBatchesPower2Floor));
841 index_t batchSize = span / numBatches;
844 indexPower2Ceil = log2Ceil(batchSize);
845 uint32_t rootLevel = depth_ -
static_cast<uint32_t
>(indexPower2Ceil);
851 struct BatchInsertResults {
855 BatchInsertResults(uint32_t
init)
862 for (uint32_t i = 0; i < numBatches; ++i) {
863 std::function<void()> op = [=,
this]() {
865 bool withinRange = startIndex <= highest_index;
867 opCount->roots[i] = sparse_batch_update(startIndex, batchSize, rootLevel, *updates);
869 }
catch (std::exception& e) {
870 status->set_failure(e.what());
873 if (opCount->count.fetch_sub(1) == 1) {
876 if (!status->success) {
878 response.
message = status->message;
879 completion(response);
884 for (
size_t i = 0; i < opCount->roots.size(); i++) {
885 if (opCount->roots[i].first) {
886 hashes_at_level.push_back(
std::make_pair(i, opCount->roots[i].second));
890 sparse_batch_update(hashes_at_level, rootLevel);
892 }
catch (std::exception& e) {
897 completion(response);
900 startIndex += batchSize;
901 workers_->enqueue(op);
905template <
typename Store,
typename HashingPolicy>
907 std::shared_ptr<std::vector<IndexedLeafValueType>> leaves_to_hash,
const HashGenerationCallback& completion)
909 execute_and_report<HashGenerationResponse>(
912 std::vector<IndexedLeafValueType>& leaves = *leaves_to_hash;
913 for (uint32_t i = 0; i < leaves.size(); ++i) {
915 fr hash = leaf.is_empty() ?
fr::zero() : HashingPolicy::hash(leaf.get_hash_inputs());
916 (*response.
inner.hashes)[i] = hash;
917 store_->put_leaf_by_hash(hash, leaf);
923template <
typename Store,
typename HashingPolicy>
928 execute_and_report<InsertionGenerationResponse>(
937 return aValue == bValue ?
a.second <
b.second : aValue > bValue;
940 std::sort(values_to_be_sorted->begin(), values_to_be_sorted->end(), comp);
948 response.
inner.highest_index = 0;
950 response.
inner.low_leaf_updates->reserve(values.size());
951 response.
inner.leaves_to_append =
953 index_t num_leaves_to_be_inserted = values.size();
959 store_->get_meta(meta);
963 index_t new_total_size = num_leaves_to_be_inserted + meta.
size;
964 if (new_total_size > max_size_) {
965 throw std::runtime_error(
format(
"Unable to insert values into tree ",
972 for (
size_t i = 0; i < values.size(); ++i) {
974 index_t index_into_appended_leaves = value_pair.second;
975 index_t index_of_new_leaf =
static_cast<index_t>(index_into_appended_leaves) + meta.
size;
976 if (value_pair.first.is_empty()) {
979 fr value = value_pair.first.get_key();
980 auto it = unique_values.insert(
value);
982 throw std::runtime_error(
format(
983 "Duplicate key not allowed in same batch, key value: ",
value,
", tree: ", meta.
name));
988 bool is_already_present =
false;
990 requestContext.
root = store_->get_current_root(*tx,
true);
991 std::tie(is_already_present, low_leaf_index) =
992 store_->find_low_value(value_pair.first.get_key(), requestContext, *tx);
998 store_->get_cached_leaf_by_index(low_leaf_index);
1001 if (optional_low_leaf.has_value()) {
1002 low_leaf = optional_low_leaf.value();
1007 std::optional<fr> low_leaf_hash = find_leaf_hash(low_leaf_index, requestContext, *tx,
true);
1009 if (!low_leaf_hash.has_value()) {
1011 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1013 ", failed to find low leaf at index ",
1021 store_->get_leaf_by_hash(low_leaf_hash.value(), *tx,
true);
1023 if (!low_leaf_option.has_value()) {
1025 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1027 " failed to get leaf pre-image by hash for index ",
1031 low_leaf = low_leaf_option.value();
1036 .updated_leaf = IndexedLeafValueType::empty(),
1042 if (!is_already_present) {
1047 low_leaf.nextIndex = index_of_new_leaf;
1049 store_->set_leaf_key_at_index(index_of_new_leaf, new_leaf);
1057 store_->put_cached_leaf_by_index(low_leaf_index,
low_leaf);
1062 (*response.
inner.leaves_to_append)[index_into_appended_leaves] = new_leaf;
1063 }
else if (IndexedLeafValueType::is_updateable()) {
1072 store_->put_cached_leaf_by_index(low_leaf_index, replacement_leaf);
1077 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1080 IndexedLeafValueType::name(),
1081 " is not updateable and ",
1082 value_pair.first.get_key(),
1083 " is already present"));
1085 response.
inner.highest_index =
std::max(response.
inner.highest_index, low_leaf_index);
1087 response.
inner.low_leaf_updates->push_back(low_update);
1094template <
typename Store,
typename HashingPolicy>
1105 bool success = store_->get_cached_node_by_index(level,
index,
value);
1114 uint32_t level = depth_;
1115 fr new_hash = leaf.leaf.is_empty() ?
fr::zero() : HashingPolicy::hash(leaf.get_hash_inputs());
1119 uint32_t leader_level = depth_ - 1;
1123 store_->put_cached_node_by_index(level,
index, new_hash);
1125 store_->put_leaf_by_hash(new_hash, leaf);
1135 leader_level = level - 1;
1141 bool is_right =
static_cast<bool>(
index & 0x01);
1144 fr new_right_value = new_right_option.has_value() ? new_right_option.value() : zero_hashes_[level];
1145 fr new_left_value = new_left_option.has_value() ? new_left_option.value() : zero_hashes_[level];
1147 previous_sibling_path.emplace_back(is_right ? new_left_value : new_right_value);
1148 new_hash = HashingPolicy::hash_pair(new_left_value, new_right_value);
1154 leader_level = level - 1;
1159 store_->put_cached_node_by_index(level,
index, new_hash);
1160 store_->put_node_by_hash(new_hash, { .left = new_left_option, .right = new_right_option, .ref = 1 });
1170template <
typename Store,
typename HashingPolicy>
1177 bool success = store_->get_cached_node_by_index(level,
index,
value);
1181 std::vector<index_t> indices;
1182 indices.reserve(hashes_at_level.size());
1185 for (
size_t i = 0; i < hashes_at_level.size(); ++i) {
1187 fr hash = hashes_at_level[i].second;
1188 hashes[
index] = hash;
1189 indices.push_back(
index);
1194 std::vector<index_t> next_indices;
1198 auto it = unique_indices.insert(parent_index);
1202 next_indices.push_back(parent_index);
1203 bool is_right =
static_cast<bool>(
index & 0x01);
1207 fr new_right_value = new_right_option.has_value() ? new_right_option.value() : zero_hashes_[level];
1208 fr new_left_value = new_left_option.has_value() ? new_left_option.value() : zero_hashes_[level];
1210 new_hash = HashingPolicy::hash_pair(new_left_value, new_right_value);
1211 store_->put_cached_node_by_index(level - 1, parent_index, new_hash);
1212 store_->put_node_by_hash(new_hash, { .left = new_left_option, .right = new_right_option, .ref = 1 });
1213 next_hashes[parent_index] = new_hash;
1217 unique_indices.clear();
1222template <
typename Store,
typename HashingPolicy>
1225 const index_t& num_leaves_to_be_inserted,
1226 const uint32_t& root_level,
1232 bool success = store_->get_cached_node_by_index(level,
index,
value);
1236 uint32_t level = depth_;
1238 std::vector<index_t> indices;
1239 indices.reserve(updates.size());
1245 index_t end_index = start_index + num_leaves_to_be_inserted;
1247 for (
size_t i = 0; i < updates.size(); ++i) {
1256 : HashingPolicy::hash(update.
updated_leaf.get_hash_inputs());
1262 store_->put_cached_node_by_index(level, update.
leaf_index, new_hash);
1264 store_->put_leaf_by_hash(new_hash, update.
updated_leaf);
1272 if (indices.empty()) {
1276 while (level > root_level) {
1277 std::vector<index_t> next_indices;
1281 auto it = unique_indices.insert(parent_index);
1285 next_indices.push_back(parent_index);
1286 bool is_right =
static_cast<bool>(
index & 0x01);
1287 new_hash = hashes[
index];
1290 fr new_right_value = new_right_option.has_value() ? new_right_option.value() : zero_hashes_[level];
1291 fr new_left_value = new_left_option.has_value() ? new_left_option.value() : zero_hashes_[level];
1293 new_hash = HashingPolicy::hash_pair(new_left_value, new_right_value);
1294 store_->put_cached_node_by_index(level - 1, parent_index, new_hash);
1295 store_->put_node_by_hash(new_hash, { .left = new_left_option, .right = new_right_option, .ref = 1 });
1296 next_hashes[parent_index] = new_hash;
1302 unique_indices.clear();
1309template <
typename Store,
typename HashingPolicy>
1313 add_or_update_values_sequentially_internal(values, completion,
true);
1316template <
typename Store,
typename HashingPolicy>
1320 auto final_completion =
1323 response.
success = add_data_response.success;
1324 response.
message = add_data_response.message;
1325 if (add_data_response.success) {
1326 response.
inner = add_data_response.inner.add_data_result;
1329 completion(response);
1331 add_or_update_values_sequentially_internal(values, final_completion,
false);
1334template <
typename Store,
typename HashingPolicy>
1338 bool capture_witness)
1342 struct IntermediateResults {
1344 size_t appended_leaves = 0;
1348 auto on_error = [=](
const std::string& message) {
1353 completion(response);
1354 }
catch (std::exception&) {
1361 response.
success = updates_completion_response.success;
1362 response.
message = updates_completion_response.message;
1363 if (updates_completion_response.success) {
1367 store_->get_meta(meta);
1369 index_t new_total_size = results->appended_leaves + meta.
size;
1370 meta.
size = new_total_size;
1371 meta.
root = store_->get_current_root(*tx,
true);
1373 store_->put_meta(meta);
1376 if (capture_witness) {
1378 response.
inner.insertion_witness_data =
1380 response.
inner.insertion_witness_data->reserve(results->updates_to_perform.size());
1382 response.
inner.low_leaf_witness_data =
1384 response.
inner.low_leaf_witness_data->reserve(results->updates_to_perform.size());
1386 size_t current_witness_index = 0;
1387 for (
size_t i = 0; i < results->updates_to_perform.size(); ++i) {
1389 updates_completion_response.inner.update_witnesses->at(current_witness_index++);
1390 response.
inner.low_leaf_witness_data->push_back(low_leaf_witness);
1393 if (results->updates_to_perform.at(i).new_leaf.has_value()) {
1395 updates_completion_response.inner.update_witnesses->at(current_witness_index++);
1396 response.
inner.insertion_witness_data->push_back(insertion_witness);
1400 IndexedLeafValueType::empty(), 0, std::vector<fr>(depth_)));
1406 completion(response);
1413 if (!insertion_response.success) {
1414 on_error(insertion_response.message);
1419 flat_updates->reserve(insertion_response.inner.updates_to_perform.size() * 2);
1421 for (
size_t i = 0; i < insertion_response.inner.updates_to_perform.size(); ++i) {
1422 InsertionUpdates& insertion_update = insertion_response.inner.updates_to_perform.at(i);
1424 if (insertion_update.
new_leaf.has_value()) {
1425 results->appended_leaves++;
1428 std::tie(new_leaf, new_leaf_index) = insertion_update.
new_leaf.value();
1431 .updated_leaf = new_leaf,
1432 .original_leaf = IndexedLeafValueType::empty(),
1437 results->updates_to_perform =
std::move(insertion_response.inner.updates_to_perform);
1438 assert(insertion_response.inner.updates_to_perform.size() == 0);
1439 if (capture_witness) {
1440 perform_updates(flat_updates->size(), flat_updates, final_completion);
1443 perform_updates_without_witness(insertion_response.inner.highest_index, flat_updates, final_completion);
1447 workers_->enqueue([=,
this]() { generate_sequential_insertions(values, insertion_generation_completed); });
1450template <
typename Store,
typename HashingPolicy>
1454 execute_and_report<SequentialInsertionGenerationResponse>(
1458 store_->get_meta(meta);
1462 requestContext.
root = store_->get_current_root(*tx,
true);
1466 if (meta.
size > 0) {
1467 find_leaf_hash(meta.size - 1, requestContext, *tx, true);
1472 for (
size_t i = 0; i < values.size(); ++i) {
1476 if (new_payload.is_empty()) {
1479 fr value = new_payload.get_key();
1483 bool is_already_present =
false;
1485 std::tie(is_already_present, low_leaf_index) =
1486 store_->find_low_value(new_payload.get_key(), requestContext, *tx);
1491 store_->get_cached_leaf_by_index(low_leaf_index);
1494 if (optional_low_leaf.has_value()) {
1495 low_leaf = optional_low_leaf.value();
1497 std::optional<fr> low_leaf_hash = find_leaf_hash(low_leaf_index, requestContext, *tx,
true);
1499 if (!low_leaf_hash.has_value()) {
1500 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1502 ", failed to find low leaf at index ",
1507 store_->get_leaf_by_hash(low_leaf_hash.value(), *tx,
true);
1509 if (!low_leaf_option.has_value()) {
1510 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1512 " failed to get leaf pre-image by hash for index ",
1515 low_leaf = low_leaf_option.value();
1522 .updated_leaf = IndexedLeafValueType::empty(),
1528 if (!is_already_present) {
1532 index_t index_of_new_leaf = current_size;
1533 low_leaf.nextIndex = index_of_new_leaf;
1537 store_->set_leaf_key_at_index(index_of_new_leaf, new_leaf);
1538 store_->put_cached_leaf_by_index(index_of_new_leaf, new_leaf);
1540 store_->put_cached_leaf_by_index(low_leaf_index,
low_leaf);
1543 insertion_update.
new_leaf = std::pair(new_leaf, index_of_new_leaf);
1544 }
else if (IndexedLeafValueType::is_updateable()) {
1549 store_->put_cached_leaf_by_index(low_leaf_index, replacement_leaf);
1552 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1555 IndexedLeafValueType::name(),
1556 " is not updateable and ",
1557 new_payload.get_key(),
1558 " is already present"));
1561 response.
inner.updates_to_perform.push_back(insertion_update);
1565 if (current_size > max_size_) {
1566 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1574 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)
IndexedTreeLeafData low_leaf
ContentAddressedCachedTreeStore< bb::fr > Store
std::vector< fr > fr_sibling_path
Key get_key(int64_t keyCount)
constexpr T get_msb(const T in)
field< Bn254FrParams > fr
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< block_number_t > blockNumber
static constexpr field zero()