Kagome
Polkadot Runtime Engine in C++17
child_state_api_impl.cpp
Go to the documentation of this file.
1 
7 
8 #include <boost/algorithm/string/predicate.hpp>
9 #include <unordered_map>
10 #include <utility>
11 
12 #include "common/hexutil.hpp"
13 #include "common/monadic_utils.hpp"
15 
16 namespace kagome::api {
17 
19  std::shared_ptr<blockchain::BlockHeaderRepository> block_repo,
20  std::shared_ptr<const storage::trie::TrieStorage> trie_storage,
21  std::shared_ptr<blockchain::BlockTree> block_tree,
22  std::shared_ptr<runtime::Core> runtime_core,
23  std::shared_ptr<runtime::Metadata> metadata)
24  : header_repo_{std::move(block_repo)},
25  storage_{std::move(trie_storage)},
26  block_tree_{std::move(block_tree)},
27  runtime_core_{std::move(runtime_core)},
28  metadata_{std::move(metadata)} {
29  BOOST_ASSERT(nullptr != header_repo_);
30  BOOST_ASSERT(nullptr != storage_);
31  BOOST_ASSERT(nullptr != block_tree_);
32  BOOST_ASSERT(nullptr != runtime_core_);
33  BOOST_ASSERT(nullptr != metadata_);
34  }
35 
37  const std::shared_ptr<api::ApiService> &api_service) {
38  BOOST_ASSERT(api_service != nullptr);
39  api_service_ = api_service;
40  }
41 
42  outcome::result<std::vector<common::Buffer>> ChildStateApiImpl::getKeys(
43  const common::Buffer &child_storage_key,
44  const std::optional<common::Buffer> &prefix_opt,
45  const std::optional<primitives::BlockHash> &block_hash_opt) const {
46  const auto &prefix = prefix_opt.value_or(common::kEmptyBuffer);
47  const auto &block_hash =
48  block_hash_opt.value_or(block_tree_->getLastFinalized().hash);
49 
50  OUTCOME_TRY(header, header_repo_->getBlockHeader(block_hash));
51  OUTCOME_TRY(initial_trie_reader,
52  storage_->getEphemeralBatchAt(header.state_root));
53  OUTCOME_TRY(child_root, initial_trie_reader->get(child_storage_key));
54  OUTCOME_TRY(child_root_hash,
55  common::Hash256::fromSpan(gsl::make_span(child_root.get())));
56  OUTCOME_TRY(child_storage_trie_reader,
57  storage_->getEphemeralBatchAt(child_root_hash));
58  auto cursor = child_storage_trie_reader->trieCursor();
59 
60  OUTCOME_TRY(cursor->seekLowerBound(prefix));
61 
62  std::vector<common::Buffer> result{};
63  while (cursor->isValid()) {
64  auto key = cursor->key();
65  BOOST_ASSERT(key.has_value());
66 
67  // make sure our key begins with prefix
68  if (!boost::starts_with(key.value(), prefix)) {
69  break;
70  }
71  result.push_back(cursor->key().value());
72  OUTCOME_TRY(cursor->next());
73  }
74 
75  return result;
76  }
77 
78  outcome::result<std::vector<common::Buffer>> ChildStateApiImpl::getKeysPaged(
79  const common::Buffer &child_storage_key,
80  const std::optional<common::Buffer> &prefix_opt,
81  uint32_t keys_amount,
82  const std::optional<common::Buffer> &prev_key_opt,
83  const std::optional<primitives::BlockHash> &block_hash_opt) const {
84  const auto &prefix = prefix_opt.value_or(common::kEmptyBuffer);
85  const auto &prev_key = prev_key_opt.value_or(prefix);
86  const auto &block_hash =
87  block_hash_opt.value_or(block_tree_->getLastFinalized().hash);
88 
89  OUTCOME_TRY(header, header_repo_->getBlockHeader(block_hash));
90  OUTCOME_TRY(initial_trie_reader,
91  storage_->getEphemeralBatchAt(header.state_root));
92  OUTCOME_TRY(child_root, initial_trie_reader->get(child_storage_key));
93  OUTCOME_TRY(child_root_hash,
94  common::Hash256::fromSpan(gsl::make_span(child_root.get())));
95  OUTCOME_TRY(child_storage_trie_reader,
96  storage_->getEphemeralBatchAt(child_root_hash));
97  auto cursor = child_storage_trie_reader->trieCursor();
98 
99  // if prev_key is bigger than prefix, then set cursor to the next key after
100  // prev_key
101  if (prev_key > prefix) {
102  OUTCOME_TRY(cursor->seekUpperBound(prev_key));
103  }
104  // otherwise set cursor to key that is next to or equal to prefix
105  else {
106  OUTCOME_TRY(cursor->seekLowerBound(prefix));
107  }
108 
109  std::vector<common::Buffer> result{};
110  result.reserve(keys_amount);
111  for (uint32_t i = 0; i < keys_amount && cursor->isValid(); ++i) {
112  auto key = cursor->key();
113  BOOST_ASSERT(key.has_value());
114 
115  // make sure our key begins with prefix
116  if (!boost::starts_with(key.value(), prefix)) {
117  break;
118  }
119  result.push_back(cursor->key().value());
120  OUTCOME_TRY(cursor->next());
121  }
122 
123  return result;
124  }
125 
126  outcome::result<std::optional<common::Buffer>> ChildStateApiImpl::getStorage(
127  const common::Buffer &child_storage_key,
128  const common::Buffer &key,
129  const std::optional<primitives::BlockHash> &block_hash_opt) const {
130  auto at = block_hash_opt ? block_hash_opt.value()
131  : block_tree_->getLastFinalized().hash;
132  OUTCOME_TRY(header, header_repo_->getBlockHeader(at));
133  OUTCOME_TRY(trie_reader, storage_->getEphemeralBatchAt(header.state_root));
134  OUTCOME_TRY(child_root, trie_reader->get(child_storage_key));
135  OUTCOME_TRY(child_root_hash,
136  common::Hash256::fromSpan(gsl::make_span(child_root.get())));
137  OUTCOME_TRY(child_storage_trie_reader,
138  storage_->getEphemeralBatchAt(child_root_hash));
139  auto res = child_storage_trie_reader->tryGet(key);
140  return common::map_result_optional(res,
141  [](const auto &r) { return r.get(); });
142  }
143 
144  outcome::result<std::optional<primitives::BlockHash>>
146  const common::Buffer &child_storage_key,
147  const common::Buffer &key,
148  const std::optional<primitives::BlockHash> &block_hash_opt) const {
149  OUTCOME_TRY(value_opt, getStorage(child_storage_key, key, block_hash_opt));
150  if (value_opt.has_value()) {
152  auto hash = codec.hash256(value_opt.value());
153  return hash;
154  }
155  return std::nullopt;
156  }
157 
158  outcome::result<std::optional<uint64_t>> ChildStateApiImpl::getStorageSize(
159  const common::Buffer &child_storage_key,
160  const common::Buffer &key,
161  const std::optional<primitives::BlockHash> &block_hash_opt) const {
162  auto at = block_hash_opt ? block_hash_opt.value()
163  : block_tree_->getLastFinalized().hash;
164  OUTCOME_TRY(header, header_repo_->getBlockHeader(at));
165  OUTCOME_TRY(trie_reader, storage_->getEphemeralBatchAt(header.state_root));
166  OUTCOME_TRY(child_root, trie_reader->get(child_storage_key));
167  OUTCOME_TRY(child_root_hash,
168  common::Hash256::fromSpan(gsl::make_span(child_root.get())));
169  OUTCOME_TRY(child_storage_trie_reader,
170  storage_->getEphemeralBatchAt(child_root_hash));
171  OUTCOME_TRY(value, child_storage_trie_reader->get(key));
172  return value.get().size();
173  }
174 } // namespace kagome::api
Class represents arbitrary (including empty) byte buffer.
Definition: buffer.hpp:29
std::shared_ptr< blockchain::BlockTree > block_tree_
std::weak_ptr< api::ApiService > api_service_
outcome::result< std::optional< common::Buffer > > getStorage(const common::Buffer &child_storage_key, const common::Buffer &key, const std::optional< primitives::BlockHash > &block_hash_opt) const override
Returns a child storage entry.
std::shared_ptr< blockchain::BlockHeaderRepository > header_repo_
std::shared_ptr< runtime::Metadata > metadata_
ChildStateApiImpl(std::shared_ptr< blockchain::BlockHeaderRepository > block_repo, std::shared_ptr< const storage::trie::TrieStorage > trie_storage, std::shared_ptr< blockchain::BlockTree > block_tree, std::shared_ptr< runtime::Core > runtime_core, std::shared_ptr< runtime::Metadata > metadata)
std::shared_ptr< const storage::trie::TrieStorage > storage_
std::shared_ptr< runtime::Core > runtime_core_
outcome::result< std::vector< common::Buffer > > getKeysPaged(const common::Buffer &child_storage_key, const std::optional< common::Buffer > &prefix_opt, uint32_t keys_amount, const std::optional< common::Buffer > &prev_key_opt, const std::optional< primitives::BlockHash > &block_hash_opt) const override
Warning: This method is UNSAFE. Returns the keys from the specified child storage. Paginated version of getKeys. The keys can also be filtered based on a prefix.
outcome::result< std::vector< common::Buffer > > getKeys(const common::Buffer &child_storage_key, const std::optional< common::Buffer > &prefix_opt, const std::optional< primitives::BlockHash > &block_hash_opt) const override
Warning: This method is UNSAFE. Returns the keys from the specified child storage. The keys can also be filtered based on a prefix.
void setApiService(const std::shared_ptr< api::ApiService > &api_service) override
gsl::span< const uint8_t > make_span(const rocksdb::Slice &s)
static outcome::result< Blob< size_ > > fromSpan(const gsl::span< const uint8_t > &span)
Definition: blob.hpp:208
common::Hash256 hash256(const BufferView &buf) const override
Get the hash of a node.
static const Buffer kEmptyBuffer
Definition: buffer.hpp:246
outcome::result< std::optional< primitives::BlockHash > > getStorageHash(const common::Buffer &child_storage_key, const common::Buffer &key, const std::optional< primitives::BlockHash > &block_hash_opt) const override
Returns the hash of a child storage entry.
outcome::result< std::optional< uint64_t > > getStorageSize(const common::Buffer &child_storage_key, const common::Buffer &key, const std::optional< primitives::BlockHash > &block_hash_opt) const override
Returns the size of a child storage entry.
outcome::result< std::optional< R > > map_result_optional(outcome::result< std::optional< T >> const &res_opt, F const &f)