8 #include <boost/algorithm/string/predicate.hpp> 9 #include <unordered_map> 12 #include <jsonrpc-lean/fault.h> 21 case E::MAX_BLOCK_RANGE_EXCEEDED:
22 return "Maximum block range size (" 24 +
" blocks) exceeded";
25 case E::MAX_KEY_SET_SIZE_EXCEEDED:
26 return "Maximum key set size (" 29 case E::END_BLOCK_LOWER_THAN_BEGIN_BLOCK:
30 return "End block is lower (is an ancestor of) the begin block " 31 "(should be the other way)";
33 return "Unknown State API error";
39 std::shared_ptr<blockchain::BlockHeaderRepository> block_repo,
40 std::shared_ptr<const storage::trie::TrieStorage> trie_storage,
41 std::shared_ptr<blockchain::BlockTree> block_tree,
42 std::shared_ptr<runtime::Core> runtime_core,
43 std::shared_ptr<runtime::Metadata> metadata,
44 std::shared_ptr<runtime::RawExecutor> executor)
45 : header_repo_{std::move(block_repo)},
60 std::shared_ptr<api::ApiService>
const &api_service) {
61 BOOST_ASSERT(api_service !=
nullptr);
66 std::string_view method,
68 const std::optional<primitives::BlockHash> &opt_at)
const {
70 opt_at.has_value() ? opt_at.value() :
block_tree_->deepestLeaf().hash;
71 return executor_->callAtRaw(at, method, data);
75 const std::optional<common::BufferView> &prefix_opt,
77 const std::optional<common::BufferView> &prev_key_opt,
78 const std::optional<primitives::BlockHash> &block_hash_opt)
const {
80 const auto &prev_key = prev_key_opt.value_or(prefix);
81 const auto &block_hash =
82 block_hash_opt.value_or(
block_tree_->getLastFinalized().hash);
84 OUTCOME_TRY(header,
header_repo_->getBlockHeader(block_hash));
85 OUTCOME_TRY(initial_trie_reader,
86 storage_->getEphemeralBatchAt(header.state_root));
87 auto cursor = initial_trie_reader->trieCursor();
91 if (prev_key > prefix) {
92 OUTCOME_TRY(cursor->seekUpperBound(prev_key));
96 OUTCOME_TRY(cursor->seekLowerBound(prefix));
99 std::vector<common::Buffer> result{};
100 result.reserve(keys_amount);
101 for (uint32_t i = 0; i < keys_amount && cursor->isValid(); ++i) {
102 auto key = cursor->key();
103 BOOST_ASSERT(key.has_value());
106 if (!boost::starts_with(key.value(), prefix)) {
109 result.push_back(cursor->key().value());
110 OUTCOME_TRY(cursor->next());
118 auto last_finalized =
block_tree_->getLastFinalized();
125 OUTCOME_TRY(trie_reader,
storage_->getEphemeralBatchAt(header.state_root));
126 auto res = trie_reader->tryGet(key);
128 [](
const auto &r) {
return r.get(); });
131 outcome::result<std::vector<StateApiImpl::StorageChangeSet>>
133 gsl::span<const common::Buffer> keys,
135 std::optional<primitives::BlockHash> opt_to)
const {
139 opt_to.has_value() ? opt_to.value() :
block_tree_->deepestLeaf().hash;
145 OUTCOME_TRY(from_number,
header_repo_->getNumberByHash(from));
146 OUTCOME_TRY(to_number,
header_repo_->getNumberByHash(to));
147 if (to_number < from_number) {
155 std::vector<StorageChangeSet> changes;
156 std::map<gsl::span<const uint8_t>, std::optional<common::Buffer>>
161 OUTCOME_TRY(range,
block_tree_->getChainByBlocks(from, to));
162 for (
auto &block : range) {
163 OUTCOME_TRY(header,
header_repo_->getBlockHeader(block));
164 OUTCOME_TRY(batch,
storage_->getEphemeralBatchAt(header.state_root));
166 for (
auto &key : keys) {
167 OUTCOME_TRY(opt_value, batch->tryGet(key));
168 auto it = last_values.find(key);
169 if (it == last_values.end() || it->second != opt_value) {
170 std::optional<common::Buffer> opt_buffer =
171 opt_value ? std::make_optional(opt_value.value().get())
173 change.changes.push_back(
176 last_values[key] = std::move(opt_value);
178 if (!change.changes.empty()) {
179 changes.emplace_back(std::move(change));
185 outcome::result<std::vector<StateApiImpl::StorageChangeSet>>
187 gsl::span<const common::Buffer> keys,
188 std::optional<primitives::BlockHash> opt_at)
const {
190 opt_at.has_value() ? opt_at.value() :
block_tree_->deepestLeaf().hash;
195 const std::optional<primitives::BlockHash> &at)
const {
203 const std::vector<common::Buffer> &keys) {
205 return api_service->subscribeSessionToKeys(keys);
208 throw jsonrpc::InternalErrorFault(
209 "Internal error. Api service not initialized.");
213 const std::vector<uint32_t> &subscription_id) {
215 return api_service->unsubscribeSessionFromIds(subscription_id);
217 throw jsonrpc::InternalErrorFault(
218 "Internal error. Api service not initialized.");
223 return api_service->subscribeRuntimeVersion();
226 throw jsonrpc::InternalErrorFault(
227 "Internal error. Api service not initialized.");
231 uint32_t subscription_id) {
233 OUTCOME_TRY(api_service->unsubscribeRuntimeVersion(subscription_id));
234 return outcome::success();
237 throw jsonrpc::InternalErrorFault(
238 "Internal error. Api service not initialized.");
247 std::string_view hex_block_hash) {
249 OUTCOME_TRY(data,
metadata_->metadata(h));
outcome::result< common::Buffer > call(std::string_view method, common::Buffer data, const std::optional< primitives::BlockHash > &opt_at) const override
Class represents arbitrary (including empty) byte buffer.
outcome::result< primitives::Version > getRuntimeVersion(const std::optional< primitives::BlockHash > &at) const override
OUTCOME_CPP_DEFINE_CATEGORY(kagome::api, StateApiImpl::Error, e)
StateApiImpl(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< runtime::RawExecutor > executor)
std::string_view to_string(SlotType s)
static constexpr size_t kMaxBlockRange
std::shared_ptr< runtime::Core > runtime_core_
static constexpr size_t kMaxKeySetSize
outcome::result< std::vector< common::Buffer > > getKeysPaged(const std::optional< common::BufferView > &prefix, uint32_t keys_amount, const std::optional< common::BufferView > &prev_key, const std::optional< primitives::BlockHash > &block_hash_opt) const override
outcome::result< uint32_t > subscribeRuntimeVersion() override
outcome::result< std::optional< common::Buffer > > getStorage(const common::BufferView &key) const override
outcome::result< void > unsubscribeRuntimeVersion(uint32_t subscription_id) override
static outcome::result< Blob< size_ > > fromHexWithPrefix(std::string_view hex)
outcome::result< std::vector< StorageChangeSet > > queryStorage(gsl::span< const common::Buffer > keys, const primitives::BlockHash &from, std::optional< primitives::BlockHash > to) const override
outcome::result< std::string > getMetadata() override
std::shared_ptr< blockchain::BlockHeaderRepository > header_repo_
outcome::result< uint32_t > subscribeStorage(const std::vector< common::Buffer > &keys) override
std::string hex_lower_0x(gsl::span< const uint8_t > bytes) noexcept
Converts bytes to hex representation with prefix 0x.
std::shared_ptr< blockchain::BlockTree > block_tree_
std::shared_ptr< runtime::Metadata > metadata_
outcome::result< bool > unsubscribeStorage(const std::vector< uint32_t > &subscription_id) override
static const Buffer kEmptyBuffer
std::shared_ptr< runtime::RawExecutor > executor_
std::weak_ptr< api::ApiService > api_service_
std::shared_ptr< const storage::trie::TrieStorage > storage_
outcome::result< std::vector< StorageChangeSet > > queryStorageAt(gsl::span< const common::Buffer > keys, std::optional< primitives::BlockHash > at) const override
void setApiService(std::shared_ptr< api::ApiService > const &api_service) override
outcome::result< std::optional< common::Buffer > > getStorageAt(const common::BufferView &key, const primitives::BlockHash &at) const override
outcome::result< std::optional< R > > map_result_optional(outcome::result< std::optional< T >> const &res_opt, F const &f)