16 #include "scale/encode_append.hpp" 27 if (state_version_int == 0) {
29 }
else if (state_version_int == 1) {
31 throw std::runtime_error(
"StateVersion::V1 is not implemented");
34 throw std::runtime_error(fmt::format(
35 "Invalid state version: {}. Expected 0 or 1", state_version_int));
42 std::shared_ptr<runtime::TrieStorageProvider> storage_provider,
43 std::shared_ptr<const runtime::MemoryProvider> memory_provider)
44 : storage_provider_(
std::move(storage_provider)),
45 memory_provider_(
std::move(memory_provider)),
59 logger_->error(res.error().message());
76 auto key = memory.loadN(key_ptr, key_size);
77 std::optional<uint32_t> res{std::nullopt};
78 if (
auto data_opt_res =
get(key); data_opt_res.has_value()) {
79 auto &data_opt = data_opt_res.value();
80 if (data_opt.has_value()) {
82 data = data.subspan(std::min<size_t>(offset, data.size()));
83 auto written = std::min<size_t>(data.size(), value.size);
84 memory.storeBuffer(value.ptr, data.subspan(0, written));
91 logger_, std::string_view{
"none"}, key, value_out, offset);
95 "Error in ext_storage_read_version_1: {}",
96 data_opt_res.error().message());
98 return memory.storeBuffer(scale::encode(res).value());
104 return batch->tryGet(key);
110 return memory.loadN(key_ptr, key_size);
116 auto cursor = batch->trieCursor();
117 OUTCOME_TRY(cursor->seekUpperBound(key));
118 return cursor->key();
126 auto key = memory.loadN(key_ptr, key_size);
127 auto value = memory.loadN(value_ptr, value_size);
132 auto put_result = batch->put(key, value);
133 if (not put_result) {
135 "ext_set_storage failed, due to fail in trie db with reason: {}",
136 put_result.error().message());
144 auto key_buffer = memory.loadN(key_ptr, key_size);
146 constexpr
auto error_message =
147 "ext_storage_get_version_1( {} ) => value was not obtained. Reason: {}";
149 auto result =
get(key_buffer);
155 error_message, key_buffer.toHex(), result.error().message());
158 auto &option = result.value();
160 return memory.storeBuffer(scale::encode(option).value());
168 auto key = memory.loadN(key_ptr, key_size);
169 auto del_result = batch->remove(key);
171 if (not del_result) {
173 "ext_storage_clear_version_1 did not delete key {} from trie db " 176 del_result.error().message());
185 auto key = memory.loadN(key_ptr, key_size);
186 auto res = batch->contains(key);
187 return (res.has_value() and res.value()) ? 1 : 0;
194 auto prefix = memory.loadN(prefix_ptr, prefix_size);
204 auto prefix = memory.loadN(prefix_ptr, prefix_size);
205 auto enc_limit = memory.loadN(limit_ptr, limit_size);
206 auto limit_res = scale::decode<std::optional<uint32_t>>(enc_limit);
208 auto msg = fmt::format(
209 "ext_storage_clear_prefix_version_2 failed at decoding second " 213 throw std::runtime_error(msg);
215 auto limit_opt = std::move(limit_res.value());
230 [[maybe_unused]]
auto state_version = toStateVersion(version);
232 outcome::result<storage::trie::RootHash> res{{}};
235 opt_batch.has_value() and opt_batch.value() !=
nullptr) {
236 res = opt_batch.value()->commit();
238 logger_->warn(
"ext_storage_root called in an ephemeral extension");
241 if (res.has_error()) {
242 logger_->error(
"ext_storage_root resulted with an error: {}",
243 res.error().message());
245 const auto &root = res.value();
247 return memory.storeBuffer(root);
254 return memory.storeBuffer(scale::encode(std::optional<Buffer>()).value());
263 auto key_bytes = memory.loadN(key_ptr, key_size);
265 if (res.has_error()) {
266 logger_->error(
"ext_storage_next_key resulted with error: {}",
267 res.error().message());
270 auto &&next_key_opt = res.value();
271 if (
auto enc_res = scale::encode(next_key_opt); enc_res.has_value()) {
273 res.value().has_value()
274 ? res.value().value()
277 return memory.storeBuffer(enc_res.value());
280 "ext_storage_next_key result encoding resulted with error: {}",
281 enc_res.error().message());
291 auto key_bytes = memory.loadN(key_ptr, key_size);
292 auto append_bytes = memory.loadN(append_ptr, append_size);
294 auto val_opt_res =
get(key_bytes);
295 if (val_opt_res.has_error()) {
296 throw std::runtime_error{
297 fmt::format(
"Error fetching value from storage: {}",
298 val_opt_res.error().message())};
300 auto &val_opt = val_opt_res.value();
303 if (scale::append_or_new_vec(val.asVector(), append_bytes).has_value()) {
306 auto put_result = batch->put(key_bytes, std::move(val));
307 if (not put_result) {
309 "ext_storage_append_version_1 failed, due to fail in trie db " 311 put_result.error().message());
319 if (res.has_error()) {
320 logger_->error(
"Storage transaction start has failed: {}",
321 res.error().message());
322 throw std::runtime_error(res.error().message());
329 if (res.has_error()) {
330 logger_->error(
"Storage transaction rollback has failed: {}",
331 res.error().message());
332 throw std::runtime_error(res.error().message());
339 if (res.has_error()) {
340 logger_->error(
"Storage transaction commit has failed: {}",
341 res.error().message());
342 throw std::runtime_error(res.error().message());
350 using KeyValueCollection =
351 std::vector<std::pair<common::Buffer, common::Buffer>>;
356 using ValuesCollection = std::vector<common::Buffer>;
363 const auto &buffer = memory.loadN(ptr, size);
364 const auto &pairs = scale::decode<KeyValueCollection>(buffer);
366 logger_->error(
"failed to decode pairs: {}", pairs.error().message());
367 throw std::runtime_error(pairs.error().message());
370 auto &&pv = pairs.value();
373 static const auto empty_root =
375 auto res = memory.storeBuffer(empty_root);
379 for (
auto &&p : pv) {
380 auto &&key = p.first;
381 auto &&value = p.second;
383 auto put_res = trie.
put(key, value);
386 "Insertion of value {} with key {} into the trie failed due to " 390 put_res.error().message());
395 logger_->error(
"failed to encode trie root: {}", enc.error().message());
396 throw std::runtime_error(enc.error().message());
398 const auto &hash = codec.
hash256(enc.value());
400 auto res = memory.storeBuffer(hash);
416 const auto &buffer = memory.loadN(address, size);
417 const auto &values = scale::decode<ValuesCollection>(buffer);
419 logger_->error(
"failed to decode values: {}", values.error().message());
420 throw std::runtime_error(values.error().message());
422 const auto &collection = values.value();
424 [[maybe_unused]]
auto state_version = toStateVersion(version);
427 collection.begin(), collection.end());
428 if (!ordered_hash.has_value()) {
430 "ext_blake2_256_enumerated_trie_root resulted with an error: {}",
431 ordered_hash.error().message());
432 throw std::runtime_error(ordered_hash.error().message());
435 auto res = memory.storeBuffer(ordered_hash.value());
444 auto res = batch->clearPrefix(
445 prefix, limit ? std::optional<uint64_t>(limit.value()) : std::nullopt);
447 auto msg = fmt::format(
"ext_storage_clear_prefix failed: {}",
448 res.error().message());
450 throw std::runtime_error(msg);
452 auto enc_res = scale::encode(res.value());
454 auto msg = fmt::format(
"ext_storage_clear_prefix failed: {}",
455 enc_res.error().message());
457 throw std::runtime_error(msg);
459 return memory.storeBuffer(enc_res.value());
465 auto current_key = prefix;
467 while (key_res.has_value() and key_res.value().has_value()) {
468 auto &key_opt = key_res.value();
469 current_key = key_opt.value();
471 bool contains_prefix =
472 std::equal(prefix.begin(), prefix.end(), current_key.begin());
473 if (not contains_prefix) {
478 auto value_opt =
get(current_key).value();
479 if (value_opt and value_opt.value().get() == empty_hash) {
481 auto remove_res = batch->remove(current_key);
482 if (not remove_res) {
484 "Unable to remove empty child storage under key {}, error is {}",
486 remove_res.error().message());
489 logger_,
"Removed empty child trie under key {}", current_key);
void removeEmptyChildStorages()
runtime::WasmSpan ext_storage_read_version_1(runtime::WasmSpan key, runtime::WasmSpan value_out, runtime::WasmOffset offset)
Class represents arbitrary (including empty) byte buffer.
uint32_t WasmSize
Size type is uint32_t because we are working in 32 bit address space.
void ext_storage_append_version_1(runtime::WasmSpan key, runtime::WasmSpan value) const
WasmPointer ptr
address of buffer
void ext_storage_start_transaction_version_1()
runtime::WasmPointer ext_trie_blake2_256_ordered_root_version_1(runtime::WasmSpan values_data)
#define SL_TRACE_FUNC_CALL(logger, ret,...)
std::shared_ptr< runtime::TrieStorageProvider > storage_provider_
outcome::result< std::optional< common::Buffer > > getStorageNextKey(const common::Buffer &key) const
void ext_storage_clear_prefix_version_1(runtime::WasmSpan prefix)
uint32_t WasmOffset
Offset type is uint32_t because we are working in 32 bit address space.
runtime::WasmPointer ext_trie_blake2_256_root_version_1(runtime::WasmSpan values_data)
runtime::WasmSpan ext_storage_root_version_1()
runtime::WasmSpan clearPrefix(common::BufferView prefix, std::optional< uint32_t > limit)
storage::trie::PolkadotCodec codec_
runtime::WasmSpan ext_storage_changes_root_version_1(runtime::WasmSpan parent_hash)
runtime::WasmSize ext_storage_exists_version_1(runtime::WasmSpan key_data) const
void ext_storage_clear_version_1(runtime::WasmSpan key_data)
const common::Buffer kChildStorageDefaultPrefix
SLBuffer< std::numeric_limits< size_t >::max()> Buffer
std::shared_ptr< const runtime::MemoryProvider > memory_provider_
void ext_storage_commit_transaction_version_1()
runtime::WasmSpan ext_storage_get_version_1(runtime::WasmSpan key)
runtime::WasmPointer ext_trie_blake2_256_ordered_root_version_2(runtime::WasmSpan values_data, runtime::WasmI32 state_version)
uint64_t WasmSpan
combination of pointer and size, where less significant part represents wasm pointer, and most significant represents size
outcome::result< common::Buffer > encodeNode(const Node &node) const
Encode node to byte representation.
outcome::result< std::optional< common::BufferConstRef > > get(const common::BufferView &key) const
common::Hash256 hash256(const BufferView &buf) const override
Get the hash of a node.
runtime::WasmSpan ext_storage_clear_prefix_version_2(runtime::WasmSpan prefix, runtime::WasmSpan limit)
StorageExtension(std::shared_ptr< runtime::TrieStorageProvider > storage_provider, std::shared_ptr< const runtime::MemoryProvider > memory_provider)
uint32_t WasmPointer
type of wasm memory is 32 bit integer
NodePtr getRoot() override
void ext_storage_rollback_transaction_version_1()
void ext_storage_set_version_1(runtime::WasmSpan key, runtime::WasmSpan value)
runtime::WasmSpan ext_storage_root_version_2(runtime::WasmI32 state_version)
Logger createLogger(const std::string &tag)
#define SL_TRACE_VOID_FUNC_CALL(logger,...)
outcome::result< common::Buffer > calculateOrderedTrieHash(const It &begin, const It &end)
common::Buffer loadKey(runtime::WasmSpan key) const
outcome::result< void > put(const common::BufferView &key, const common::Buffer &value) override
Store value by key.
runtime::WasmSpan ext_storage_next_key_version_1(runtime::WasmSpan key) const