21#include <unordered_map>
22#include <unordered_set>
44template <
typename Store,
typename HashingPolicy>
struct ContentAddressedIndexedTreeTestAccess;
52template <
typename Store,
typename HashingPolicy>
103 uint32_t subtree_depth,
125 uint32_t subtree_depth,
153 bool includeUncommitted,
161 bool includeUncommitted,
197 const index_t& num_leaves_to_be_inserted,
198 const uint32_t& root_level,
211 uint32_t subtree_depth,
213 bool capture_witness);
223 bool capture_witness);
285template <
typename Store,
typename HashingPolicy>
293 if (initial_size < 2) {
294 throw std::runtime_error(
"Indexed trees must have initial size > 1");
296 if (prefilled_values.size() > initial_size) {
297 throw std::runtime_error(
"Number of prefilled values can't be more than initial size");
299 zero_hashes_.resize(depth_ + 1);
303 for (uint32_t i = depth_; i > 0; --i) {
304 zero_hashes_[i] = current;
305 current = HashingPolicy::hash_pair(current, current);
307 zero_hashes_[0] = current;
310 store_->get_meta(meta);
317 std::vector<IndexedLeafValueType> appended_leaves;
318 std::vector<bb::fr> appended_hashes;
320 auto num_default_values =
static_cast<uint32_t
>(initial_size - prefilled_values.size());
321 for (uint32_t i = 0; i < num_default_values; ++i) {
324 initial_set.insert(initial_set.end(), prefilled_values.begin(), prefilled_values.end());
325 for (uint32_t i = num_default_values; i < initial_size; ++i) {
327 const auto* msg = i == num_default_values ?
"Prefilled values must not be the same as the default values"
328 :
"Prefilled values must be unique and sorted";
329 throw std::runtime_error(msg);
333 for (uint32_t i = 0; i < initial_size; ++i) {
334 uint32_t next_index = i == (initial_size - 1) ? 0 : i + 1;
335 auto initial_leaf = IndexedLeafValueType(initial_set[i], next_index, initial_set[next_index].
get_key());
336 fr leaf_hash = HashingPolicy::hash(initial_leaf.get_hash_inputs());
337 appended_leaves.push_back(initial_leaf);
338 appended_hashes.push_back(leaf_hash);
339 store_->set_leaf_key_at_index(i, initial_leaf);
340 store_->put_leaf_by_hash(leaf_hash, initial_leaf);
342 store_->put_leaf_by_hash(0, IndexedLeafValueType::empty());
344 TypedResponse<AddDataResponse>
result;
346 AppendCompletionCallback completion = [&](
const TypedResponse<AddDataResponse>& _result) ->
void {
348 signal.signal_level(0);
351 signal.wait_for_level(0);
353 throw std::runtime_error(
format(
"Failed to initialize tree: ",
result.message));
355 store_->get_meta(meta);
356 meta.initialRoot =
result.inner.root;
357 meta.initialSize =
result.inner.size;
358 store_->put_meta(meta);
359 store_->commit_genesis_state();
362template <
typename Store,
typename HashingPolicy>
364 bool includeUncommitted,
367 auto job = [=,
this]() {
368 execute_and_report<GetIndexedLeafResponse<LeafValueType>>(
373 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
375 if (!leaf_hash.has_value()) {
376 response.success =
false;
377 response.message =
"Failed to find leaf hash for current root";
381 store_->get_leaf_by_hash(leaf_hash.value(), *tx, includeUncommitted);
382 if (!leaf.has_value()) {
383 response.success =
false;
384 response.message =
"Failed to find leaf by it's hash";
387 response.success =
true;
388 response.inner.indexed_leaf = leaf.value();
392 workers_->enqueue(job);
395template <
typename Store,
typename HashingPolicy>
398 bool includeUncommitted,
401 auto job = [=,
this]() {
402 execute_and_report<GetIndexedLeafResponse<LeafValueType>>(
406 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
407 throw std::runtime_error(
format(
"Unable to get leaf at index ",
411 ", failed to get block data."));
416 requestContext.
root = blockData.
root;
418 if (!leaf_hash.has_value()) {
419 response.success =
false;
420 response.message =
format(
"Failed to find leaf hash for root of block ", blockNumber);
424 store_->get_leaf_by_hash(leaf_hash.value(), *tx, includeUncommitted);
425 if (!leaf.has_value()) {
426 response.success =
false;
427 response.message =
format(
"Unable to get leaf at index ",
index,
" for block ", blockNumber);
430 response.success =
true;
431 response.inner.indexed_leaf = leaf.value();
435 workers_->enqueue(job);
438template <
typename Store,
typename HashingPolicy>
440 bool includeUncommitted,
443 auto job = [=,
this]() {
444 execute_and_report<GetLowIndexedLeafResponse>(
449 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
457 workers_->enqueue(job);
460template <
typename Store,
typename HashingPolicy>
463 bool includeUncommitted,
466 auto job = [=,
this]() {
467 execute_and_report<GetLowIndexedLeafResponse>(
471 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
472 throw std::runtime_error(
473 format(
"Unable to find low leaf for block ", blockNumber,
", failed to get block data."));
476 requestContext.blockNumber = blockNumber;
477 requestContext.includeUncommitted = includeUncommitted;
478 requestContext.root = blockData.
root;
479 requestContext.maxIndex = blockData.
size;
487 workers_->enqueue(job);
490template <
typename Store,
typename HashingPolicy>
497template <
typename Store,
typename HashingPolicy>
504template <
typename Store,
typename HashingPolicy>
508 add_or_update_values(values, 0, completion);
511template <
typename Store,
typename HashingPolicy>
515 add_or_update_values(values, 0, completion);
518template <
typename Store,
typename HashingPolicy>
521 uint32_t subtree_depth,
524 add_or_update_values_internal(values, subtree_depth, completion,
true);
527template <
typename Store,
typename HashingPolicy>
529 uint32_t subtree_depth,
534 response.
success = add_data_response.success;
535 response.
message = add_data_response.message;
536 if (add_data_response.success) {
537 response.
inner = add_data_response.inner.add_data_result;
540 completion(response);
542 add_or_update_values_internal(values, subtree_depth, final_completion,
false);
545template <
typename Store,
typename HashingPolicy>
548 uint32_t subtree_depth,
550 bool capture_witness)
555 for (
size_t i = 0; i < values.size(); ++i) {
560 struct IntermediateResults {
566 std::atomic<uint32_t> count;
571 IntermediateResults()
580 auto on_error = [=](
const std::string& message) {
585 completion(response);
586 }
catch (std::exception&) {
593 response.
success = add_data_response.success;
594 response.
message = add_data_response.message;
595 if (add_data_response.success) {
596 if (capture_witness) {
599 response.
inner.low_leaf_witness_data =
std::move(results->low_leaf_witness_data);
601 response.
inner.add_data_result =
std::move(add_data_response.inner);
604 completion(response);
608 if (!response.success) {
609 on_error(response.message);
612 if (capture_witness) {
613 results->subtree_path =
std::move(response.inner.path);
616 (*results->hashes_to_append), final_completion,
false);
622 if (!hashes_response.success) {
623 results->status.set_failure(hashes_response.message);
625 results->hashes_to_append = hashes_response.inner.hashes;
628 if (results->count.fetch_sub(1) == 1) {
629 if (!results->status.success) {
630 on_error(results->status.message);
633 if (capture_witness) {
635 subtree_depth, sibling_path_completion,
true);
641 sibling_path_completion(response);
649 if (!updates_response.success) {
650 results->status.set_failure(updates_response.message);
651 }
else if (capture_witness) {
652 results->low_leaf_witness_data = updates_response.inner.update_witnesses;
655 if (results->count.fetch_sub(1) == 1) {
656 if (!results->status.success) {
657 on_error(results->status.message);
660 if (capture_witness) {
662 subtree_depth, sibling_path_completion,
true);
668 sibling_path_completion(response);
676 if (!insertion_response.success) {
677 on_error(insertion_response.message);
680 workers_->enqueue([=,
this]() {
681 generate_hashes_for_appending(insertion_response.inner.leaves_to_append, hash_completion);
683 if (capture_witness) {
684 perform_updates(values.size(), insertion_response.inner.low_leaf_updates, updates_completion);
687 perform_updates_without_witness(
688 insertion_response.inner.highest_index, insertion_response.inner.low_leaf_updates, updates_completion);
692 workers_->enqueue([=,
this]() { generate_insertions(values_to_be_sorted, insertion_generation_completed); });
698template <
typename Store,
typename HashingPolicy>
707 if (updates->size() == 0) {
710 response.
inner.update_witnesses = update_witnesses;
711 completion(response);
726 for (
size_t i = 0; i < updates->size(); ++i) {
733 std::queue<std::function<void()>> operations;
734 std::mutex enqueueMutex;
738 std::unique_lock lock(enqueueMutex);
739 if (operations.empty()) {
742 auto nextOp = operations.front();
747 void enqueue_initial(
ThreadPool& workers,
size_t numJobs)
749 std::unique_lock lock(enqueueMutex);
750 for (
size_t i = 0; i < numJobs && !operations.empty(); ++i) {
751 auto nextOp = operations.front();
757 void add_job(std::function<
void()>& job) { operations.push(job); }
762 for (uint32_t i = 0; i < updates->size(); ++i) {
763 std::function<void()> op = [=,
this]() {
765 Signal& leaderSignal = *(*signals)[i];
766 Signal& followerSignal = *(*signals)[i + 1];
768 auto& current_witness_data = update_witnesses->at(i);
770 current_witness_data.index = update.
leaf_index;
771 current_witness_data.path.clear();
773 update_leaf_and_hash_to_root(update.
leaf_index,
777 current_witness_data.path);
778 }
catch (std::exception& e) {
779 status->set_failure(e.what());
786 enqueuedOperations->enqueue_next(*workers_);
789 if (i == updates->size() - 1) {
791 response.
success = status->success;
792 response.
message = status->message;
794 response.
inner.update_witnesses = update_witnesses;
796 completion(response);
799 enqueuedOperations->add_job(op);
805 size_t initialSize = std::min(workers_->num_threads(),
static_cast<size_t>(depth_));
806 enqueuedOperations->enqueue_initial(*workers_, initialSize);
814template <
typename Store,
typename HashingPolicy>
821 if (updates->size() == 0) {
824 completion(response);
830 auto log2Ceil = [=](uint64_t
value) {
832 uint64_t temp =
static_cast<uint64_t
>(1) << log;
833 return temp ==
value ? log : log + 1;
836 uint64_t indexPower2Ceil = log2Ceil(highest_index + 1);
839 index_t numBatches =
static_cast<index_t>(1) << numBatchesPower2Floor;
840 index_t batchSize = span / numBatches;
843 indexPower2Ceil = log2Ceil(batchSize);
844 uint32_t rootLevel = depth_ -
static_cast<uint32_t
>(indexPower2Ceil);
850 struct BatchInsertResults {
854 BatchInsertResults(uint32_t
init)
861 for (uint32_t i = 0; i < numBatches; ++i) {
862 std::function<void()> op = [=,
this]() {
864 bool withinRange = startIndex <= highest_index;
866 opCount->roots[i] = sparse_batch_update(startIndex, batchSize, rootLevel, *updates);
868 }
catch (std::exception& e) {
869 status->set_failure(e.what());
872 if (opCount->count.fetch_sub(1) == 1) {
875 if (!status->success) {
877 response.
message = status->message;
878 completion(response);
883 for (
size_t i = 0; i < opCount->roots.size(); i++) {
884 if (opCount->roots[i].first) {
885 hashes_at_level.push_back(
std::make_pair(i, opCount->roots[i].second));
889 sparse_batch_update(hashes_at_level, rootLevel);
891 }
catch (std::exception& e) {
896 completion(response);
899 startIndex += batchSize;
900 workers_->enqueue(op);
904template <
typename Store,
typename HashingPolicy>
906 std::shared_ptr<std::vector<IndexedLeafValueType>> leaves_to_hash,
const HashGenerationCallback& completion)
908 execute_and_report<HashGenerationResponse>(
911 std::vector<IndexedLeafValueType>& leaves = *leaves_to_hash;
912 for (uint32_t i = 0; i < leaves.size(); ++i) {
914 fr hash = leaf.is_empty() ?
fr::zero() : HashingPolicy::hash(leaf.get_hash_inputs());
915 (*response.
inner.hashes)[i] = hash;
916 store_->put_leaf_by_hash(hash, leaf);
922template <
typename Store,
typename HashingPolicy>
927 execute_and_report<InsertionGenerationResponse>(
936 return aValue == bValue ?
a.second <
b.second : aValue > bValue;
939 std::sort(values_to_be_sorted->begin(), values_to_be_sorted->end(), comp);
947 response.
inner.highest_index = 0;
949 response.
inner.low_leaf_updates->reserve(values.size());
950 response.
inner.leaves_to_append =
952 index_t num_leaves_to_be_inserted = values.size();
958 store_->get_meta(meta);
962 index_t new_total_size = num_leaves_to_be_inserted + meta.
size;
963 if (new_total_size > max_size_) {
964 throw std::runtime_error(
format(
"Unable to insert values into tree ",
971 for (
size_t i = 0; i < values.size(); ++i) {
973 index_t index_into_appended_leaves = value_pair.second;
974 index_t index_of_new_leaf =
static_cast<index_t>(index_into_appended_leaves) + meta.
size;
975 if (value_pair.first.is_empty()) {
978 fr value = value_pair.first.get_key();
979 auto it = unique_values.insert(
value);
981 throw std::runtime_error(
format(
982 "Duplicate key not allowed in same batch, key value: ",
value,
", tree: ", meta.
name));
987 bool is_already_present =
false;
989 requestContext.
root = store_->get_current_root(*tx,
true);
990 std::tie(is_already_present, low_leaf_index) =
991 store_->find_low_value(value_pair.first.get_key(), requestContext, *tx);
997 store_->get_cached_leaf_by_index(low_leaf_index);
1000 if (optional_low_leaf.has_value()) {
1001 low_leaf = optional_low_leaf.value();
1006 std::optional<fr> low_leaf_hash = find_leaf_hash(low_leaf_index, requestContext, *tx,
true);
1008 if (!low_leaf_hash.has_value()) {
1010 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1012 ", failed to find low leaf at index ",
1020 store_->get_leaf_by_hash(low_leaf_hash.value(), *tx,
true);
1022 if (!low_leaf_option.has_value()) {
1024 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1026 " failed to get leaf pre-image by hash for index ",
1030 low_leaf = low_leaf_option.value();
1035 .updated_leaf = IndexedLeafValueType::empty(),
1041 if (!is_already_present) {
1046 low_leaf.nextIndex = index_of_new_leaf;
1048 store_->set_leaf_key_at_index(index_of_new_leaf, new_leaf);
1056 store_->put_cached_leaf_by_index(low_leaf_index,
low_leaf);
1061 (*response.
inner.leaves_to_append)[index_into_appended_leaves] = new_leaf;
1062 }
else if (IndexedLeafValueType::is_updateable()) {
1071 store_->put_cached_leaf_by_index(low_leaf_index, replacement_leaf);
1076 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1079 IndexedLeafValueType::name(),
1080 " is not updateable and ",
1081 value_pair.first.get_key(),
1082 " is already present"));
1084 response.
inner.highest_index =
std::max(response.
inner.highest_index, low_leaf_index);
1086 response.
inner.low_leaf_updates->push_back(low_update);
1093template <
typename Store,
typename HashingPolicy>
1104 bool success = store_->get_cached_node_by_index(level,
index,
value);
1113 uint32_t level = depth_;
1114 fr new_hash = leaf.is_empty() ?
fr::zero() : HashingPolicy::hash(leaf.get_hash_inputs());
1118 uint32_t leader_level = depth_ - 1;
1122 store_->put_cached_node_by_index(level,
index, new_hash);
1124 store_->put_leaf_by_hash(new_hash, leaf);
1134 leader_level = level - 1;
1140 bool is_right =
static_cast<bool>(
index & 0x01);
1143 fr new_right_value = new_right_option.has_value() ? new_right_option.value() : zero_hashes_[level];
1144 fr new_left_value = new_left_option.has_value() ? new_left_option.value() : zero_hashes_[level];
1146 previous_sibling_path.emplace_back(is_right ? new_left_value : new_right_value);
1147 new_hash = HashingPolicy::hash_pair(new_left_value, new_right_value);
1153 leader_level = level - 1;
1158 store_->put_cached_node_by_index(level,
index, new_hash);
1159 store_->put_node_by_hash(new_hash, { .left = new_left_option, .right = new_right_option, .ref = 1 });
1169template <
typename Store,
typename HashingPolicy>
1176 bool success = store_->get_cached_node_by_index(level,
index,
value);
1181 indices.reserve(hashes_at_level.size());
1184 for (
size_t i = 0; i < hashes_at_level.size(); ++i) {
1186 fr hash = hashes_at_level[i].second;
1187 hashes[
index] = hash;
1188 indices.push_back(
index);
1197 auto it = unique_indices.insert(parent_index);
1201 next_indices.push_back(parent_index);
1202 bool is_right =
static_cast<bool>(
index & 0x01);
1206 fr new_right_value = new_right_option.has_value() ? new_right_option.value() : zero_hashes_[level];
1207 fr new_left_value = new_left_option.has_value() ? new_left_option.value() : zero_hashes_[level];
1209 new_hash = HashingPolicy::hash_pair(new_left_value, new_right_value);
1210 store_->put_cached_node_by_index(level - 1, parent_index, new_hash);
1211 store_->put_node_by_hash(new_hash, { .left = new_left_option, .right = new_right_option, .ref = 1 });
1212 next_hashes[parent_index] = new_hash;
1216 unique_indices.clear();
1221template <
typename Store,
typename HashingPolicy>
1224 const index_t& num_leaves_to_be_inserted,
1225 const uint32_t& root_level,
1231 bool success = store_->get_cached_node_by_index(level,
index,
value);
1235 uint32_t level = depth_;
1238 indices.reserve(updates.size());
1244 index_t end_index = start_index + num_leaves_to_be_inserted;
1246 for (
size_t i = 0; i < updates.size(); ++i) {
1261 store_->put_cached_node_by_index(level, update.
leaf_index, new_hash);
1263 store_->put_leaf_by_hash(new_hash, update.
updated_leaf);
1271 if (indices.empty()) {
1275 while (level > root_level) {
1280 auto it = unique_indices.insert(parent_index);
1284 next_indices.push_back(parent_index);
1285 bool is_right =
static_cast<bool>(
index & 0x01);
1286 new_hash = hashes[
index];
1289 fr new_right_value = new_right_option.has_value() ? new_right_option.value() : zero_hashes_[level];
1290 fr new_left_value = new_left_option.has_value() ? new_left_option.value() : zero_hashes_[level];
1292 new_hash = HashingPolicy::hash_pair(new_left_value, new_right_value);
1293 store_->put_cached_node_by_index(level - 1, parent_index, new_hash);
1294 store_->put_node_by_hash(new_hash, { .left = new_left_option, .right = new_right_option, .ref = 1 });
1295 next_hashes[parent_index] = new_hash;
1301 unique_indices.clear();
1308template <
typename Store,
typename HashingPolicy>
1312 add_or_update_values_sequentially_internal(values, completion,
true);
1315template <
typename Store,
typename HashingPolicy>
1319 auto final_completion =
1322 response.
success = add_data_response.success;
1323 response.
message = add_data_response.message;
1324 if (add_data_response.success) {
1325 response.
inner = add_data_response.inner.add_data_result;
1328 completion(response);
1330 add_or_update_values_sequentially_internal(values, final_completion,
false);
1333template <
typename Store,
typename HashingPolicy>
1337 bool capture_witness)
1341 struct IntermediateResults {
1343 size_t appended_leaves = 0;
1347 auto on_error = [=](
const std::string& message) {
1352 completion(response);
1353 }
catch (std::exception&) {
1360 response.
success = updates_completion_response.success;
1361 response.
message = updates_completion_response.message;
1362 if (updates_completion_response.success) {
1366 store_->get_meta(meta);
1368 index_t new_total_size = results->appended_leaves + meta.
size;
1369 meta.
size = new_total_size;
1370 meta.
root = store_->get_current_root(*tx,
true);
1372 store_->put_meta(meta);
1375 if (capture_witness) {
1377 response.
inner.insertion_witness_data =
1379 response.
inner.insertion_witness_data->reserve(results->updates_to_perform.size());
1381 response.
inner.low_leaf_witness_data =
1383 response.
inner.low_leaf_witness_data->reserve(results->updates_to_perform.size());
1385 size_t current_witness_index = 0;
1386 for (
size_t i = 0; i < results->updates_to_perform.size(); ++i) {
1388 updates_completion_response.inner.update_witnesses->at(current_witness_index++);
1389 response.
inner.low_leaf_witness_data->push_back(low_leaf_witness);
1392 if (results->updates_to_perform.at(i).new_leaf.has_value()) {
1394 updates_completion_response.inner.update_witnesses->at(current_witness_index++);
1395 response.
inner.insertion_witness_data->push_back(insertion_witness);
1399 IndexedLeafValueType::empty(), 0, std::vector<fr>(depth_)));
1405 completion(response);
1412 if (!insertion_response.success) {
1413 on_error(insertion_response.message);
1418 flat_updates->reserve(insertion_response.inner.updates_to_perform.size() * 2);
1420 for (
size_t i = 0; i < insertion_response.inner.updates_to_perform.size(); ++i) {
1421 InsertionUpdates& insertion_update = insertion_response.inner.updates_to_perform.at(i);
1423 if (insertion_update.
new_leaf.has_value()) {
1424 results->appended_leaves++;
1427 std::tie(new_leaf, new_leaf_index) = insertion_update.
new_leaf.value();
1430 .updated_leaf = new_leaf,
1431 .original_leaf = IndexedLeafValueType::empty(),
1436 results->updates_to_perform =
std::move(insertion_response.inner.updates_to_perform);
1437 assert(insertion_response.inner.updates_to_perform.size() == 0);
1438 if (capture_witness) {
1439 perform_updates(flat_updates->size(), flat_updates, final_completion);
1442 perform_updates_without_witness(insertion_response.inner.highest_index, flat_updates, final_completion);
1446 workers_->enqueue([=,
this]() { generate_sequential_insertions(values, insertion_generation_completed); });
1449template <
typename Store,
typename HashingPolicy>
1453 execute_and_report<SequentialInsertionGenerationResponse>(
1457 store_->get_meta(meta);
1461 requestContext.
root = store_->get_current_root(*tx,
true);
1465 if (meta.
size > 0) {
1466 find_leaf_hash(meta.size - 1, requestContext, *tx, true);
1471 for (
size_t i = 0; i < values.size(); ++i) {
1475 if (new_payload.is_empty()) {
1478 fr value = new_payload.get_key();
1482 bool is_already_present =
false;
1484 std::tie(is_already_present, low_leaf_index) =
1485 store_->find_low_value(new_payload.get_key(), requestContext, *tx);
1490 store_->get_cached_leaf_by_index(low_leaf_index);
1493 if (optional_low_leaf.has_value()) {
1494 low_leaf = optional_low_leaf.value();
1496 std::optional<fr> low_leaf_hash = find_leaf_hash(low_leaf_index, requestContext, *tx,
true);
1498 if (!low_leaf_hash.has_value()) {
1499 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1501 ", failed to find low leaf at index ",
1506 store_->get_leaf_by_hash(low_leaf_hash.value(), *tx,
true);
1508 if (!low_leaf_option.has_value()) {
1509 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1511 " failed to get leaf pre-image by hash for index ",
1514 low_leaf = low_leaf_option.value();
1521 .updated_leaf = IndexedLeafValueType::empty(),
1527 if (!is_already_present) {
1531 index_t index_of_new_leaf = current_size;
1532 low_leaf.nextIndex = index_of_new_leaf;
1536 store_->set_leaf_key_at_index(index_of_new_leaf, new_leaf);
1537 store_->put_cached_leaf_by_index(index_of_new_leaf, new_leaf);
1539 store_->put_cached_leaf_by_index(low_leaf_index,
low_leaf);
1542 insertion_update.
new_leaf = std::pair(new_leaf, index_of_new_leaf);
1543 }
else if (IndexedLeafValueType::is_updateable()) {
1548 store_->put_cached_leaf_by_index(low_leaf_index, replacement_leaf);
1551 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1554 IndexedLeafValueType::name(),
1555 " is not updateable and ",
1556 new_payload.get_key(),
1557 " is already present"));
1560 response.
inner.updates_to_perform.push_back(insertion_update);
1564 if (current_size > max_size_) {
1565 throw std::runtime_error(
format(
"Unable to insert values into tree ",
1573 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)
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()