10 #include "scale/scale.hpp" 13 using primitives::Block;
15 using storage::face::MapCursor;
16 using storage::face::WriteBatch;
21 std::shared_ptr<storage::BufferStorage> storage,
22 std::shared_ptr<crypto::Hasher> hasher)
23 : storage_{std::move(storage)},
27 BOOST_ASSERT(
hasher_ !=
nullptr);
32 const std::shared_ptr<storage::BufferStorage> &storage,
33 const std::shared_ptr<crypto::Hasher> &hasher) {
34 auto block_storage = std::shared_ptr<BlockStorageImpl>(
38 if (res.has_error()) {
39 return res.as_failure();
42 if (not res.value()) {
48 genesis_block.header.extrinsics_root = extrinsics_root;
49 genesis_block.header.state_root = state_root;
52 OUTCOME_TRY(genesis_block_hash, block_storage->putBlock(genesis_block));
53 OUTCOME_TRY(block_storage->putNumberToIndexKey({0, genesis_block_hash}));
55 OUTCOME_TRY(block_storage->setBlockTreeLeaves({genesis_block_hash}));
66 outcome::result<std::optional<primitives::BlockHeader>>
68 OUTCOME_TRY(encoded_header_opt,
70 if (encoded_header_opt.has_value()) {
73 scale::decode<primitives::BlockHeader>(encoded_header_opt.value()));
74 return std::move(header);
79 outcome::result<std::optional<primitives::BlockBody>>
82 if (block_data.has_value() && block_data.value().body.has_value()) {
83 return block_data.value().body.value();
88 outcome::result<std::optional<primitives::BlockData>>
90 OUTCOME_TRY(encoded_block_data_opt,
92 if (encoded_block_data_opt.has_value()) {
95 scale::decode<primitives::BlockData>(encoded_block_data_opt.value()));
96 return std::move(block_data);
101 outcome::result<std::optional<primitives::Justification>>
104 if (block_data.has_value()
105 && block_data.value().justification.has_value()) {
106 return block_data.value().justification.value();
113 SL_DEBUG(
logger_,
"Save num-to-idx for {}", block);
119 OUTCOME_TRY(encoded_header, scale::encode(header));
120 auto block_hash =
hasher_->blake2b_256(encoded_header);
125 Buffer{std::move(encoded_header)}));
138 if (not existing_block_data_opt.has_value()) {
139 to_insert = block_data;
141 auto &existing_data = existing_block_data_opt.value();
145 block_data.
header ? block_data.
header : existing_data.header;
146 to_insert.
body = block_data.
body ? block_data.
body : existing_data.body;
149 : existing_data.justification;
152 : existing_data.message_queue;
157 OUTCOME_TRY(encoded_block_data, scale::encode(to_insert));
162 Buffer{encoded_block_data}));
163 return outcome::success();
172 if (not existing_block_data_opt.has_value()) {
173 return outcome::success();
175 auto &existing_data = existing_block_data_opt.value();
177 auto move_if_flag = [](
bool flag,
auto &&value) {
179 return std::move(value);
181 return std::optional<typename std::decay_t<decltype(value)>::value_type>(
187 move_if_flag(!remove_flags.
header, std::move(existing_data.header));
189 move_if_flag(!remove_flags.
body, std::move(existing_data.body));
191 !remove_flags.
justification, std::move(existing_data.justification));
193 !remove_flags.
message_queue, std::move(existing_data.message_queue));
195 move_if_flag(!remove_flags.
receipt, std::move(existing_data.receipt));
197 OUTCOME_TRY(encoded_block_data, scale::encode(to_insert));
202 Buffer{encoded_block_data}));
203 return outcome::success();
212 block_data.
hash = block_hash;
217 logger_->info(
"Added block {} as child of {}",
221 return std::move(block_hash);
231 return outcome::success();
240 return outcome::success();
247 SL_TRACE(
logger_,
"Removing block {}...", block);
249 auto hash_to_idx_key =
251 if (
auto res =
storage_->remove(hash_to_idx_key); res.has_error()) {
252 logger_->error(
"could not remove hash-to-idx from the storage: {}",
253 res.error().message());
257 auto num_to_idx_key =
259 OUTCOME_TRY(num_to_idx_val_opt,
storage_->tryLoad(num_to_idx_key.view()));
260 if (num_to_idx_val_opt == block_lookup_key) {
261 if (
auto res =
storage_->remove(num_to_idx_key); res.has_error()) {
263 "could not remove num-to-idx from the storage: {}",
265 res.error().message());
268 SL_DEBUG(
logger_,
"Removed num-to-idx of {}", block);
275 if (
auto res =
storage_->remove(body_key); res.has_error()) {
277 "could not remove body of block {} from the storage: {}",
279 res.error().message());
284 if (
auto res =
storage_->remove(header_key); res.has_error()) {
286 "could not remove header of block {} from the storage: {}",
288 res.error().message());
292 logger_->info(
"Removed block {}", block);
294 return outcome::success();
297 outcome::result<std::vector<primitives::BlockHash>>
303 OUTCOME_TRY(leaves_opt,
305 if (not leaves_opt.has_value()) {
311 scale::decode<std::vector<primitives::BlockHash>>(leaves_opt.value()));
319 std::vector<primitives::BlockHash> leaves) {
322 return outcome::success();
325 OUTCOME_TRY(encoded_leaves, scale::encode(leaves));
327 Buffer{std::move(encoded_leaves)}));
331 return outcome::success();
337 auto current_hash = leaves[0];
340 if (j_opt.has_value()) {
344 if (header_opt.has_value()) {
345 auto header = header_opt.value();
346 if (header.number == 0) {
348 "Not found block with justification. " 349 "Genesis block will be used as last finalized ({})",
351 return {0, current_hash};
353 current_hash = header.parent_hash;
356 logger_,
"Failed to fetch header for block ({})", current_hash);
364 "Justification is found in block {}. " 365 "This block will be used as last finalized",
const common::Buffer kBlockTreeLeavesLookupKey
Class represents arbitrary (including empty) byte buffer.
outcome::result< void > putJustification(const primitives::Justification &j, const primitives::BlockHash &hash, primitives::BlockNumber number) override
std::optional< primitives::BlockHeader > header
Block class represents polkadot block primitive.
common::Buffer numberAndHashToLookupKey(primitives::BlockNumber number, const common::Hash256 &hash)
outcome::result< void > removeBlockData(primitives::BlockNumber block_number, const primitives::BlockDataFlags &remove_flags) override
outcome::result< void > setBlockTreeLeaves(std::vector< primitives::BlockHash > leaves) override
std::optional< common::Buffer > message_queue
outcome::result< void > removeJustification(const primitives::BlockHash &hash, primitives::BlockNumber number) override
static BlockDataFlags allUnset(primitives::BlockHash hash)
outcome::result< void > putBlockData(primitives::BlockNumber block_number, const primitives::BlockData &block_data) override
BlockStorageImpl(std::shared_ptr< storage::BufferStorage > storage, std::shared_ptr< crypto::Hasher > hasher)
common::Buffer numberToIndexKey(primitives::BlockNumber n)
outcome::result< void > putWithPrefix(storage::BufferStorage &map, prefix::Prefix prefix, BlockNumber num, Hash256 block_hash, const common::Buffer &value)
outcome::result< void > putNumberToIndexKey(storage::BufferStorage &map, const primitives::BlockInfo &block)
outcome::result< std::optional< primitives::Justification > > getJustification(const primitives::BlockId &block) const override
std::optional< common::Buffer > receipt
SLBuffer< std::numeric_limits< size_t >::max()> Buffer
outcome::result< void > putNumberToIndexKey(const primitives::BlockInfo &block) override
std::shared_ptr< storage::BufferStorage > storage_
outcome::result< std::optional< primitives::BlockData > > getBlockData(const primitives::BlockId &id) const override
static outcome::result< std::shared_ptr< BlockStorageImpl > > create(storage::trie::RootHash state_root, const std::shared_ptr< storage::BufferStorage > &storage, const std::shared_ptr< crypto::Hasher > &hasher)
std::optional< std::vector< primitives::BlockHash > > block_tree_leaves_
outcome::result< primitives::BlockInfo > getLastFinalized() const override
outcome::result< std::optional< common::Buffer > > getWithPrefix(const storage::BufferStorage &map, prefix::Prefix prefix, const primitives::BlockId &block_id)
outcome::result< bool > hasBlockHeader(const primitives::BlockId &id) const override
Check if header existing by provided block {.
outcome::result< std::vector< primitives::BlockHash > > getBlockTreeLeaves() const override
outcome::result< std::optional< primitives::BlockHeader > > getBlockHeader(const primitives::BlockId &id) const override
boost::variant< BlockHash, BlockNumber > BlockId
Block id is the variant over BlockHash and BlockNumber.
outcome::result< void > removeBlock(const primitives::BlockInfo &block) override
outcome::result< bool > hasWithPrefix(const storage::BufferStorage &map, prefix::Prefix prefix, const primitives::BlockId &block_id)
outcome::result< std::optional< primitives::BlockBody > > getBlockBody(const primitives::BlockId &id) const override
BlockHeader header
block header
Logger createLogger(const std::string &tag)
primitives::BlockHash hash
outcome::result< primitives::BlockHash > putBlockHeader(const primitives::BlockHeader &header) override
outcome::result< primitives::BlockHash > putBlock(const primitives::Block &block) override
storage::trie::RootHash trieRoot(const std::vector< std::pair< common::Buffer, common::Buffer >> &key_vals)
common::Buffer prependPrefix(common::BufferView key, prefix::Prefix key_column)
primitives::BlockHash hash
BlockBody body
extrinsics collection
std::optional< primitives::BlockBody > body
std::shared_ptr< crypto::Hasher > hasher_
std::optional< primitives::Justification > justification