70 const std::vector<fr>& initial_values = {},
71 bool commit_genesis_state =
true);
110 bool includeUncommitted)
const;
121 bool includeUncommitted)
const;
132 uint32_t subtree_depth,
134 bool includeUncommitted)
const;
150 bool includeUncommitted,
170 bool includeUncommitted,
177 bool includeUncommitted,
185 bool includeUncommitted,
192 bool includeUncommitted,
200 bool includeUncommitted,
208 bool includeUncommitted,
217 bool includeUncommitted,
278 uint32_t subtree_depth,
285 bool updateNodesByIndexCache =
false)
const;
299template <
typename Store,
typename HashingPolicy>
301 std::unique_ptr<Store> store,
303 const std::vector<fr>& initial_values,
304 bool commit_genesis_state)
305 : store_(
std::move(store))
315 auto current = HashingPolicy::zero_hash();
316 for (
size_t i =
depth_; i > 0; --i) {
319 current = HashingPolicy::hash_pair(current, current);
330 if (initial_values.empty()) {
343 throw std::runtime_error(
format(
"Failed to initialize tree: ", result.
message));
353 if (commit_genesis_state) {
354 store_->commit_genesis_state();
358template <
typename Store,
typename HashingPolicy>
362 auto job = [=,
this]() {
363 execute_and_report<TreeMetaResponse>(
366 store_->get_meta(response.
inner.meta, *tx, includeUncommitted);
370 workers_->enqueue(job);
373template <
typename Store,
typename HashingPolicy>
375 bool includeUncommitted,
378 auto job = [=,
this]() {
379 execute_and_report<TreeMetaResponse>(
382 store_->get_meta(response.
inner.meta, *tx, includeUncommitted);
385 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
386 throw std::runtime_error(
387 format(
"Unable to get meta data for block ", blockNumber,
", failed to get block data."));
390 response.
inner.meta.size = blockData.
size;
391 response.
inner.meta.committedSize = blockData.
size;
392 response.
inner.meta.root = blockData.
root;
396 workers_->enqueue(job);
399template <
typename Store,
typename HashingPolicy>
402 bool includeUncommitted)
const
404 get_subtree_sibling_path(index, 0, on_completion, includeUncommitted);
407template <
typename Store,
typename HashingPolicy>
411 bool includeUncommitted)
const
413 auto job = [=,
this]() {
414 execute_and_report<GetSiblingPathResponse>(
416 if (blockNumber == 0) {
417 throw std::runtime_error(
"Unable to get sibling path at block 0");
421 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
422 throw std::runtime_error(
format(
"Unable to get sibling path for index ",
426 ", failed to get block data."));
432 requestContext.
root = blockData.
root;
433 OptionalSiblingPath optional_path = get_subtree_sibling_path_internal(index, 0, requestContext, *tx);
434 response.
inner.path = optional_sibling_path_to_full_sibling_path(optional_path);
438 workers_->enqueue(job);
441template <
typename Store,
typename HashingPolicy>
445 auto job = [=,
this]() {
446 execute_and_report<BlockForIndexResponse>(
448 response.
inner.blockNumbers.reserve(indices.size());
450 for (
index_t index : indices) {
452 response.
inner.blockNumbers.emplace_back(block);
457 workers_->enqueue(job);
460template <
typename Store,
typename HashingPolicy>
462 const std::vector<index_t>& indices,
466 auto job = [=,
this]() {
467 execute_and_report<BlockForIndexResponse>(
469 response.
inner.blockNumbers.reserve(indices.size());
472 if (!store_->get_block_data(blockNumber, blockPayload, *tx)) {
473 throw std::runtime_error(
format(
"Unable to find block numbers for indices for block ",
475 ", failed to get block data."));
478 for (
index_t index : indices) {
479 bool outOfRange = index >= maxIndex;
481 outOfRange ?
std::nullopt : store_->find_block_for_index(index, *tx);
482 response.
inner.blockNumbers.emplace_back(block);
487 workers_->enqueue(job);
490template <
typename Store,
typename HashingPolicy>
492 uint32_t subtree_depth,
const HashPathCallback& on_completion,
bool includeUncommitted)
const
494 auto job = [=,
this]() {
495 execute_and_report<GetSiblingPathResponse>(
499 store_->get_meta(meta, *tx, includeUncommitted);
502 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
504 get_subtree_sibling_path_internal(meta.
size, subtree_depth, requestContext, *tx);
505 response.
inner.path = optional_sibling_path_to_full_sibling_path(optional_path);
509 workers_->enqueue(job);
512template <
typename Store,
typename HashingPolicy>
515 uint32_t subtree_depth,
517 bool includeUncommitted)
const
519 auto job = [=,
this]() {
520 execute_and_report<GetSiblingPathResponse>(
525 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
528 get_subtree_sibling_path_internal(leaf_index, subtree_depth, requestContext, *tx);
529 response.
inner.path = optional_sibling_path_to_full_sibling_path(optional_path);
533 workers_->enqueue(job);
536template <
typename Store,
typename HashingPolicy>
540 if (optionalPath.empty()) {
544 size_t pathIndex = optionalPath.size() - 1;
545 for (
index_t level = 1; level <= optionalPath.size(); level++) {
547 path[pathIndex] = op.has_value() ? op.value() : zero_hashes_[level];
553template <
typename Store,
typename HashingPolicy>
558 bool updateNodesByIndexCache)
const
563 index_t child_index_at_level = 0;
564 for (uint32_t i = 0; i < depth_; ++i) {
576 bool is_right =
static_cast<bool>(leaf_index & mask);
584 if (!child.has_value()) {
588 if (updateNodesByIndexCache) {
589 child_index_at_level = is_right ? (child_index_at_level * 2) + 1 : (child_index_at_level * 2);
591 index_t sibling_index_at_level = is_right ? child_index_at_level - 1 : child_index_at_level + 1;
592 if (sibling.has_value()) {
593 store_->put_cached_node_by_index(i + 1, sibling_index_at_level, sibling.value(),
false);
600 hash = child.value();
602 if (!updateNodesByIndexCache) {
606 child_index_at_level = is_right ? (child_index_at_level * 2) + 1 : (child_index_at_level * 2);
609 store_->put_cached_node_by_index(i + 1, child_index_at_level,
hash,
false);
611 index_t sibling_index_at_level = is_right ? child_index_at_level - 1 : child_index_at_level + 1;
612 if (sibling.has_value()) {
616 store_->put_cached_node_by_index(i + 1, sibling_index_at_level, sibling.value(),
false);
624template <
typename Store,
typename HashingPolicy>
627 HashingPolicy>::get_subtree_sibling_path_internal(
const index_t& leaf_index,
628 uint32_t subtree_depth,
634 if (subtree_depth >= depth_) {
637 path.resize(depth_ - subtree_depth);
638 size_t path_index = path.size() - 1;
646 for (uint32_t level = 0; level < depth_ - subtree_depth; ++level) {
649 bool is_right =
static_cast<bool>(leaf_index & mask);
662 hash = child.has_value() ? child.value() : zero_hashes_[level + 1];
665 path[path_index--] = sibling;
671template <
typename Store,
typename HashingPolicy>
673 bool includeUncommitted,
676 auto job = [=,
this]() {
677 execute_and_report<GetLeafResponse>(
682 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
683 std::optional<fr> leaf_hash = find_leaf_hash(leaf_index, requestContext, *tx,
false);
684 response.
success = leaf_hash.has_value();
686 response.
inner.leaf = leaf_hash.value();
688 response.
message =
format(
"Failed to find leaf hash at index ", leaf_index);
693 workers_->enqueue(job);
696template <
typename Store,
typename HashingPolicy>
699 bool includeUncommitted,
702 auto job = [=,
this]() {
703 execute_and_report<GetLeafResponse>(
705 if (blockNumber == 0) {
706 throw std::runtime_error(
"Unable to get leaf at block 0");
710 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
711 throw std::runtime_error(
format(
"Unable to get leaf at index ",
715 ", failed to get block data."));
717 if (blockData.
size < leaf_index) {
722 ", leaf index out of range.");
729 requestContext.
root = blockData.
root;
730 std::optional<fr> leaf_hash = find_leaf_hash(leaf_index, requestContext, *tx,
false);
731 response.
success = leaf_hash.has_value();
733 response.
inner.leaf = leaf_hash.value();
736 format(
"Failed to find leaf hash at index ", leaf_index,
" for block number ", blockNumber);
741 workers_->enqueue(job);
744template <
typename Store,
typename HashingPolicy>
747 bool includeUncommitted,
750 find_leaf_indices_from(leaves, 0, includeUncommitted, on_completion);
753template <
typename Store,
typename HashingPolicy>
757 bool includeUncommitted,
760 find_leaf_indices_from(leaves, 0, blockNumber, includeUncommitted, on_completion);
763template <
typename Store,
typename HashingPolicy>
767 bool includeUncommitted,
770 auto job = [=,
this]() ->
void {
771 execute_and_report<FindLeafIndexResponse>(
773 response.
inner.leaf_indices.reserve(leaves.size());
779 for (
const auto& leaf : leaves) {
781 store_->find_leaf_index_from(leaf, start_index, requestContext, *tx);
782 response.
inner.leaf_indices.emplace_back(leaf_index);
787 workers_->enqueue(job);
790template <
typename Store,
typename HashingPolicy>
795 bool includeUncommitted,
798 auto job = [=,
this]() ->
void {
799 execute_and_report<FindLeafIndexResponse>(
801 response.
inner.leaf_indices.reserve(leaves.size());
802 if (blockNumber == 0) {
803 throw std::runtime_error(
"Unable to find leaf index for block number 0");
807 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
808 throw std::runtime_error(
format(
"Unable to find leaf from index ",
812 ", failed to get block data."));
820 for (
const auto& leaf : leaves) {
822 store_->find_leaf_index_from(leaf, start_index, requestContext, *tx);
823 response.
inner.leaf_indices.emplace_back(leaf_index);
828 workers_->enqueue(job);
831template <
typename Store,
typename HashingPolicy>
834 bool includeUncommitted,
837 auto job = [=,
this]() ->
void {
838 execute_and_report<FindLeafPathResponse>(
840 response.
inner.leaf_paths.reserve(leaves.size());
845 requestContext.
root = store_->get_current_root(*tx, includeUncommitted);
847 for (
const auto& leaf : leaves) {
849 if (!leaf_index.has_value()) {
854 get_subtree_sibling_path_internal(leaf_index.value(), 0, requestContext, *tx);
856 sibling_path_and_index.
path = optional_sibling_path_to_full_sibling_path(optional_path);
857 sibling_path_and_index.
index = leaf_index.value();
858 response.
inner.leaf_paths.emplace_back(sibling_path_and_index);
863 workers_->enqueue(job);
866template <
typename Store,
typename HashingPolicy>
870 bool includeUncommitted,
873 auto job = [=,
this]() ->
void {
874 execute_and_report<FindLeafPathResponse>(
876 response.
inner.leaf_paths.reserve(leaves.size());
877 if (blockNumber == 0) {
878 throw std::runtime_error(
"Unable to find leaf index for block number 0");
882 if (!store_->get_block_data(blockNumber, blockData, *tx)) {
883 throw std::runtime_error(
884 format(
"Unable to find sibling path for block ", blockNumber,
", failed to get block data."));
891 requestContext.
root = blockData.
root;
893 for (
const auto& leaf : leaves) {
895 if (!leaf_index.has_value()) {
900 get_subtree_sibling_path_internal(leaf_index.value(), 0, requestContext, *tx);
902 sibling_path_and_index.
path = optional_sibling_path_to_full_sibling_path(optional_path);
903 sibling_path_and_index.
index = leaf_index.value();
904 response.
inner.leaf_paths.emplace_back(sibling_path_and_index);
909 workers_->enqueue(job);
912template <
typename Store,
typename HashingPolicy>
919template <
typename Store,
typename HashingPolicy>
923 add_values_internal(values, on_completion,
true);
926template <
typename Store,
typename HashingPolicy>
931 auto append_op = [=,
this]() ->
void {
932 execute_and_report<AddDataResponse>(
934 add_values_internal(hashes, response.
inner.root, response.
inner.size, update_index);
938 workers_->enqueue(append_op);
941template <
typename Store,
typename HashingPolicy>
944 auto job = [=,
this]() {
945 execute_and_report<CommitResponse>(
947 store_->commit_block(response.
inner.meta, response.
inner.stats);
951 workers_->enqueue(job);
954template <
typename Store,
typename HashingPolicy>
957 auto job = [=,
this]() {
execute_and_report([=,
this]() { store_->rollback(); }, on_completion); };
958 workers_->enqueue(job);
966template <
typename Store,
typename HashingPolicy>
969 auto job = [=,
this]() {
execute_and_report([=,
this]() { store_->checkpoint(); }, on_completion); };
970 workers_->enqueue(job);
973template <
typename Store,
typename HashingPolicy>
977 auto job = [=,
this]() {
execute_and_report([=,
this]() { store_->commit_checkpoint(); }, on_completion); };
978 workers_->enqueue(job);
981template <
typename Store,
typename HashingPolicy>
985 auto job = [=,
this]() {
execute_and_report([=,
this]() { store_->revert_checkpoint(); }, on_completion); };
986 workers_->enqueue(job);
989template <
typename Store,
typename HashingPolicy>
993 auto job = [=,
this]() {
execute_and_report([=,
this]() { store_->commit_all_checkpoints(); }, on_completion); };
994 workers_->enqueue(job);
997template <
typename Store,
typename HashingPolicy>
1001 auto job = [=,
this]() {
execute_and_report([=,
this]() { store_->revert_all_checkpoints(); }, on_completion); };
1002 workers_->enqueue(job);
1005template <
typename Store,
typename HashingPolicy>
1009 auto job = [=,
this]() {
1010 execute_and_report<RemoveHistoricResponse>(
1012 if (blockNumber == 0) {
1013 throw std::runtime_error(
"Unable to remove historic block 0");
1015 store_->remove_historical_block(blockNumber, response.
inner.meta, response.
inner.stats);
1019 workers_->enqueue(job);
1022template <
typename Store,
typename HashingPolicy>
1026 auto job = [=,
this]() {
1027 execute_and_report<UnwindResponse>(
1029 if (blockNumber == 0) {
1030 throw std::runtime_error(
"Unable to unwind block 0");
1032 store_->unwind_block(blockNumber, response.
inner.meta, response.
inner.stats);
1036 workers_->enqueue(job);
1039template <
typename Store,
typename HashingPolicy>
1043 auto job = [=,
this]() {
1046 if (blockNumber == 0) {
1047 throw std::runtime_error(
"Unable to finalize block 0");
1049 store_->advance_finalized_block(blockNumber);
1053 workers_->enqueue(job);
1056template <
typename Store,
typename HashingPolicy>
1061 if (treeSize != 0U) {
1062 while (!(minPower2 & treeSize)) {
1065 if (minPower2 <= remainingAppendSize) {
1070 while (maxPower2 <= remainingAppendSize) {
1073 return maxPower2 >> 1;
1076template <
typename Store,
typename HashingPolicy>
1084 store_->get_meta(meta);
1086 new_size = meta.
size;
1088 while (sizeToAppend != 0U) {
1089 index_t batchSize = get_batch_insertion_size(new_size, sizeToAppend);
1090 sizeToAppend -= batchSize;
1091 int64_t start =
static_cast<int64_t
>(batchIndex);
1092 int64_t end =
static_cast<int64_t
>(batchIndex + batchSize);
1093 std::vector<fr> batch = std::vector<fr>(values->begin() + start, values->begin() + end);
1094 batchIndex += batchSize;
1095 add_batch_internal(batch, new_root, new_size, update_index, *tx);
1099template <
typename Store,
typename HashingPolicy>
1103 uint32_t start_level = depth_;
1104 uint32_t level = start_level;
1105 std::vector<fr>& hashes_local = values;
1106 auto number_to_insert =
static_cast<uint32_t
>(hashes_local.size());
1109 store_->get_meta(meta);
1111 new_size = meta.
size + number_to_insert;
1114 if (values.empty()) {
1118 if (new_size > max_size_) {
1119 throw std::runtime_error(
1120 format(
"Unable to append leaves to tree ", meta.
name,
" new size: ", new_size,
" max size: ", max_size_));
1124 for (uint32_t i = 0; i < number_to_insert; ++i) {
1128 store_->put_cached_node_by_index(level, i + index, hashes_local[i]);
1133 for (uint32_t i = 0; i < number_to_insert; ++i) {
1135 if (hashes_local[i] ==
fr::zero()) {
1139 store_->update_index(index + i, hashes_local[i]);
1144 while (number_to_insert > 1) {
1145 number_to_insert >>= 1;
1149 for (uint32_t i = 0; i < number_to_insert; ++i) {
1150 fr left = hashes_local[i * 2];
1151 fr right = hashes_local[i * 2 + 1];
1152 hashes_local[i] = HashingPolicy::hash_pair(left, right);
1154 store_->put_node_by_hash(hashes_local[i], { .left = left, .right = right, .ref = 1 });
1155 store_->put_cached_node_by_index(level, index + i, hashes_local[i]);
1161 fr new_hash = hashes_local[0];
1166 requestContext.
root = store_->get_current_root(tx,
true);
1168 get_subtree_sibling_path_internal(meta.
size, depth_ - level, requestContext, tx);
1169 fr_sibling_path sibling_path_to_root = optional_sibling_path_to_full_sibling_path(optional_sibling_path_to_root);
1170 size_t sibling_path_index = 0;
1176 bool is_right =
static_cast<bool>(index & 0x01);
1180 fr left_hash = is_right ? sibling_path_to_root[sibling_path_index] : new_hash;
1181 fr right_hash = is_right ? new_hash : sibling_path_to_root[sibling_path_index];
1183 std::optional<fr> left_op = is_right ? optional_sibling_path_to_root[sibling_path_index] : new_hash;
1184 std::optional<fr> right_op = is_right ? new_hash : optional_sibling_path_to_root[sibling_path_index];
1186 new_hash = HashingPolicy::hash_pair(left_hash, right_hash);
1191 ++sibling_path_index;
1192 store_->put_cached_node_by_index(level, index, new_hash);
1193 store_->put_node_by_hash(new_hash, { .left = left_op, .right = right_op, .ref = 1 });
1197 new_root = new_hash;
1198 meta.
root = new_hash;
1199 meta.
size = new_size;
1201 store_->put_meta(meta);
Implements a simple append-only merkle tree All methods are asynchronous unless specified as otherwis...
typename Store::ReadTransaction ReadTransaction
void get_leaf(const index_t &index, bool includeUncommitted, const GetLeafCallback &completion) const
Returns the leaf value at the provided index.
void remove_historic_block(const block_number_t &blockNumber, const RemoveHistoricBlockCallback &on_completion)
std::function< void(TypedResponse< FindLeafPathResponse > &)> FindSiblingPathCallback
OptionalSiblingPath get_subtree_sibling_path_internal(const index_t &leaf_index, uint32_t subtree_depth, const RequestContext &requestContext, ReadTransaction &tx) const
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.
void add_values_internal(std::shared_ptr< std::vector< fr > > values, fr &new_root, index_t &new_size, bool update_index)
void add_batch_internal(std::vector< fr > &values, fr &new_root, index_t &new_size, bool update_index, ReadTransaction &tx)
std::function< void(Response &)> EmptyResponseCallback
std::shared_ptr< ThreadPool > workers_
void commit_checkpoint(const CheckpointCommitCallback &on_completion)
void commit_all_checkpoints(const CheckpointCommitCallback &on_completion)
std::vector< fr > zero_hashes_
uint32_t depth() const
Synchronous method to retrieve the depth of the tree.
EmptyResponseCallback RollbackCallback
std::vector< std::optional< fr > > OptionalSiblingPath
virtual ~ContentAddressedAppendOnlyTree()=default
std::function< void(TypedResponse< GetLeafResponse > &)> GetLeafCallback
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.
ContentAddressedAppendOnlyTree & operator=(ContentAddressedAppendOnlyTree const &other)=delete
void get_meta_data(bool includeUncommitted, const MetaDataCallback &on_completion) const
Returns the tree meta data.
fr_sibling_path optional_sibling_path_to_full_sibling_path(const OptionalSiblingPath &optionalPath) const
std::unique_ptr< Store > store_
EmptyResponseCallback FinalizeBlockCallback
ContentAddressedAppendOnlyTree & operator=(ContentAddressedAppendOnlyTree const &&other)=delete
void find_block_numbers(const std::vector< index_t > &indices, const GetBlockForIndexCallback &on_completion) const
Returns the block numbers that correspond to the given indices values.
void unwind_block(const block_number_t &blockNumber, const UnwindBlockCallback &on_completion)
std::function< void(TypedResponse< FindLeafIndexResponse > &)> FindLeafCallback
std::function< void(TypedResponse< GetSiblingPathResponse > &)> HashPathCallback
std::function< void(TypedResponse< TreeMetaResponse > &)> MetaDataCallback
void revert_checkpoint(const CheckpointRevertCallback &on_completion)
std::function< void(TypedResponse< UnwindResponse > &)> UnwindBlockCallback
std::function< void(TypedResponse< AddDataResponse > &)> AppendCompletionCallback
void revert_all_checkpoints(const CheckpointRevertCallback &on_completion)
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
EmptyResponseCallback CheckpointRevertCallback
void rollback(const RollbackCallback &on_completion)
Rollback the uncommitted changes.
typename Store::ReadTransactionPtr ReadTransactionPtr
void find_leaf_indices(const std::vector< typename Store::LeafType > &leaves, bool includeUncommitted, const FindLeafCallback &on_completion) const
Returns the index of the provided leaf in the tree.
EmptyResponseCallback CheckpointCallback
void get_subtree_sibling_path(uint32_t subtree_depth, const HashPathCallback &on_completion, bool includeUncommitted) const
Get the subtree sibling path object.
std::function< void(TypedResponse< CommitResponse > &)> CommitCallback
index_t get_batch_insertion_size(const index_t &treeSize, const index_t &remainingAppendSize)
ContentAddressedAppendOnlyTree(ContentAddressedAppendOnlyTree &&other)=delete
void finalize_block(const block_number_t &blockNumber, const FinalizeBlockCallback &on_completion)
void checkpoint(const CheckpointCallback &on_completion)
void find_leaf_indices_from(const std::vector< typename Store::LeafType > &leaves, const index_t &start_index, bool includeUncommitted, const FindLeafCallback &on_completion) const
Returns the index of the provided leaf in the tree only if it exists after the index value provided.
std::function< void(TypedResponse< BlockForIndexResponse > &)> GetBlockForIndexCallback
ContentAddressedAppendOnlyTree(std::unique_ptr< Store > store, std::shared_ptr< ThreadPool > workers, const std::vector< fr > &initial_values={}, bool commit_genesis_state=true)
std::function< void(TypedResponse< RemoveHistoricResponse > &)> RemoveHistoricBlockCallback
ContentAddressedAppendOnlyTree(ContentAddressedAppendOnlyTree const &other)=delete
EmptyResponseCallback CheckpointCommitCallback
void find_leaf_sibling_paths(const std::vector< typename Store::LeafType > &leaves, bool includeUncommitted, const FindSiblingPathCallback &on_completion) const
Returns the sibling paths for the provided leaves in the tree.
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)
ContentAddressedCachedTreeStore< bb::fr > Store
void add_values(TreeType &tree, const std::vector< NullifierLeafValue > &values)
void hash(State &state) noexcept
void execute_and_report(const std::function< void(TypedResponse< ResponseType > &)> &f, const std::function< void(TypedResponse< ResponseType > &)> &on_completion)
std::vector< fr > fr_sibling_path
constexpr uint64_t pow64(const uint64_t input, const uint64_t exponent)
Entry point for Barretenberg command-line interface.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::optional< fr > right
std::optional< index_t > maxIndex
std::optional< block_number_t > blockNumber
static constexpr field zero()