/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . Copyright 2017-2020 Telegram Systems LLP */ #pragma once #include "td/utils/optional.h" #include "td/utils/Slice.h" #include "vm/cells.h" #include "Bitset.h" namespace ton { // merkle_node$_ {n:#} left:^(ton::MerkleTree n) right:^(ton::MerkleTree n) = ton::MerkleTree (n + 1); // merkle_leaf$_ hash:bits256 = ton::MerkleTree 0; class MerkleTree { public: td::uint32 get_depth() const; td::Ref get_root(size_t depth_limit = std::numeric_limits::max()) const; td::Bits256 get_root_hash() const; MerkleTree(size_t chunks_count, td::Bits256 root_hash); MerkleTree(size_t chunks_count, td::Ref root_proof); struct Chunk { std::size_t index{0}; td::Bits256 hash; }; explicit MerkleTree(td::Span chunks); MerkleTree() = default; void init_begin(size_t chunks_count); void init_add_chunk(std::size_t index, td::Slice hash); void init_finish(); // merge external proof with an existing proof td::Status add_proof(td::Ref new_root); // generate proof for all chunks from l to r inclusive td::Result> gen_proof(size_t l, size_t r); // Trying to add and validate list of chunks simultaniously td::Status try_add_chunks(td::Span chunks); // Returns bitmask of successfully added chunks // Intended to be used during validation of a torrent. // We got arbitrary chunks read from disk, and we got an arbirary proof. // Now we can say about some chunks that they are correct. This ia a general way // to do this. // // NB: already added chunks are simply validated. One should be careful // not to process them twice void add_chunks(td::Span chunks, td::Bitset &bitmask); private: td::uint64 total_blocks_; std::size_t n_; // n = 2^log_n td::uint32 log_n_; std::size_t mark_id_{0}; std::vector mark_; // n_ * 2 std::vector> proof_; // n_ * 2 td::optional root_hash_; td::Ref root_proof_; td::Status validate_proof(td::Ref new_root); bool has_chunk(std::size_t index) const; void remove_chunk(std::size_t index); void add_chunk(std::size_t index, td::Slice hash); void init_proof(); td::Ref merge(td::Ref root, size_t index); void cleanup_add(size_t index); td::Status do_gen_proof(td::Ref node, size_t il, size_t ir, size_t l, size_t r) const; void do_gen_proof(td::Ref node, td::Ref node_raw, size_t depth_limit) const; td::Status validate_existing_chunk(const Chunk &chunk); }; } // namespace ton