7 #include <boost/algorithm/string/predicate.hpp> 8 #include <boost/bind/storage.hpp> 9 #include <libp2p/outcome/outcome.hpp> 25 case E::INVALID_CHILD_ROOTHASH:
26 return "Expected child root hash prefix.";
27 case E::NOTFOUND_CHILD_ROOTHASH:
28 return "Child storage root hash not found.";
30 return "unknown error";
36 std::shared_ptr<blockchain::BlockHeaderRepository> blocks_headers,
37 std::shared_ptr<storage::trie::TrieStorage> storage)
38 : blocks_headers_(
std::move(blocks_headers)),
39 storage_{std::move(storage)},
45 outcome::result<std::pair<KeyValueStateEntry, size_t>>
49 OUTCOME_TRY(batch,
storage_->getEphemeralBatchAt(hash));
51 auto cursor = batch->trieCursor();
56 auto res = key.empty() ? cursor->next() : cursor->seekUpperBound(key);
58 if (res.has_value()) {
59 while (cursor->key().has_value() && size < limit) {
60 if (
auto value_res = batch->tryGet(cursor->key().value());
61 value_res.has_value()) {
62 const auto &value_opt = value_res.value();
63 if (value_opt.has_value()) {
66 size += entry.
entries.back().key.size()
67 + entry.
entries.back().value.size();
72 entry.
complete = not cursor->key().has_value();
74 return res.as_failure();
80 outcome::result<network::StateResponse>
83 OUTCOME_TRY(batch,
storage_->getEphemeralBatchAt(header.state_root));
85 auto cursor = batch->trieCursor();
87 auto res = (request.
start.empty() || request.
start[0].empty()
89 : cursor->seekUpperBound(request.
start[0]));
97 response.
entries.emplace_back(std::move(entry));
101 if (request.
start.size() == 2) {
102 const auto &parent_key = request.
start[0];
104 if (!boost::starts_with(parent_key, child_prefix)) {
107 if (
auto value_res = batch->tryGet(parent_key);
108 value_res.has_value() && value_res.value().has_value()) {
115 response.
entries.emplace_back(std::move(entry_res.first));
116 size += entry_res.second;
122 if (!res.has_value()) {
123 return res.as_failure();
128 if (
auto value_res = batch->tryGet(cursor->key().value());
129 value_res.has_value()) {
130 const auto &value = value_res.value();
131 auto &entry = response.
entries.front();
135 entry.
entries.back().key.size() + entry.
entries.back().value.size();
137 if (boost::starts_with(cursor->key().value(), child_prefix)) {
140 value_res.value().value().get()));
141 OUTCOME_TRY(entry_res,
144 response.
entries.emplace_back(std::move(entry_res.first));
145 size += entry_res.second;
148 if (not entry_res.first.complete) {
153 res = cursor->next();
155 response.
entries.front().complete = not cursor->key().has_value();
std::vector< common::Buffer > start
primitives::BlockHash hash
Block header hash.
Class represents arbitrary (including empty) byte buffer.
StateProtocolObserverImpl(std::shared_ptr< blockchain::BlockHeaderRepository > blocks_headers, std::shared_ptr< storage::trie::TrieStorage > storage)
std::vector< StateEntry > entries
A collection of keys-values.
const common::Buffer kChildStorageDefaultPrefix
storage::trie::RootHash state_root
std::shared_ptr< storage::trie::TrieStorage > storage_
static outcome::result< Blob< size_ > > fromSpan(const gsl::span< const uint8_t > &span)
outcome::result< std::pair< KeyValueStateEntry, size_t > > getEntry(const storage::trie::RootHash &hash, const common::Buffer &key, size_t limit) const
outcome::result< StateResponse > onStateRequest(const StateRequest &request) const override
std::shared_ptr< blockchain::BlockHeaderRepository > blocks_headers_
constexpr unsigned MAX_RESPONSE_BYTES
Logger createLogger(const std::string &tag)
std::vector< KeyValueStateEntry > entries
OUTCOME_CPP_DEFINE_CATEGORY(kagome::network, StateProtocolObserverImpl::Error, e)
bool complete
Set to true when there are no more keys to return.