Kagome
Polkadot Runtime Engine in C++17
runtime_environment_factory.cpp
Go to the documentation of this file.
1 
7 
11 
14  e) {
16 
17  switch (e) {
18  case E::PARENT_FACTORY_EXPIRED:
19  return "The parent factory has expired";
20  case E::ABSENT_BLOCK:
21  return "Failed to obtain the required block from storage";
22  case E::ABSENT_HEAP_BASE:
23  return "Failed to extract heap base from a module";
24  case E::FAILED_TO_SET_STORAGE_STATE:
25  return "Failed to set the storage state to the desired value";
26  }
27  return "Unknown runtime environment construction error";
28 }
29 
30 namespace kagome::runtime {
31  using namespace kagome::common::literals;
32 
34  std::shared_ptr<ModuleInstance> module_instance,
35  std::shared_ptr<const MemoryProvider> memory_provider,
36  std::shared_ptr<TrieStorageProvider> storage_provider,
37  primitives::BlockInfo blockchain_state)
38  : module_instance{std::move(module_instance)},
39  memory_provider{std::move(memory_provider)},
41  blockchain_state_{std::move(blockchain_state)} {
42  BOOST_ASSERT(this->module_instance);
43  BOOST_ASSERT(this->memory_provider);
44  BOOST_ASSERT(this->storage_provider);
45  }
46 
49  std::weak_ptr<const RuntimeEnvironmentFactory> parent_factory,
50  const primitives::BlockInfo &blockchain_state,
51  const storage::trie::RootHash &storage_state)
52  : blockchain_state_{blockchain_state},
53  storage_state_{storage_state},
54  parent_factory_{std::move(parent_factory)} {
55  BOOST_ASSERT(parent_factory_.lock() != nullptr);
56  }
57 
60  persistent_ = true;
61  return *this;
62  }
63 
64  outcome::result<std::unique_ptr<RuntimeEnvironment>>
66  KAGOME_PROFILE_START(runtime_env_making);
67  auto parent_factory = parent_factory_.lock();
68  if (parent_factory == nullptr) {
70  }
71  auto header_res =
72  parent_factory->header_repo_->getBlockHeader(blockchain_state_.hash);
73  if (!header_res) {
74  parent_factory->logger_->error(
75  "Failed to obtain the block {} when initializing a runtime "
76  "environment; Reason: {}",
78  header_res.error().message());
79  return Error::ABSENT_BLOCK;
80  }
81 
82  OUTCOME_TRY(instance,
83  parent_factory->module_repo_->getInstanceAt(
84  parent_factory->code_provider_,
86  header_res.value()));
87 
88  const auto &env = instance->getEnvironment();
89  if (persistent_) {
90  if (auto res = env.storage_provider->setToPersistentAt(storage_state_);
91  !res) {
92  SL_DEBUG(parent_factory->logger_,
93  "Failed to set the storage state to hash {:l} when initializing a "
94  "runtime environment; Reason: {}",
96  res.error().message());
98  }
99  } else {
100  if (auto res = env.storage_provider->setToEphemeralAt(storage_state_);
101  !res) {
102  SL_DEBUG(parent_factory->logger_,
103  "Failed to set the storage state to hash {:l} when initializing a "
104  "runtime environment; Reason: {}",
106  res.error().message());
108  }
109  }
110 
111  OUTCOME_TRY(opt_heap_base, instance->getGlobal("__heap_base"));
112  if (!opt_heap_base.has_value()) {
113  parent_factory->logger_->error(
114  "__heap_base global variable is not found in a runtime module");
116  }
117  int32_t heap_base = boost::get<int32_t>(opt_heap_base.value());
118 
119  OUTCOME_TRY(env.memory_provider->resetMemory(heap_base));
120 
121  auto heappages_key = ":heappages"_buf;
122  auto heappages_res =
123  env.storage_provider->getCurrentBatch()->get(heappages_key);
124  if (heappages_res.has_value()) {
125  const auto &heappages = heappages_res.value().get();
126  if (sizeof(uint64_t) != heappages.size()) {
127  parent_factory->logger_->error(
128  "Unable to read :heappages value. Type size mismatch. "
129  "Required {} bytes, but {} available",
130  sizeof(uint64_t),
131  heappages.size());
132  } else {
133  uint64_t pages = common::le_bytes_to_uint64(heappages.asVector());
134  env.memory_provider->getCurrentMemory()->get().resize(
135  pages * kMemoryPageSize);
136  parent_factory->logger_->trace(
137  "Creating wasm module with non-default :heappages value set to {}",
138  pages);
139  }
141  != heappages_res.error()) {
142  return heappages_res.error();
143  }
144 
145  auto &memory = env.memory_provider->getCurrentMemory()->get();
146  instance->forDataSegment([&memory](auto offset, auto segment) {
147  memory.storeBuffer(offset, segment);
148  });
149 
150  SL_DEBUG(parent_factory->logger_,
151  "Runtime environment at {}, state: {:l}",
154 
155  auto runtime_env = std::make_unique<RuntimeEnvironment>(
156  instance, env.memory_provider, env.storage_provider, blockchain_state_);
157  KAGOME_PROFILE_END(runtime_env_making);
158  return runtime_env;
159  }
160 
162  std::shared_ptr<const runtime::RuntimeCodeProvider> code_provider,
163  std::shared_ptr<ModuleRepository> module_repo,
164  std::shared_ptr<const blockchain::BlockHeaderRepository> header_repo)
165  : code_provider_{std::move(code_provider)},
166  module_repo_{std::move(module_repo)},
167  header_repo_{std::move(header_repo)},
168  logger_{log::createLogger("RuntimeEnvironmentFactory", "runtime")} {
169  BOOST_ASSERT(code_provider_ != nullptr);
170  BOOST_ASSERT(module_repo_ != nullptr);
171  BOOST_ASSERT(header_repo_ != nullptr);
172  }
173 
174  std::unique_ptr<RuntimeEnvironmentFactory::RuntimeEnvironmentTemplate>
176  const primitives::BlockInfo &blockchain_state,
177  const storage::trie::RootHash &storage_state) const {
178  return std::make_unique<RuntimeEnvironmentTemplate>(
179  weak_from_this(), blockchain_state, storage_state);
180  }
181 
182  outcome::result<
183  std::unique_ptr<RuntimeEnvironmentFactory::RuntimeEnvironmentTemplate>>
185  const primitives::BlockHash &block_hash) const {
186  OUTCOME_TRY(header, header_repo_->getBlockHeader(block_hash));
187  return start({header.number, std::move(block_hash)},
188  std::move(header.state_root));
189  }
190 
191  outcome::result<
192  std::unique_ptr<RuntimeEnvironmentFactory::RuntimeEnvironmentTemplate>>
194  auto genesis_hash = header_repo_->getHashByNumber(0);
195  if (!genesis_hash) {
196  logger_->error(
197  "Failed to obtain the genesis block for runtime executor "
198  "initialization; Reason: {}",
199  genesis_hash.error().message());
200  return Error::ABSENT_BLOCK;
201  }
202  return start(genesis_hash.value());
203  }
204 
205 } // namespace kagome::runtime
#define KAGOME_PROFILE_END(scope)
virtual outcome::result< std::unique_ptr< RuntimeEnvironmentTemplate > > start() const
returns a handle to make a RuntimeEnvironment at genesis block state
uint64_t le_bytes_to_uint64(gsl::span< const uint8_t, 8 > bytes)
Definition: mp_utils.cpp:58
const std::shared_ptr< const MemoryProvider > memory_provider
const std::shared_ptr< TrieStorageProvider > storage_provider
RuntimeEnvironment(std::shared_ptr< ModuleInstance > module_instance, std::shared_ptr< const MemoryProvider > memory_provider, std::shared_ptr< TrieStorageProvider > storage_provider, primitives::BlockInfo blockchain_state)
RuntimeEnvironmentFactory(std::shared_ptr< const runtime::RuntimeCodeProvider > code_provider, std::shared_ptr< ModuleRepository > module_repo, std::shared_ptr< const blockchain::BlockHeaderRepository > header_repo)
std::shared_ptr< const blockchain::BlockHeaderRepository > header_repo_
virtual outcome::result< std::unique_ptr< RuntimeEnvironment > > make()
std::shared_ptr< const runtime::RuntimeCodeProvider > code_provider_
constexpr size_t kMemoryPageSize
Definition: memory.hpp:26
std::shared_ptr< ModuleRepository > module_repo_
OUTCOME_CPP_DEFINE_CATEGORY(kagome::runtime, RuntimeEnvironmentFactory::Error, e)
#define KAGOME_PROFILE_START(scope)
RuntimeEnvironmentTemplate(std::weak_ptr< const RuntimeEnvironmentFactory > parent_factory_, const primitives::BlockInfo &blockchain_state, const storage::trie::RootHash &storage_state)
Logger createLogger(const std::string &tag)
Definition: logger.cpp:112
const std::shared_ptr< ModuleInstance > module_instance