2#include "../fixtures.hpp"
4#include "../node_store/array_store.hpp"
5#include "../nullifier_tree/nullifier_memory_tree.hpp"
6#include "../test_fixtures.hpp"
75 throw std::runtime_error(
"injected get_current_root failure");
102 std::filesystem::create_directories(
_directory);
124 std::filesystem::path directory = rootDirectory;
125 directory.append(
name);
126 std::filesystem::create_directories(directory);
132template <
typename TypeOfTree>
void check_size(TypeOfTree& tree,
index_t expected_size,
bool includeUncommitted =
true)
136 EXPECT_EQ(response.success,
true);
137 EXPECT_EQ(response.inner.meta.size, expected_size);
140 tree.get_meta_data(includeUncommitted, completion);
144template <
typename TypeOfTree>
fr get_root(TypeOfTree& tree,
bool includeUncommitted =
true)
149 r = response.inner.meta.root;
152 tree.get_meta_data(includeUncommitted, completion);
157template <
typename TypeOfTree>
void check_root(TypeOfTree& tree,
fr expected_root,
bool includeUncommitted =
true)
160 EXPECT_EQ(root, expected_root);
163template <
typename TypeOfTree>
167 bool includeUncommitted =
true,
168 bool expected_success =
true)
173 EXPECT_EQ(response.success, expected_success);
174 if (response.success) {
175 h = response.inner.path;
179 tree.get_sibling_path(
index, blockNumber, completion, includeUncommitted);
184template <
typename LeafValueType,
typename TypeOfTree>
187 bool includeUncommitted =
true,
188 bool expected_success =
true)
193 EXPECT_EQ(leaf.success, expected_success);
195 l = leaf.inner.indexed_leaf;
199 tree.get_leaf(
index, includeUncommitted, completion);
204template <
typename LeafValueType,
typename TypeOfTree>
209 auto completion = [&](
const auto& leaf) ->
void {
210 low_leaf_info = leaf.inner;
213 tree.find_low_leaf(leaf.
get_key(), includeUncommitted, completion);
215 return low_leaf_info;
218template <
typename LeafValueType,
typename TypeOfTree>
222 bool includeUncommitted =
true)
226 auto completion = [&](
const auto& leaf) ->
void {
227 low_leaf_info = leaf.inner;
230 tree.find_low_leaf(leaf.
get_key(), blockNumber, includeUncommitted, completion);
232 return low_leaf_info;
235template <
typename LeafValueType,
typename TypeOfTree>
240 bool expected_success,
241 bool includeUncommitted =
true)
245 EXPECT_EQ(response.success, expected_success);
246 if (response.success) {
247 EXPECT_EQ(response.inner.indexed_leaf.value().leaf, leaf);
252 tree.get_leaf(expected_index, blockNumber, includeUncommitted, completion);
256template <
typename TypeOfTree>
261 bool includeUncommitted =
true,
262 bool expected_success =
true)
265 if (expected_success) {
266 EXPECT_EQ(path, expected_sibling_path);
270template <
typename TypeOfTree>
274 bool includeUncommitted =
true,
275 bool expected_success =
true)
278 EXPECT_EQ(path, expected_sibling_path);
285 EXPECT_EQ(response.success,
true);
286 EXPECT_EQ(response.inner.meta.unfinalizedBlockHeight, expected_block_height);
289 tree.get_meta_data(
true, completion);
293template <
typename TypeOfTree>
void commit_tree(TypeOfTree& tree,
bool expectedSuccess =
true)
297 EXPECT_EQ(response.success, expectedSuccess);
300 tree.commit(completion);
304template <
typename LeafValueType,
typename TypeOfTree>
309 EXPECT_EQ(response.success, expectedSuccess);
313 tree.add_or_update_value(
value, completion);
317template <
typename LeafValueType,
typename TypeOfTree>
323 EXPECT_EQ(response.success, expectedSuccess);
327 tree.add_or_update_values_sequentially(values, completion);
331template <
typename LeafValueType,
typename TypeOfTree>
336 EXPECT_EQ(response.success, expectedSuccess);
340 tree.add_or_update_values(values, completion);
344template <
typename LeafValueType,
typename TypeOfTree>
349 EXPECT_EQ(response.success, expectedSuccess);
353 tree.add_or_update_values_sequentially(values, completion);
357template <
typename LeafValueType,
typename TypeOfTree>
362 EXPECT_EQ(response.success, expectedSuccess);
366 tree.add_or_update_values(values, completion);
370template <
typename LeafValueType,
typename TypeOfTree>
373 bool expectedSuccess =
true)
377 EXPECT_EQ(response.success, expectedSuccess);
381 tree.add_or_update_values_sequentially(values, completion);
385template <
typename TypeOfTree>
390 EXPECT_EQ(response.success, expected_success);
393 tree.remove_historic_block(blockNumber, completion);
397template <
typename TypeOfTree>
401 auto completion = [&](
const Response& response) ->
void {
402 EXPECT_EQ(response.success, expected_success);
405 tree.finalize_block(blockNumber, completion);
409template <
typename TypeOfTree>
414 EXPECT_EQ(response.success, expected_success);
417 tree.unwind_block(blockNumber, completion);
425 EXPECT_EQ(response.success,
true);
426 EXPECT_EQ(response.inner.meta.unfinalizedBlockHeight, expected_block_height);
429 tree.get_meta_data(
true, completion);
435 constexpr size_t depth = 10;
450 constexpr size_t depth = 10;
455 EXPECT_ANY_THROW(
Store(
"Wrong name", depth, db));
456 EXPECT_ANY_THROW(
Store(
name, depth + 1, db));
463 constexpr size_t depth = 10;
478 completed.set_value(response.success);
483 ASSERT_EQ(completed_future.wait_for(std::chrono::seconds(60)), std::future_status::ready);
484 EXPECT_FALSE(completed_future.get());
491 constexpr size_t depth = 10;
500 for (uint32_t i = 0; i < 4; i++) {
511 constexpr size_t depth = 10;
515 EXPECT_THROW(
TreeType(
std::move(store), workers, current_size), std::runtime_error);
523 constexpr size_t depth = 4;
530 for (uint32_t i = 0; i < 14; i++) {
535 std::stringstream ss;
536 ss <<
"Unable to insert values into tree " <<
name <<
" new size: 17 max size: 16";
540 EXPECT_EQ(response.success,
false);
541 EXPECT_EQ(response.message, ss.str());
550 constexpr size_t depth = 10;
579 uint32_t num_to_append = 512;
581 for (uint32_t i = 0; i < num_to_append; i += 2) {
584 add_values<NullifierLeafValue>(tree,
587 check_size(tree, num_to_append + current_size);
597 constexpr size_t depth = 10;
610 check_find_leaf_index<NullifierLeafValue, TreeType>(
614 check_find_leaf_index<NullifierLeafValue, TreeType>(
621 check_find_leaf_index<NullifierLeafValue, TreeType>(
623 check_find_leaf_index<NullifierLeafValue, TreeType>(
625 check_find_leaf_index<NullifierLeafValue, TreeType>(
644 check_find_leaf_index<NullifierLeafValue, TreeType>(
661 index_t current_size = initial_size;
664 constexpr size_t depth = 10;
720void test_batch_insert(uint32_t batchSize, std::string directory, uint64_t mapSize, uint64_t maxReaders)
723 const uint32_t batch_size = batchSize;
724 const uint32_t num_batches = 16;
730 auto tree1 =
create_tree(directory, mapSize, maxReaders, depth, batch_size, workers);
731 auto tree2 =
create_tree(directory, mapSize, maxReaders, depth, batch_size, multi_workers);
732 auto tree3 =
create_tree(directory, mapSize, maxReaders, depth, batch_size, multi_workers);
734 for (uint32_t i = 0; i < num_batches; i++) {
749 for (uint32_t j = 0; j < batch_size; j++) {
752 memory_tree_sibling_paths.push_back(path);
760 tree1_low_leaf_witness_data = response.inner.low_leaf_witness_data;
763 tree1->add_or_update_values(batch, completion);
771 tree2_low_leaf_witness_data = response.inner.low_leaf_witness_data;
774 tree2->add_or_update_values(batch, completion);
781 tree3->add_or_update_values(batch, completion);
796 for (uint32_t j = 0; j < batch_size; j++) {
797 EXPECT_EQ(tree1_low_leaf_witness_data->at(j).leaf, tree2_low_leaf_witness_data->at(j).leaf);
798 EXPECT_EQ(tree1_low_leaf_witness_data->at(j).index, tree2_low_leaf_witness_data->at(j).index);
799 EXPECT_EQ(tree1_low_leaf_witness_data->at(j).path, tree2_low_leaf_witness_data->at(j).path);
805 std::string directory,
810 const uint32_t batch_size = batchSize;
811 const uint32_t num_batches = 16;
817 for (uint32_t i = 0; i < num_batches; i++) {
819 auto tree1 =
create_tree(directory, mapSize, maxReaders, depth, batch_size, workers);
820 auto tree2 =
create_tree(directory, mapSize, maxReaders, depth, batch_size, multi_workers);
821 auto tree3 =
create_tree(directory, mapSize, maxReaders, depth, batch_size, multi_workers);
836 for (uint32_t j = 0; j < batch_size; j++) {
839 memory_tree_sibling_paths.push_back(path);
847 tree1_low_leaf_witness_data = response.inner.low_leaf_witness_data;
850 tree1->add_or_update_values(batch, completion);
858 tree2_low_leaf_witness_data = response.inner.low_leaf_witness_data;
861 tree2->add_or_update_values(batch, completion);
868 tree3->add_or_update_values(batch, completion);
883 for (uint32_t j = 0; j < batch_size; j++) {
884 EXPECT_EQ(tree1_low_leaf_witness_data->at(j).leaf, tree2_low_leaf_witness_data->at(j).leaf);
885 EXPECT_EQ(tree1_low_leaf_witness_data->at(j).index, tree2_low_leaf_witness_data->at(j).index);
886 EXPECT_EQ(tree1_low_leaf_witness_data->at(j).path, tree2_low_leaf_witness_data->at(j).path);
897 uint32_t batchSize = 2;
898 while (batchSize <= 2) {
906 uint32_t batchSize = 2;
907 while (batchSize <= 32) {
915 const uint32_t batch_size = 128;
920 auto tree1 =
create_tree(_directory, _mapSize, _maxReaders, depth, batch_size, workers);
921 auto tree2 =
create_tree(_directory, _mapSize, _maxReaders, depth, batch_size, workers);
924 for (uint32_t i = 1; i <= 12; i++) {
926 auto tree =
create_tree(_directory, _mapSize, _maxReaders, depth, batch_size, multiWorkers);
930 std::vector<fr> tree1Roots;
931 std::vector<fr> tree2Roots;
933 for (uint32_t round = 0; round < 10; round++) {
934 std::vector<fr> frValues1 = create_values(3);
935 std::vector<fr> frValues2 = create_values(3);
937 for (uint32_t i = 0; i < 3; i++) {
938 leaves[i] = frValues1[i];
939 leaves[i + 64] = frValues2[i];
950 tree1Roots.push_back(
get_root(*tree1));
951 tree2Roots.push_back(
get_root(*tree2,
true));
952 EXPECT_EQ(tree1Roots[round], tree2Roots[round]);
954 for (
const auto& tree : trees) {
957 EXPECT_EQ(treeRoot, tree1Roots[round]);
967 constexpr size_t depth = 10;
974 for (uint32_t i = 0; i < 16; i++) {
977 values[8] = values[0];
979 std::stringstream ss;
980 ss <<
"Duplicate key not allowed in same batch, key value: " << values[0].nullifier <<
", tree: " <<
name;
984 EXPECT_EQ(response.success,
false);
985 EXPECT_EQ(response.message, ss.str());
988 tree.add_or_update_values(values, add_completion);
995 const uint32_t batch_size = batchSize;
996 const uint32_t num_batches = 16;
1002 auto sequential_tree_1 =
create_tree(directory, mapSize, maxReaders, depth, batch_size, workers);
1003 auto sequential_tree_2 =
create_tree(directory, mapSize, maxReaders, depth, batch_size, multi_workers);
1004 auto sequential_tree_3 =
create_tree(directory, mapSize, maxReaders, depth, batch_size, multi_workers);
1005 auto batch_tree =
create_tree(directory, mapSize, maxReaders, depth, batch_size, multi_workers);
1007 for (uint32_t i = 0; i < num_batches; i++) {
1025 for (uint32_t j = 0; j < batch_size; j++) {
1028 memory_tree_sibling_paths.push_back(path);
1032 sequential_tree_1_insertion_witness_data;
1035 sequential_tree_2_insertion_witness_data;
1041 sequential_tree_1_low_leaf_witness_data = response.inner.low_leaf_witness_data;
1042 sequential_tree_1_insertion_witness_data = response.inner.insertion_witness_data;
1045 sequential_tree_1->add_or_update_values_sequentially(batch, completion);
1053 sequential_tree_2_low_leaf_witness_data = response.inner.low_leaf_witness_data;
1054 sequential_tree_2_insertion_witness_data = response.inner.insertion_witness_data;
1057 sequential_tree_2->add_or_update_values_sequentially(batch, completion);
1064 sequential_tree_3->add_or_update_values_sequentially(batch, completion);
1071 batch_tree->add_or_update_values(batch, completion);
1089 for (uint32_t j = 0; j < batch_size; j++) {
1090 EXPECT_EQ(sequential_tree_1_low_leaf_witness_data->at(j).leaf,
1091 sequential_tree_2_low_leaf_witness_data->at(j).leaf);
1092 EXPECT_EQ(sequential_tree_1_low_leaf_witness_data->at(j).index,
1093 sequential_tree_2_low_leaf_witness_data->at(j).index);
1094 EXPECT_EQ(sequential_tree_1_low_leaf_witness_data->at(j).path,
1095 sequential_tree_2_low_leaf_witness_data->at(j).path);
1097 EXPECT_EQ(sequential_tree_1_insertion_witness_data->at(j).leaf,
1098 sequential_tree_2_insertion_witness_data->at(j).leaf);
1099 EXPECT_EQ(sequential_tree_1_insertion_witness_data->at(j).index,
1100 sequential_tree_2_insertion_witness_data->at(j).index);
1101 EXPECT_EQ(sequential_tree_1_insertion_witness_data->at(j).path,
1102 sequential_tree_2_insertion_witness_data->at(j).path);
1109 uint32_t batchSize = 2;
1110 while (batchSize <= 2) {
1121 constexpr size_t depth = 3;
1127 std::move(store), workers, current_size);
1132 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 2).leaf.value, values[1].value);
1146 uint32_t depth_ =
static_cast<uint32_t
>(path.size());
1147 uint32_t
index = idx;
1148 for (uint32_t i = 0; i < depth_; ++i) {
1149 fr left = (
index & 1) ? path[i] : current;
1150 fr right = (
index & 1) ? current : path[i];
1154 return current == root;
1162 constexpr size_t depth = 3;
1180 EXPECT_EQ(get_leaf<NullifierLeafValue>(tree, 0), zero_leaf);
1181 EXPECT_EQ(get_leaf<NullifierLeafValue>(tree, 1), one_leaf);
1258 auto e000 =
hash_leaf(get_leaf<NullifierLeafValue>(tree, 0));
1259 auto e001 =
hash_leaf(get_leaf<NullifierLeafValue>(tree, 1));
1260 auto e010 =
hash_leaf(get_leaf<NullifierLeafValue>(tree, 2));
1261 auto e011 =
hash_leaf(get_leaf<NullifierLeafValue>(tree, 3));
1262 auto e100 =
hash_leaf(get_leaf<NullifierLeafValue>(tree, 4));
1263 auto e101 =
hash_leaf(get_leaf<NullifierLeafValue>(tree, 5));
1325 constexpr uint32_t depth = 8;
1336 for (uint32_t i = 0; i < 20; i++) {
1355 for (uint32_t i = 0; i < uint32_t(21); i++) {
1357 abs_diff(
uint256_t(new_member),
uint256_t(get_leaf<NullifierLeafValue>(tree, i).leaf.get_key()));
1359 abs_diff(
uint256_t(new_member),
uint256_t(get_leaf<NullifierLeafValue>(tree, i).leaf.get_key()));
1360 differences.push_back(diff_hi + diff_lo);
1363 auto index =
static_cast<uint32_t
>(it - differences.begin());
1371 constexpr size_t depth = 10;
1377 uint32_t num_reads = 16 * 1024;
1389 Signal signal(1 + num_reads);
1393 tree.
commit(commit_completion);
1395 tree.add_or_update_value(
get_value(0), add_completion);
1397 for (
size_t i = 0; i < num_reads; i++) {
1399 paths[i] = response.inner.path;
1413 constexpr size_t depth = 3;
1419 std::move(store), workers, current_size);
1434 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 0), zero_leaf);
1435 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 1), one_leaf);
1510 auto e000 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 0));
1511 auto e001 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 1));
1512 auto e010 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 2));
1513 auto e011 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 3));
1515 auto e101 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 5));
1574 constexpr size_t depth = 3;
1580 std::move(store), workers, current_size);
1595 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 0), zero_leaf);
1596 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 1), one_leaf);
1669 auto e000 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 0));
1670 auto e001 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 1));
1671 auto e010 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 2));
1672 auto e011 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 3));
1673 auto e100 =
hash_leaf(get_leaf<PublicDataLeafValue>(tree, 4));
1731 constexpr uint32_t depth = 8;
1741 EXPECT_EQ(predecessor.is_already_present,
false);
1742 EXPECT_EQ(predecessor.index, 1);
1748 EXPECT_EQ(predecessor.is_already_present,
true);
1749 EXPECT_EQ(predecessor.index, 2);
1755 constexpr uint32_t depth = 8;
1778 const uint32_t batch_size = 16;
1779 const uint32_t num_batches = 8;
1782 uint32_t depth = 10;
1792 auto check = [&]() {
1797 for (uint32_t i = 0; i < memory_tree_sibling_paths_index_0.size(); i++) {
1802 for (uint32_t i = 0; i < num_batches; i++) {
1810 for (uint32_t j = 0; j < batch_size; j++) {
1821 tree1_low_leaf_witness_data = response.inner.low_leaf_witness_data;
1824 tree1.add_or_update_values(batch, completion);
1840 constexpr size_t depth = 3;
1845 using LocalTreeType =
1847 auto tree = LocalTreeType(
std::move(store), workers, current_size);
1862 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 0), zero_leaf);
1863 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 1), one_leaf);
1957 check_historic_find_leaf_index_from<PublicDataLeafValue, LocalTreeType>(
1963 EXPECT_EQ(lowLeaf.
index, 1);
1966 EXPECT_EQ(lowLeaf.
index, 3);
1969 EXPECT_EQ(lowLeaf.
index, 2);
1974 const uint32_t batch_size = 16;
1975 uint32_t depth = 10;
1984 std::vector<fr> values = create_values(batch_size);
1987 values.begin(), values.end(), nullifierValues.begin(), [](
const fr& v) { return NullifierLeafValue(v); });
1993 std::vector<fr> values2 = create_values(batch_size);
1996 values2[batch_size / 2] = values[0];
1999 values2.begin(), values2.end(), nullifierValues2.begin(), [](
const fr& v) { return NullifierLeafValue(v); });
2005 const uint32_t batch_size = 16;
2006 uint32_t depth = 10;
2015 std::vector<fr> values = create_values(batch_size);
2018 values.begin(), values.end(), nullifierValues.begin(), [](
const fr& v) { return NullifierLeafValue(v); });
2023 std::vector<fr> values2 = create_values(batch_size);
2026 values2[batch_size / 2] = values[0];
2029 values2.begin(), values2.end(), nullifierValues2.begin(), [](
const fr& v) { return NullifierLeafValue(v); });
2036 const uint32_t batch_size = 16;
2037 uint32_t depth = 10;
2052 for (uint32_t j = 0; j < batch_size; j++) {
2063 for (uint32_t j = 0; j < batch_size; j++) {
2071 fr block2Root = memdb.
root();
2077 for (uint32_t j = 0; j < batch_size; j++) {
2090 auto treeAtBlock2 =
TreeType(
std::move(storeAtBlock2), multi_workers, batch_size);
2093 check_sibling_path(treeAtBlock2, 3 + batch_size, block2SiblingPathIndex3,
false,
true);
2094 auto block2TreeLeaf10 = get_leaf<NullifierLeafValue>(treeAtBlock2, 7 + batch_size);
2095 EXPECT_EQ(block2TreeLeaf10.leaf.nullifier, batch1[7].nullifier);
2101 get_leaf<NullifierLeafValue>(treeAtBlock2, 35 + batch_size,
false,
false);
2102 check_find_leaf_index<NullifierLeafValue, TreeType>(treeAtBlock2, { batch3[4] }, {
std::nullopt },
true);
2113 check_sibling_path(treeAtBlock2, 3 + batch_size, block3SiblingPathIndex3,
true,
true);
2114 check_sibling_path(treeAtBlock2, 19 + batch_size, block3SiblingPathIndex19,
true,
true);
2115 check_sibling_path(treeAtBlock2, 35 + batch_size, block3SiblingPathIndex35,
true,
true);
2119 EXPECT_EQ(historicSiblingPath, block1SiblingPathIndex3);
2122 check_historic_find_leaf_index<NullifierLeafValue, TreeType>(
2123 treeAtBlock2, { batch3[3] }, 2, {
std::nullopt },
true,
false);
2126 check_historic_find_leaf_index_from<NullifierLeafValue, TreeType>(
2127 treeAtBlock2, { batch3[3] }, 2, 20 + batch_size, {
std::nullopt },
true,
false);
2141 constexpr size_t depth = 3;
2146 using LocalTreeType =
2148 auto tree = LocalTreeType(
std::move(store), workers, current_size);
2163 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 0), zero_leaf);
2164 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 1), one_leaf);
2264 check_historic_find_leaf_index_from<PublicDataLeafValue, LocalTreeType>(
2270 EXPECT_EQ(lowLeaf.
index, 1);
2273 EXPECT_EQ(lowLeaf.
index, 3);
2276 EXPECT_EQ(lowLeaf.
index, 2);
2285 check_historic_find_leaf_index<PublicDataLeafValue, LocalTreeType>(
2305 constexpr size_t depth = 3;
2310 using LocalTreeType =
2312 auto tree = LocalTreeType(
std::move(store), workers, current_size);
2327 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 0), zero_leaf);
2328 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 1), one_leaf);
2330 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2331 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2357 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2358 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2385 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2386 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2421 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2422 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2462 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2463 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2476 check_historic_find_leaf_index_from<PublicDataLeafValue, LocalTreeType>(
2482 EXPECT_EQ(lowLeaf.
index, 1);
2485 EXPECT_EQ(lowLeaf.
index, 3);
2488 EXPECT_EQ(lowLeaf.
index, 2);
2495 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2496 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2516 check_find_leaf_index<PublicDataLeafValue, LocalTreeType>(
2518 check_find_leaf_index_from<PublicDataLeafValue, LocalTreeType>(
2530 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2531 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2550 constexpr size_t depth = 3;
2556 std::move(store), workers, current_size);
2571 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 0), zero_leaf);
2572 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 1), one_leaf);
2596 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2597 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2623 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2624 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2649 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2650 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2668 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2669 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2687 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, zero_leaf,
true);
2688 check_leaf_by_hash<PublicDataLeafValue, HashPolicy>(db, one_leaf,
true);
2710 uint64_t maxReaders,
2714 uint32_t numBlocksToUnwind,
2715 std::vector<fr> values)
2723 auto it =
std::find_if(values.begin(), values.end(), [&](
const fr& v) { return v != fr::zero(); });
2724 bool emptyBlocks = it == values.end();
2726 uint32_t batchSize = blockSize;
2730 std::vector<fr> roots;
2732 fr initialRoot = memdb.
root();
2736 leafValues.reserve(values.size());
2737 for (
const fr& v : values) {
2738 leafValues.emplace_back(v);
2741 for (uint32_t i = 0; i < numBlocks; i++) {
2744 for (
size_t j = 0; j < batchSize; ++j) {
2745 size_t ind = i * batchSize + j;
2747 to_add.push_back(leafValues[ind]);
2750 index_t expected_size = (i + 2) * batchSize;
2755 historicPathsMaxIndex.push_back(memdb.
get_sibling_path(expected_size - 1));
2756 roots.push_back(memdb.
root());
2765 const uint32_t blocksToRemove = numBlocksToUnwind;
2766 for (uint32_t i = 0; i < blocksToRemove; i++) {
2779 const index_t previousValidBlock = blockNumber - 1;
2781 index_t deletedBlockStartIndex = (1 + previousValidBlock) * batchSize;
2782 index_t deletedBlockStartIndexIntoLocalValues = previousValidBlock * batchSize;
2786 check_root(tree, previousValidBlock == 0 ? initialRoot : roots[previousValidBlock - 1]);
2791 previousValidBlock == 0 ? initialPath : historicPathsZeroIndex[previousValidBlock - 1],
2797 get_leaf<NullifierLeafValue>(tree, 1 + deletedBlockStartIndex,
false,
false);
2799 check_find_leaf_index<NullifierLeafValue, TreeType>(
2800 tree, { leafValues[1 + deletedBlockStartIndexIntoLocalValues] }, {
std::nullopt },
true);
2803 for (
index_t j = 0; j < numBlocks; j++) {
2805 bool expectedSuccess = historicBlockNumber <= previousValidBlock;
2807 tree, 0, historicBlockNumber, historicPathsZeroIndex[j],
false, expectedSuccess);
2808 index_t maxSizeAtBlock = ((j + 2) * batchSize) - 1;
2810 tree, maxSizeAtBlock, historicBlockNumber, historicPathsMaxIndex[j],
false, expectedSuccess);
2816 const index_t expectedIndexInTree = leafIndex + batchSize;
2818 tree, leafValues[leafIndex], expectedIndexInTree, historicBlockNumber, expectedSuccess,
false);
2821 if (expectedSuccess) {
2824 check_historic_find_leaf_index<NullifierLeafValue, TreeType>(
2825 tree, { leafValues[leafIndex] }, historicBlockNumber, expectedResults, expectedSuccess,
true);
2826 check_historic_find_leaf_index_from<NullifierLeafValue, TreeType>(
2827 tree, { leafValues[leafIndex] }, historicBlockNumber, 0, expectedResults, expectedSuccess,
true);
2835 constexpr uint32_t numBlocks = 8;
2836 constexpr uint32_t numBlocksToUnwind = 4;
2837 std::vector<uint32_t> blockSizes = { 2, 4, 8, 16, 32 };
2838 for (
const uint32_t& size : blockSizes) {
2839 uint32_t actualSize = size;
2840 std::vector<fr> values = create_values(actualSize * numBlocks);
2841 std::stringstream ss;
2842 ss <<
"DB " << actualSize;
2844 _directory, ss.str(), _mapSize, _maxReaders, 20, actualSize, numBlocks, numBlocksToUnwind, values);
2851 constexpr uint32_t numBlocks = 8;
2852 constexpr uint32_t numBlocksToUnwind = 4;
2853 std::vector<uint32_t> blockSizes = { 2, 4, 8, 16, 32 };
2854 for (
const uint32_t& size : blockSizes) {
2855 uint32_t actualSize = size;
2856 std::vector<fr> values = std::vector<fr>(actualSize * numBlocks,
fr::zero());
2857 std::stringstream ss;
2858 ss <<
"DB " << actualSize;
2860 _directory, ss.str(), _mapSize, _maxReaders, 20, actualSize, numBlocks, numBlocksToUnwind, values);
2867 constexpr size_t depth = 3;
2891 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 0), leaf_0);
2892 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 1), leaf_1);
2893 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 2), leaf_2);
2894 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 3), leaf_3);
2903 constexpr size_t depth = 4;
2911 auto tree =
TreeType(
std::move(store), workers, initial_size, prefilled_values);
2920 EXPECT_EQ(get_leaf<NullifierLeafValue>(tree, 0), expected_leaf_0);
2933 constexpr size_t depth = 3;
2959 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 0), leaf_0);
2960 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 1), leaf_1);
2961 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 2), leaf_2);
2962 EXPECT_EQ(get_leaf<PublicDataLeafValue>(tree, 3), leaf_3);
2968 constexpr size_t depth = 3;
2982 constexpr size_t depth = 3;
2996 index_t current_size = initial_size;
2999 constexpr size_t depth = 3;
3005 std::move(store), workers, current_size);
3060 index_t fork_size = current_size;
3065 std::move(forkStore), workers, initial_size);
3071 EXPECT_EQ(predecessor.is_already_present,
false);
3072 EXPECT_EQ(predecessor.index, 2);
3099 EXPECT_EQ(predecessor.is_already_present,
false);
3100 EXPECT_EQ(predecessor.index, 4);
3114 EXPECT_EQ(predecessor.is_already_present,
false);
3115 EXPECT_EQ(predecessor.index, 2);
3146 EXPECT_EQ(predecessor.is_already_present,
false);
3147 EXPECT_EQ(predecessor.index, 4);
3174 EXPECT_EQ(predecessor.is_already_present,
false);
3175 EXPECT_EQ(predecessor.index, 4);
3204 EXPECT_EQ(predecessor.is_already_present,
false);
3205 EXPECT_EQ(predecessor.index, 4);
3211 EXPECT_EQ(predecessor.is_already_present,
false);
3212 EXPECT_EQ(predecessor.index, 5);
3230 EXPECT_EQ(predecessor.is_already_present,
false);
3231 EXPECT_EQ(predecessor.index, 4);
3237 EXPECT_EQ(predecessor.is_already_present,
false);
3238 EXPECT_EQ(predecessor.index, 5);
3266 EXPECT_EQ(predecessor.is_already_present,
false);
3267 EXPECT_EQ(predecessor.index, 4);
3273 EXPECT_EQ(predecessor.is_already_present,
false);
3274 EXPECT_EQ(predecessor.index, 2);
3280 std::vector<fr> values = create_values(size);
3282 for (uint32_t j = 0; j < size; j++) {
3283 leaves.emplace_back(values[j]);
3292 constexpr size_t depth = 10;
3293 std::string
name =
"Nullifier Tree";
3304 uint32_t size_to_insert = 8;
3305 uint32_t num_insertions = 5;
3307 for (uint32_t i = 0; i < num_insertions - 1; i++) {
3309 current_size += size_to_insert;
3315 current_size += size_to_insert;
3319 current_size -= size_to_insert;
3328 current_size += size_to_insert;
3347 throw std::runtime_error(
"injected failure from put_cached_node_by_index");
3361 constexpr size_t depth = 6;
3362 constexpr index_t initial_size = 2;
3367 auto* raw_store = store.get();
3381 raw_store->throw_on_put_cached_node_by_index =
true;
3384 bool callback_success =
false;
3385 std::string callback_message;
3392 callback_success = response.
success;
3393 callback_message = response.
message;
3400 EXPECT_GT(raw_store->num_put_cached_node_calls.load(), 0);
3403 EXPECT_FALSE(callback_success);
3404 EXPECT_FALSE(callback_message.empty());
std::atomic< uint32_t > fail_on_call
std::atomic< uint32_t > root_call_count
fr get_current_root(ReadTransaction &tx, bool includeUncommitted) const
static std::string _directory
static uint64_t _maxReaders
std::atomic< bool > throw_on_put_cached_node_by_index
void put_cached_node_by_index(uint32_t level, index_t index, const fr &value)
std::atomic< uint64_t > num_put_cached_node_calls
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 commit(const CommitCallback &on_completion)
Commit the tree to the backing store.
Serves as a key-value node store for merkle trees. Caches all changes in memory before persisting the...
void put_cached_node_by_index(uint32_t level, const index_t &index, const fr &data, bool overwriteIfPresent=true)
Writes the provided data at the given node coordinates. Only writes to uncommitted data.
typename PersistedStoreType::ReadTransaction ReadTransaction
fr get_current_root(ReadTransaction &tx, bool includeUncommitted) const
Implements a parallelized batch insertion indexed tree Accepts template argument of the type of store...
std::function< void(TypedResponse< AddIndexedDataSequentiallyResponse< LeafValueType > > &)> AddSequentiallyCompletionCallbackWithWitness
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.
void perform_updates_without_witness(const index_t &highest_index, std::shared_ptr< std::vector< LeafUpdate > > updates, const UpdatesCompletionCallback &completion)
std::function< void(const TypedResponse< UpdatesCompletionResponse > &)> UpdatesCompletionCallback
std::function< void(TypedResponse< AddIndexedDataResponse< LeafValueType > > &)> AddCompletionCallbackWithWitness
std::shared_ptr< LMDBTreeStore > SharedPtr
fr update_element(size_t index, fr const &value)
fr_sibling_path get_sibling_path(size_t index) const
fr_sibling_path update_element(fr const &value)
Used in parallel insertions in the the IndexedTree. Workers signal to other following workes as they ...
void signal_level(uint32_t level=0)
Signals that the given level has been passed.
void signal_decrement(uint32_t delta=1)
void wait_for_level(uint32_t level=0)
Causes the thread to wait until the required level has been signalled.
void commit_tree(TypeOfTree &tree, bool expectedSuccess=true)
void test_batch_insert(uint32_t batchSize, std::string directory, uint64_t mapSize, uint64_t maxReaders)
ContentAddressedCachedTreeStore< NullifierLeafValue > Store
fr get_root(TypeOfTree &tree, bool includeUncommitted=true)
void advance_state(TreeType &fork, uint32_t size)
void add_value_sequentially(TypeOfTree &tree, const LeafValueType &value, bool expectedSuccess=true)
void add_values(TypeOfTree &tree, const std::vector< LeafValueType > &values, bool expectedSuccess=true)
void add_values_sequentially(TypeOfTree &tree, const std::vector< LeafValueType > &values, bool expectedSuccess=true)
void check_sibling_path(TypeOfTree &tree, index_t index, const fr_sibling_path &expected_sibling_path, bool includeUncommitted=true, bool expected_success=true)
TreeType::AddCompletionCallbackWithWitness CompletionCallback
void check_historic_sibling_path(TypeOfTree &tree, index_t index, block_number_t blockNumber, const fr_sibling_path &expected_sibling_path, bool includeUncommitted=true, bool expected_success=true)
void test_batch_insert_with_commit_restore(uint32_t batchSize, std::string directory, uint64_t mapSize, uint64_t maxReaders)
ContentAddressedIndexedTree< PublicDataStore, Poseidon2HashPolicy > PublicDataTreeType
IndexedNullifierLeafType create_indexed_nullifier_leaf(const fr &value, index_t nextIndex, const fr &nextValue)
void add_value(TypeOfTree &tree, const LeafValueType &value, bool expectedSuccess=true)
std::unique_ptr< TreeType > create_tree(const std::string &rootDirectory, uint64_t mapSize, uint64_t maxReaders, uint32_t depth, uint32_t batchSize, ThreadPoolPtr workers)
fr_sibling_path get_historic_sibling_path(TypeOfTree &tree, block_number_t blockNumber, index_t index, bool includeUncommitted=true, bool expected_success=true)
GetLowIndexedLeafResponse get_historic_low_leaf(TypeOfTree &tree, block_number_t blockNumber, const LeafValueType &leaf, bool includeUncommitted=true)
void test_sequential_insert_vs_batch(uint32_t batchSize, std::string directory, uint64_t mapSize, uint64_t maxReaders)
void check_block_height(TypeOfTree &tree, index_t expected_block_height)
IndexedLeaf< LeafValueType > get_leaf(TypeOfTree &tree, index_t index, bool includeUncommitted=true, bool expected_success=true)
void check_root(TypeOfTree &tree, fr expected_root, bool includeUncommitted=true)
GetLowIndexedLeafResponse get_low_leaf(TypeOfTree &tree, const LeafValueType &leaf, bool includeUncommitted=true)
void check_historic_leaf(TypeOfTree &tree, const LeafValueType &leaf, index_t expected_index, block_number_t blockNumber, bool expected_success, bool includeUncommitted=true)
void block_sync_values_sequential(TypeOfTree &tree, const std::vector< LeafValueType > &values, bool expectedSuccess=true)
IndexedPublicDataLeafType create_indexed_public_data_leaf(const fr &slot, const fr &value, index_t nextIndex, const fr &nextValue)
void check_unfinalized_block_height(TypeOfTree &tree, index_t expected_block_height)
void test_nullifier_tree_unwind(std::string directory, std::string name, uint64_t mapSize, uint64_t maxReaders, uint32_t depth, uint32_t blockSize, uint32_t numBlocks, uint32_t numBlocksToUnwind, std::vector< fr > values)
void check_size(TypeOfTree &tree, index_t expected_size, bool includeUncommitted=true)
ContentAddressedIndexedTree< Store, HashPolicy > TreeType
void remove_historic_block(TypeOfTree &tree, const block_number_t &blockNumber, bool expected_success=true)
void block_sync_values(TypeOfTree &tree, const std::vector< LeafValueType > &values, bool expectedSuccess=true)
fr hash_leaf(const IndexedLeaf< LeafValueType > &leaf)
void finalize_block(TypeOfTree &tree, const block_number_t &blockNumber, bool expected_success=true)
void unwind_block(TypeOfTree &tree, const block_number_t &blockNumber, bool expected_success=true)
TreeType::AddSequentiallyCompletionCallbackWithWitness SequentialCompletionCallback
bool verify_sibling_path(TreeType &tree, const IndexedNullifierLeafType &leaf_value, const uint32_t idx)
ThreadPoolPtr make_thread_pool(uint64_t numThreads)
const fr & get_value(size_t index)
void check_indices_data(LMDBTreeStore::SharedPtr db, fr leaf, index_t index, bool entryShouldBePresent, bool indexShouldBePresent)
void check_historic_find_leaf_index_from(TypeOfTree &tree, const std::vector< LeafValueType > &leaves, block_number_t blockNumber, index_t start_index, const std::vector< std::optional< index_t > > &expected_indices, bool expected_success, bool includeUncommitted=true)
std::string random_temp_directory()
uint32_t checkpoint_tree(TreeType &tree)
void check_find_leaf_index(TypeOfTree &tree, const std::vector< LeafValueType > &leaves, const std::vector< std::optional< index_t > > &expected_indices, bool expected_success, bool includeUncommitted=true)
void check_block_and_root_data(LMDBTreeStore::SharedPtr db, block_number_t blockNumber, fr root, bool expectedSuccess)
void check_find_leaf_index_from(TypeOfTree &tree, const std::vector< LeafValueType > &leaves, index_t start_index, const std::vector< std::optional< index_t > > &expected_indices, bool expected_success, bool includeUncommitted=true)
std::string random_string()
std::shared_ptr< ThreadPool > ThreadPoolPtr
void check_block_and_size_data(LMDBTreeStore::SharedPtr db, block_number_t blockNumber, index_t expectedSize, bool expectedSuccess)
void commit_checkpoint_tree(TreeType &tree, bool expected_success=true)
std::vector< fr > fr_sibling_path
void revert_checkpoint_tree(TreeType &tree, bool expected_success=true)
void check_historic_find_leaf_index(TypeOfTree &tree, const std::vector< LeafValueType > &leaves, block_number_t blockNumber, const std::vector< std::optional< index_t > > &expected_indices, bool expected_success, bool includeUncommitted=true)
fr_sibling_path get_sibling_path(TypeOfTree &tree, index_t index, bool includeUncommitted=true, bool expected_success=true)
Key get_key(int64_t keyCount)
Entry point for Barretenberg command-line interface.
TEST_F(IPATest, ChallengesAreZero)
field< Bn254FrParams > fr
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
typename Tree::UpdatesCompletionCallback UpdatesCompletionCallback
typename Tree::UpdatesCompletionResponse UpdatesCompletionResponse
static void perform_updates_without_witness(Tree &tree, const index_t &highest_index, std::shared_ptr< std::vector< LeafUpdate > > updates, const UpdatesCompletionCallback &completion)
typename Tree::LeafUpdate LeafUpdate
static IndexedLeaf< LeafType > empty()
std::vector< fr > get_hash_inputs() const
static fr hash_pair(const fr &lhs, const fr &rhs)
static fr hash(const std::vector< fr > &inputs)
static field random_element(numeric::RNG *engine=nullptr) noexcept
static constexpr field zero()