From 6d7108293637a0f0400c455923e08a84441dc343 Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Mon, 31 Oct 2022 23:23:46 +0800
Subject: [PATCH 01/13] feature: runtime properties cache

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 core/injector/CMakeLists.txt                  |  1 +
 core/injector/application_injector.cpp        | 12 +++---
 .../binaryen/core_api_factory_impl.cpp        |  4 +-
 core/runtime/common/executor.hpp              |  8 +++-
 core/runtime/runtime_api/impl/CMakeLists.txt  |  7 ++++
 core/runtime/runtime_api/impl/core.cpp        |  2 +-
 .../impl/runtime_properties_cache_impl.cpp    | 33 +++++++++++++++
 .../impl/runtime_properties_cache_impl.hpp    | 34 +++++++++++++++
 core/runtime/runtime_properties_cache.hpp     | 41 +++++++++++++++++++
 core/runtime/wavm/core_api_factory_impl.cpp   |  4 +-
 10 files changed, 135 insertions(+), 11 deletions(-)
 create mode 100644 core/runtime/runtime_api/impl/runtime_properties_cache_impl.cpp
 create mode 100644 core/runtime/runtime_api/impl/runtime_properties_cache_impl.hpp
 create mode 100644 core/runtime/runtime_properties_cache.hpp

diff --git a/core/injector/CMakeLists.txt b/core/injector/CMakeLists.txt
index 003bbdb129..0e2929aa91 100644
--- a/core/injector/CMakeLists.txt
+++ b/core/injector/CMakeLists.txt
@@ -82,6 +82,7 @@ target_link_libraries(application_injector
     rpc_thread_pool
     runtime_upgrade_tracker
     runtime_environment_factory
+    runtime_properties_cache
     executor
     secp256k1_provider
     soralog::fallback_configurator
diff --git a/core/injector/application_injector.cpp b/core/injector/application_injector.cpp
index 038fb0e9cc..36b8eb92d8 100644
--- a/core/injector/application_injector.cpp
+++ b/core/injector/application_injector.cpp
@@ -134,6 +134,7 @@
 #include "runtime/runtime_api/impl/metadata.hpp"
 #include "runtime/runtime_api/impl/offchain_worker_api.hpp"
 #include "runtime/runtime_api/impl/parachain_host.hpp"
+#include "runtime/runtime_api/impl/runtime_properties_cache_impl.hpp"
 #include "runtime/runtime_api/impl/session_keys_api.hpp"
 #include "runtime/runtime_api/impl/tagged_transaction_queue.hpp"
 #include "runtime/runtime_api/impl/transaction_payment_api.hpp"
@@ -914,12 +915,10 @@ namespace {
           if (!initialized) {
             auto env_factory = injector.template create<
                 std::shared_ptr<runtime::RuntimeEnvironmentFactory>>();
-            auto header_repo = injector.template create<
-                std::shared_ptr<blockchain::BlockHeaderRepository>>();
-            auto storage = injector.template create<
-                std::shared_ptr<storage::trie::TrieStorage>>();
-            initialized =
-                std::make_shared<runtime::Executor>(std::move(env_factory));
+            auto cache = injector.template create<
+                std::shared_ptr<runtime::RuntimePropertiesCache>>();
+            initialized = std::make_shared<runtime::Executor>(
+                std::move(env_factory), std::move(cache));
           }
           return initialized.value();
         }),
@@ -942,6 +941,7 @@ namespace {
         di::bind<runtime::AccountNonceApi>.template to<runtime::AccountNonceApiImpl>(),
         di::bind<runtime::AuthorityDiscoveryApi>.template to<runtime::AuthorityDiscoveryApiImpl>(),
         di::bind<runtime::SingleModuleCache>.template to<runtime::SingleModuleCache>(),
+        di::bind<runtime::RuntimePropertiesCache>.template to<runtime::RuntimePropertiesCacheImpl>(),
         std::forward<Ts>(args)...);
   }
 
diff --git a/core/runtime/binaryen/core_api_factory_impl.cpp b/core/runtime/binaryen/core_api_factory_impl.cpp
index 0d01ec4886..8e3f9b74c2 100644
--- a/core/runtime/binaryen/core_api_factory_impl.cpp
+++ b/core/runtime/binaryen/core_api_factory_impl.cpp
@@ -12,6 +12,7 @@
 #include "runtime/common/executor.hpp"
 #include "runtime/common/trie_storage_provider_impl.hpp"
 #include "runtime/runtime_api/impl/core.hpp"
+#include "runtime/runtime_api/impl/runtime_properties_cache_impl.hpp"
 
 namespace kagome::runtime::binaryen {
 
@@ -75,7 +76,8 @@ namespace kagome::runtime::binaryen {
         std::make_shared<OneModuleRepository>(runtime_code,
                                               instance_env_factory_),
         header_repo_);
-    auto executor = std::make_unique<Executor>(env_factory);
+    auto cache = std::make_shared<runtime::RuntimePropertiesCacheImpl>();
+    auto executor = std::make_unique<Executor>(env_factory, cache);
     return std::make_unique<CoreImpl>(
         std::move(executor), changes_tracker_, header_repo_);
   }
diff --git a/core/runtime/common/executor.hpp b/core/runtime/common/executor.hpp
index 4fbf53797b..68826cb811 100644
--- a/core/runtime/common/executor.hpp
+++ b/core/runtime/common/executor.hpp
@@ -21,6 +21,7 @@
 #include "runtime/module_repository.hpp"
 #include "runtime/persistent_result.hpp"
 #include "runtime/runtime_environment_factory.hpp"
+#include "runtime/runtime_properties_cache.hpp"
 #include "runtime/trie_storage_provider.hpp"
 #include "scale/scale.hpp"
 #include "storage/trie/trie_batches.hpp"
@@ -37,8 +38,10 @@ namespace kagome::runtime {
    public:
     using Buffer = common::Buffer;
 
-    Executor(std::shared_ptr<RuntimeEnvironmentFactory> env_factory)
-        : env_factory_{std::move(env_factory)},
+    Executor(std::shared_ptr<RuntimeEnvironmentFactory> env_factory,
+             std::shared_ptr<RuntimePropertiesCache> cache)
+        : env_factory_(std::move(env_factory)),
+          cache_(std::move(cache)),
           logger_{log::createLogger("Executor", "runtime")} {
       BOOST_ASSERT(env_factory_ != nullptr);
     }
@@ -254,6 +257,7 @@ namespace kagome::runtime {
     }
 
     std::shared_ptr<RuntimeEnvironmentFactory> env_factory_;
+    std::shared_ptr<RuntimePropertiesCache> cache_;
     log::Logger logger_;
   };
 
diff --git a/core/runtime/runtime_api/impl/CMakeLists.txt b/core/runtime/runtime_api/impl/CMakeLists.txt
index 1afe4fd392..125ecee707 100644
--- a/core/runtime/runtime_api/impl/CMakeLists.txt
+++ b/core/runtime/runtime_api/impl/CMakeLists.txt
@@ -26,4 +26,11 @@ target_link_libraries(offchain_worker_api offchain_worker)
 add_library(session_keys_api session_keys_api.cpp)
 target_link_libraries(session_keys_api executor)
 
+add_library(runtime_properties_cache
+    runtime_properties_cache_impl.cpp
+    )
+target_link_libraries(runtime_properties_cache
+    executor
+    )
+
 
diff --git a/core/runtime/runtime_api/impl/core.cpp b/core/runtime/runtime_api/impl/core.cpp
index c4a9e027e4..466d7b8ac6 100644
--- a/core/runtime/runtime_api/impl/core.cpp
+++ b/core/runtime/runtime_api/impl/core.cpp
@@ -24,7 +24,7 @@ namespace kagome::runtime {
   }
 
   outcome::result<primitives::Version> CoreImpl::version(
-      primitives::BlockHash const &block) {
+      const primitives::BlockHash &block) {
     return executor_->callAt<primitives::Version>(block, "Core_version");
   }
 
diff --git a/core/runtime/runtime_api/impl/runtime_properties_cache_impl.cpp b/core/runtime/runtime_api/impl/runtime_properties_cache_impl.cpp
new file mode 100644
index 0000000000..4675169641
--- /dev/null
+++ b/core/runtime/runtime_api/impl/runtime_properties_cache_impl.cpp
@@ -0,0 +1,33 @@
+/**
+ * Copyright Soramitsu Co., Ltd. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "runtime_properties_cache_impl.hpp"
+
+namespace kagome::runtime {
+
+  outcome::result<primitives::Version> RuntimePropertiesCacheImpl::getVersion(
+      const common::Hash256 &hash,
+      std::function<outcome::result<primitives::Version>()> obtainer) {
+    auto it = cached_versions_.find(hash);
+    if (it == cached_versions_.end()) {
+      OUTCOME_TRY(version, obtainer());
+      it = cached_versions_.emplace(hash, std::move(version)).first;
+    }
+    return it->second;
+  }
+
+  outcome::result<primitives::OpaqueMetadata>
+  RuntimePropertiesCacheImpl::getMetadata(
+      const common::Hash256 &hash,
+      std::function<outcome::result<primitives::OpaqueMetadata>()> obtainer) {
+    auto it = cached_metadata_.find(hash);
+    if (it == cached_metadata_.end()) {
+      OUTCOME_TRY(metadata, obtainer());
+      it = cached_metadata_.emplace(hash, std::move(metadata)).first;
+    }
+    return it->second;
+  }
+
+}  // namespace kagome::runtime
diff --git a/core/runtime/runtime_api/impl/runtime_properties_cache_impl.hpp b/core/runtime/runtime_api/impl/runtime_properties_cache_impl.hpp
new file mode 100644
index 0000000000..c380efb19a
--- /dev/null
+++ b/core/runtime/runtime_api/impl/runtime_properties_cache_impl.hpp
@@ -0,0 +1,34 @@
+/**
+ * Copyright Soramitsu Co., Ltd. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef KAGOME_RUNTIME_RUNTIMEPROPERTIESCACHEIMPL
+#define KAGOME_RUNTIME_RUNTIMEPROPERTIESCACHEIMPL
+
+#include "runtime/runtime_properties_cache.hpp"
+
+namespace kagome::runtime {
+
+  class RuntimePropertiesCacheImpl final : public RuntimePropertiesCache {
+   public:
+    RuntimePropertiesCacheImpl() {}
+
+    outcome::result<primitives::Version> getVersion(
+        const common::Hash256 &hash,
+        std::function<outcome::result<primitives::Version>()> obtainer)
+        override;
+
+    outcome::result<primitives::OpaqueMetadata> getMetadata(
+        const common::Hash256 &hash,
+        std::function<outcome::result<primitives::OpaqueMetadata>()> obtainer)
+        override;
+
+   private:
+    std::map<common::Hash256, primitives::Version> cached_versions_;
+    std::map<common::Hash256, primitives::OpaqueMetadata> cached_metadata_;
+  };
+
+}  // namespace kagome::runtime
+
+#endif  // KAGOME_RUNTIME_RUNTIMEPROPERTIESCACHEIMPL
diff --git a/core/runtime/runtime_properties_cache.hpp b/core/runtime/runtime_properties_cache.hpp
new file mode 100644
index 0000000000..b12c811e14
--- /dev/null
+++ b/core/runtime/runtime_properties_cache.hpp
@@ -0,0 +1,41 @@
+/**
+ * Copyright Soramitsu Co., Ltd. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/**
+ * Copyright Soramitsu Co., Ltd. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef KAGOME_RUNTIME_RUNTIMEPROPERTIESCACHE
+#define KAGOME_RUNTIME_RUNTIMEPROPERTIESCACHE
+
+#include "common/blob.hpp"
+#include "outcome/outcome.hpp"
+#include "primitives/opaque_metadata.hpp"
+#include "primitives/version.hpp"
+
+namespace kagome::runtime {
+
+  /**
+   * Cache for runtime properties (as Version and Metadata)
+   * Allows loading and compiling a module directly from its web assembly byte
+   * code and instantiating a runtime module at an arbitrary block
+   */
+  class RuntimePropertiesCache {
+   public:
+    virtual ~RuntimePropertiesCache() = default;
+
+    virtual outcome::result<primitives::Version> getVersion(
+        const common::Hash256 &hash,
+        std::function<outcome::result<primitives::Version>()> obtainer) = 0;
+
+    virtual outcome::result<primitives::OpaqueMetadata> getMetadata(
+        const common::Hash256 &hash,
+        std::function<outcome::result<primitives::OpaqueMetadata>()>
+            obtainer) = 0;
+  };
+
+}  // namespace kagome::runtime
+
+#endif  // KAGOME_RUNTIME_RUNTIMEPROPERTIESCACHE
diff --git a/core/runtime/wavm/core_api_factory_impl.cpp b/core/runtime/wavm/core_api_factory_impl.cpp
index 82faf372b4..49686e7846 100644
--- a/core/runtime/wavm/core_api_factory_impl.cpp
+++ b/core/runtime/wavm/core_api_factory_impl.cpp
@@ -10,6 +10,7 @@
 #include "runtime/common/trie_storage_provider_impl.hpp"
 #include "runtime/module_repository.hpp"
 #include "runtime/runtime_api/impl/core.hpp"
+#include "runtime/runtime_api/impl/runtime_properties_cache_impl.hpp"
 #include "runtime/runtime_environment_factory.hpp"
 #include "runtime/wavm/compartment_wrapper.hpp"
 #include "runtime/wavm/instance_environment_factory.hpp"
@@ -126,7 +127,8 @@ namespace kagome::runtime::wavm {
                     runtime_code.size())},
             last_compiled_module_),
         block_header_repo_);
-    auto executor = std::make_unique<runtime::Executor>(env_factory);
+    auto cache = std::make_shared<runtime::RuntimePropertiesCacheImpl>();
+    auto executor = std::make_unique<runtime::Executor>(env_factory, cache);
     return std::make_unique<CoreImpl>(
         std::move(executor), changes_tracker_, block_header_repo_);
   }

From ea7ef78b55a174e52730bb6f08b5aacfa903d0ab Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Wed, 2 Nov 2022 14:41:38 +0800
Subject: [PATCH 02/13] feature: remember code hash with module

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 core/injector/application_injector.cpp          |  3 ++-
 core/runtime/binaryen/core_api_factory_impl.cpp | 17 ++++++++++++-----
 .../binaryen/module/module_factory_impl.cpp     | 10 +++++++---
 .../binaryen/module/module_factory_impl.hpp     |  8 +++++++-
 core/runtime/binaryen/module/module_impl.cpp    | 17 ++++++++++-------
 core/runtime/binaryen/module/module_impl.hpp    |  9 ++++++---
 .../binaryen/module/module_instance_impl.cpp    |  4 +++-
 .../binaryen/module/module_instance_impl.hpp    |  9 ++++++++-
 core/runtime/common/runtime_instances_pool.cpp  | 11 +++++++++++
 core/runtime/module_instance.hpp                |  2 ++
 core/runtime/wavm/core_api_factory_impl.cpp     |  7 ++++++-
 core/runtime/wavm/module.cpp                    | 12 ++++++++----
 core/runtime/wavm/module.hpp                    |  8 ++++++--
 core/runtime/wavm/module_factory_impl.cpp       | 16 ++++++++++++----
 core/runtime/wavm/module_factory_impl.hpp       |  7 ++++++-
 core/runtime/wavm/module_instance.cpp           |  4 +++-
 core/runtime/wavm/module_instance.hpp           |  9 ++++++++-
 17 files changed, 117 insertions(+), 36 deletions(-)

diff --git a/core/injector/application_injector.cpp b/core/injector/application_injector.cpp
index 36b8eb92d8..2cd771f47e 100644
--- a/core/injector/application_injector.cpp
+++ b/core/injector/application_injector.cpp
@@ -901,7 +901,8 @@ namespace {
                       sptr<runtime::wavm::InstanceEnvironmentFactory>>(),
                   injector
                       .template create<sptr<runtime::wavm::IntrinsicModule>>(),
-                  module_cache_opt);
+                  module_cache_opt,
+                  injector.template create<sptr<crypto::Hasher>>());
             }),
         di::bind<runtime::ModuleFactory>.template to(
             [method](const auto &injector) {
diff --git a/core/runtime/binaryen/core_api_factory_impl.cpp b/core/runtime/binaryen/core_api_factory_impl.cpp
index 8e3f9b74c2..712ccb2348 100644
--- a/core/runtime/binaryen/core_api_factory_impl.cpp
+++ b/core/runtime/binaryen/core_api_factory_impl.cpp
@@ -20,8 +20,11 @@ namespace kagome::runtime::binaryen {
    public:
     OneModuleRepository(
         const std::vector<uint8_t> &code,
-        std::shared_ptr<const InstanceEnvironmentFactory> env_factory)
-        : env_factory_{std::move(env_factory)}, code_{code} {
+        std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
+        const common::Hash256 &code_hash)
+        : env_factory_{std::move(env_factory)},
+          code_{code},
+          code_hash_(code_hash) {
       BOOST_ASSERT(env_factory_);
     }
 
@@ -30,7 +33,9 @@ namespace kagome::runtime::binaryen {
         const primitives::BlockInfo &,
         const primitives::BlockHeader &) override {
       if (instance_ == nullptr) {
-        OUTCOME_TRY(module, ModuleImpl::createFromCode(code_, env_factory_));
+        OUTCOME_TRY(
+            module,
+            ModuleImpl::createFromCode(code_, env_factory_, code_hash_));
         OUTCOME_TRY(inst, module->instantiate());
         instance_ = std::move(inst);
       }
@@ -41,6 +46,7 @@ namespace kagome::runtime::binaryen {
     std::shared_ptr<ModuleInstance> instance_;
     std::shared_ptr<const InstanceEnvironmentFactory> env_factory_;
     const std::vector<uint8_t> &code_;
+    const common::Hash256 code_hash_;
   };
 
   class OneCodeProvider final : public RuntimeCodeProvider {
@@ -71,10 +77,11 @@ namespace kagome::runtime::binaryen {
   std::unique_ptr<Core> CoreApiFactoryImpl::make(
       std::shared_ptr<const crypto::Hasher> hasher,
       const std::vector<uint8_t> &runtime_code) const {
+    auto code_hash = hasher->sha2_256(runtime_code);
     auto env_factory = std::make_shared<runtime::RuntimeEnvironmentFactory>(
         std::make_shared<OneCodeProvider>(runtime_code),
-        std::make_shared<OneModuleRepository>(runtime_code,
-                                              instance_env_factory_),
+        std::make_shared<OneModuleRepository>(
+            runtime_code, instance_env_factory_, code_hash),
         header_repo_);
     auto cache = std::make_shared<runtime::RuntimePropertiesCacheImpl>();
     auto executor = std::make_unique<Executor>(env_factory, cache);
diff --git a/core/runtime/binaryen/module/module_factory_impl.cpp b/core/runtime/binaryen/module/module_factory_impl.cpp
index c5cbd64af2..9662dbf5e9 100644
--- a/core/runtime/binaryen/module/module_factory_impl.cpp
+++ b/core/runtime/binaryen/module/module_factory_impl.cpp
@@ -17,8 +17,11 @@ namespace kagome::runtime::binaryen {
 
   ModuleFactoryImpl::ModuleFactoryImpl(
       std::shared_ptr<InstanceEnvironmentFactory> env_factory,
-      std::shared_ptr<storage::trie::TrieStorage> storage)
-      : env_factory_{std::move(env_factory)}, storage_{std::move(storage)} {
+      std::shared_ptr<storage::trie::TrieStorage> storage,
+      std::shared_ptr<crypto::Hasher> hasher)
+      : env_factory_{std::move(env_factory)},
+        storage_{std::move(storage)},
+        hasher_(std::move(hasher)) {
     BOOST_ASSERT(env_factory_ != nullptr);
     BOOST_ASSERT(storage_ != nullptr);
   }
@@ -26,7 +29,8 @@ namespace kagome::runtime::binaryen {
   outcome::result<std::unique_ptr<Module>> ModuleFactoryImpl::make(
       gsl::span<const uint8_t> code) const {
     std::vector<uint8_t> code_vec{code.begin(), code.end()};
-    auto res = ModuleImpl::createFromCode(code_vec, env_factory_);
+    auto res = ModuleImpl::createFromCode(
+        code_vec, env_factory_, hasher_->sha2_256(code));
     if (res.has_value()) {
       return std::unique_ptr<Module>(std::move(res.value()));
     }
diff --git a/core/runtime/binaryen/module/module_factory_impl.hpp b/core/runtime/binaryen/module/module_factory_impl.hpp
index ebfd01272f..e09e5cafa3 100644
--- a/core/runtime/binaryen/module/module_factory_impl.hpp
+++ b/core/runtime/binaryen/module/module_factory_impl.hpp
@@ -12,6 +12,10 @@ namespace kagome::runtime {
   class TrieStorageProvider;
 }
 
+namespace kagome::crypto {
+  class Hasher;
+}
+
 namespace kagome::host_api {
   class HostApiFactory;
 }
@@ -35,7 +39,8 @@ namespace kagome::runtime::binaryen {
   class ModuleFactoryImpl final : public ModuleFactory {
    public:
     ModuleFactoryImpl(std::shared_ptr<InstanceEnvironmentFactory> env_factory,
-                      std::shared_ptr<storage::trie::TrieStorage> storage);
+                      std::shared_ptr<storage::trie::TrieStorage> storage,
+                      std::shared_ptr<crypto::Hasher> hasher);
 
     outcome::result<std::unique_ptr<Module>> make(
         gsl::span<const uint8_t> code) const override;
@@ -43,6 +48,7 @@ namespace kagome::runtime::binaryen {
    private:
     std::shared_ptr<InstanceEnvironmentFactory> env_factory_;
     std::shared_ptr<storage::trie::TrieStorage> storage_;
+    std::shared_ptr<crypto::Hasher> hasher_;
   };
 
 }  // namespace kagome::runtime::binaryen
diff --git a/core/runtime/binaryen/module/module_impl.cpp b/core/runtime/binaryen/module/module_impl.cpp
index 6e6d0efc1f..8ce400c4c3 100644
--- a/core/runtime/binaryen/module/module_impl.cpp
+++ b/core/runtime/binaryen/module/module_impl.cpp
@@ -34,15 +34,19 @@ namespace kagome::runtime::binaryen {
 
   ModuleImpl::ModuleImpl(
       std::unique_ptr<wasm::Module> &&module,
-      std::shared_ptr<const InstanceEnvironmentFactory> env_factory)
-      : env_factory_{std::move(env_factory)}, module_{std::move(module)} {
+      std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
+      const common::Hash256 &code_hash)
+      : env_factory_{std::move(env_factory)},
+        module_{std::move(module)},
+        code_hash_(code_hash) {
     BOOST_ASSERT(module_ != nullptr);
     BOOST_ASSERT(env_factory_ != nullptr);
   }
 
   outcome::result<std::unique_ptr<ModuleImpl>> ModuleImpl::createFromCode(
       const std::vector<uint8_t> &code,
-      std::shared_ptr<const InstanceEnvironmentFactory> env_factory) {
+      std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
+      const common::Hash256 &code_hash) {
     auto log = log::createLogger("wasm_module", "binaryen");
     // that nolint suppresses false positive in a library function
     // NOLINTNEXTLINE(clang-analyzer-core.NonNullParamChecker)
@@ -54,8 +58,7 @@ namespace kagome::runtime::binaryen {
     {
       wasm::WasmBinaryBuilder parser(
           *module,
-          reinterpret_cast<std::vector<char> const &>(  // NOLINT
-              code),
+          reinterpret_cast<std::vector<char> const &>(code),  // NOLINT
           false);
 
       try {
@@ -71,7 +74,7 @@ namespace kagome::runtime::binaryen {
     module->memory.initial = kDefaultHeappages;
 
     std::unique_ptr<ModuleImpl> wasm_module_impl(
-        new ModuleImpl(std::move(module), std::move(env_factory)));
+        new ModuleImpl(std::move(module), std::move(env_factory), code_hash));
     return wasm_module_impl;
   }
 
@@ -79,7 +82,7 @@ namespace kagome::runtime::binaryen {
       const {
     auto env = env_factory_->make();
     return std::make_shared<ModuleInstanceImpl>(
-        std::move(env.env), module_, env.rei);
+        std::move(env.env), module_, env.rei, code_hash_);
   }
 
 }  // namespace kagome::runtime::binaryen
diff --git a/core/runtime/binaryen/module/module_impl.hpp b/core/runtime/binaryen/module/module_impl.hpp
index 71ad05ce64..656f1c3b39 100644
--- a/core/runtime/binaryen/module/module_impl.hpp
+++ b/core/runtime/binaryen/module/module_impl.hpp
@@ -36,7 +36,7 @@ namespace kagome::runtime::binaryen {
     enum class Error { EMPTY_STATE_CODE = 1, INVALID_STATE_CODE };
 
     ModuleImpl(ModuleImpl &&) = default;
-    ModuleImpl &operator=(ModuleImpl &&) = default;
+    //    ModuleImpl &operator=(ModuleImpl &&) = default;
 
     ModuleImpl(const ModuleImpl &) = delete;
     ModuleImpl &operator=(const ModuleImpl &) = delete;
@@ -45,17 +45,20 @@ namespace kagome::runtime::binaryen {
 
     static outcome::result<std::unique_ptr<ModuleImpl>> createFromCode(
         const std::vector<uint8_t> &code,
-        std::shared_ptr<const InstanceEnvironmentFactory> env_factory_);
+        std::shared_ptr<const InstanceEnvironmentFactory> env_factory_,
+        const common::Hash256 &code_hash);
 
     outcome::result<std::shared_ptr<ModuleInstance>> instantiate()
         const override;
 
    private:
     ModuleImpl(std::unique_ptr<wasm::Module> &&module,
-               std::shared_ptr<const InstanceEnvironmentFactory> env_factory);
+               std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
+               const common::Hash256 &code_hash);
 
     std::shared_ptr<const InstanceEnvironmentFactory> env_factory_;
     std::shared_ptr<wasm::Module> module_;  // shared to module instances
+    const common::Hash256 code_hash_;
   };
 
 }  // namespace kagome::runtime::binaryen
diff --git a/core/runtime/binaryen/module/module_instance_impl.cpp b/core/runtime/binaryen/module/module_instance_impl.cpp
index 4c89136f9a..eeda17abc0 100644
--- a/core/runtime/binaryen/module/module_instance_impl.cpp
+++ b/core/runtime/binaryen/module/module_instance_impl.cpp
@@ -76,10 +76,12 @@ namespace kagome::runtime::binaryen {
   ModuleInstanceImpl::ModuleInstanceImpl(
       InstanceEnvironment &&env,
       std::shared_ptr<wasm::Module> parent,
-      std::shared_ptr<RuntimeExternalInterface> rei)
+      std::shared_ptr<RuntimeExternalInterface> rei,
+      const common::Hash256 &code_hash)
       : env_{std::move(env)},
         rei_{std::move(rei)},
         parent_{std::move(parent)},
+        code_hash_(code_hash),
         module_instance_{
             std::make_unique<wasm::ModuleInstance>(*parent_, rei_.get())},
         logger_{log::createLogger("ModuleInstance", "binaryen")} {
diff --git a/core/runtime/binaryen/module/module_instance_impl.hpp b/core/runtime/binaryen/module/module_instance_impl.hpp
index 24259aa76b..e661df6073 100644
--- a/core/runtime/binaryen/module/module_instance_impl.hpp
+++ b/core/runtime/binaryen/module/module_instance_impl.hpp
@@ -30,7 +30,12 @@ namespace kagome::runtime::binaryen {
 
     ModuleInstanceImpl(InstanceEnvironment &&env,
                        std::shared_ptr<wasm::Module> parent,
-                       std::shared_ptr<RuntimeExternalInterface> rei);
+                       std::shared_ptr<RuntimeExternalInterface> rei,
+                       const common::Hash256 &code_hash);
+
+    const common::Hash256 &getCodeHash() const override {
+      return code_hash_;
+    }
 
     outcome::result<PtrSize> callExportFunction(
         std::string_view name, common::BufferView args) const override;
@@ -50,6 +55,8 @@ namespace kagome::runtime::binaryen {
     std::shared_ptr<wasm::Module>
         parent_;  // must be kept alive because binaryen's module instance keeps
                   // a reference to it
+    common::Hash256 code_hash_;
+
     std::unique_ptr<wasm::ModuleInstance> module_instance_;
     log::Logger logger_;
   };
diff --git a/core/runtime/common/runtime_instances_pool.cpp b/core/runtime/common/runtime_instances_pool.cpp
index d7e2db4795..ae1679ba0b 100644
--- a/core/runtime/common/runtime_instances_pool.cpp
+++ b/core/runtime/common/runtime_instances_pool.cpp
@@ -32,20 +32,28 @@ namespace kagome::runtime {
       }
     }
 
+    const common::Hash256 &getCodeHash() const override {
+      return instance_->getCodeHash();
+    }
+
     outcome::result<PtrSize> callExportFunction(
         std::string_view name, common::BufferView encoded_args) const override {
       return instance_->callExportFunction(name, encoded_args);
     }
+
     outcome::result<std::optional<WasmValue>> getGlobal(
         std::string_view name) const override {
       return instance_->getGlobal(name);
     }
+
     void forDataSegment(DataSegmentProcessor const &callback) const override {
       return instance_->forDataSegment(callback);
     }
+
     InstanceEnvironment const &getEnvironment() const override {
       return instance_->getEnvironment();
     }
+
     outcome::result<void> resetEnvironment() override {
       return instance_->resetEnvironment();
     }
@@ -86,15 +94,18 @@ namespace kagome::runtime {
 
     pool.emplace(std::move(instance));
   }
+
   std::optional<std::shared_ptr<Module>> RuntimeInstancesPool::getModule(
       const RuntimeInstancesPool::RootHash &state) {
     std::lock_guard guard{mt_};
     return modules_.get(state);
   }
+
   void RuntimeInstancesPool::putModule(
       const RuntimeInstancesPool::RootHash &state,
       std::shared_ptr<Module> module) {
     std::lock_guard guard{mt_};
     modules_.put(state, std::move(module));
   }
+
 }  // namespace kagome::runtime
diff --git a/core/runtime/module_instance.hpp b/core/runtime/module_instance.hpp
index 0f96781ab7..27574f0e04 100644
--- a/core/runtime/module_instance.hpp
+++ b/core/runtime/module_instance.hpp
@@ -31,6 +31,8 @@ namespace kagome::runtime {
    public:
     virtual ~ModuleInstance() = default;
 
+    virtual const common::Hash256 &getCodeHash() const = 0;
+
     /**
      * Call the instance's function
      * @param name - name of the function
diff --git a/core/runtime/wavm/core_api_factory_impl.cpp b/core/runtime/wavm/core_api_factory_impl.cpp
index 49686e7846..18ff4246fe 100644
--- a/core/runtime/wavm/core_api_factory_impl.cpp
+++ b/core/runtime/wavm/core_api_factory_impl.cpp
@@ -31,6 +31,7 @@ namespace kagome::runtime::wavm {
         std::shared_ptr<IntrinsicModule> intrinsic_module,
         std::shared_ptr<const InstanceEnvironmentFactory> instance_env_factory,
         gsl::span<const uint8_t> code,
+        const common::Hash256 &code_hash,
         std::shared_ptr<SingleModuleCache> last_compiled_module)
         : instance_env_factory_{std::move(instance_env_factory)},
           compartment_{compartment},
@@ -53,7 +54,8 @@ namespace kagome::runtime::wavm {
                                               *module_params_,
                                               intrinsic_module_,
                                               instance_env_factory_,
-                                              code_);
+                                              code_,
+                                              code_hash_);
         OUTCOME_TRY(inst, module->instantiate());
         last_compiled_module_->set(std::move(module));
         instance_ = std::move(inst);
@@ -68,6 +70,7 @@ namespace kagome::runtime::wavm {
     std::shared_ptr<ModuleParams> module_params_;
     std::shared_ptr<IntrinsicModule> intrinsic_module_;
     gsl::span<const uint8_t> code_;
+    const common::Hash256 code_hash_;
     std::shared_ptr<SingleModuleCache> last_compiled_module_;
   };
 
@@ -114,6 +117,7 @@ namespace kagome::runtime::wavm {
   std::unique_ptr<Core> CoreApiFactoryImpl::make(
       std::shared_ptr<const crypto::Hasher> hasher,
       const std::vector<uint8_t> &runtime_code) const {
+    auto code_hash = hasher->sha2_256(runtime_code);
     auto env_factory = std::make_shared<runtime::RuntimeEnvironmentFactory>(
         std::make_shared<OneCodeProvider>(runtime_code),
         std::make_shared<OneModuleRepository>(
@@ -125,6 +129,7 @@ namespace kagome::runtime::wavm {
                 runtime_code.data(),
                 static_cast<gsl::span<const uint8_t>::index_type>(
                     runtime_code.size())},
+            code_hash,
             last_compiled_module_),
         block_header_repo_);
     auto cache = std::make_shared<runtime::RuntimePropertiesCacheImpl>();
diff --git a/core/runtime/wavm/module.cpp b/core/runtime/wavm/module.cpp
index a8aab8b758..b1d7811bef 100644
--- a/core/runtime/wavm/module.cpp
+++ b/core/runtime/wavm/module.cpp
@@ -25,7 +25,8 @@ namespace kagome::runtime::wavm {
       ModuleParams &module_params,
       std::shared_ptr<IntrinsicModule> intrinsic_module,
       std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
-      gsl::span<const uint8_t> code) {
+      gsl::span<const uint8_t> code,
+      const common::Hash256 &code_hash) {
     std::shared_ptr<WAVM::Runtime::Module> module = nullptr;
     WAVM::WASM::LoadError loadError;
     WAVM::IR::FeatureSpec featureSpec;
@@ -53,18 +54,21 @@ namespace kagome::runtime::wavm {
         new ModuleImpl{std::move(compartment),
                        std::move(intrinsic_module),
                        std::move(env_factory),
-                       std::move(module)});
+                       std::move(module),
+                       code_hash});
   }
 
   ModuleImpl::ModuleImpl(
       std::shared_ptr<CompartmentWrapper> compartment,
       std::shared_ptr<const IntrinsicModule> intrinsic_module,
       std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
-      std::shared_ptr<WAVM::Runtime::Module> module)
+      std::shared_ptr<WAVM::Runtime::Module> module,
+      const common::Hash256 &code_hash)
       : env_factory_{std::move(env_factory)},
         compartment_{std::move(compartment)},
         intrinsic_module_{std::move(intrinsic_module)},
         module_{std::move(module)},
+        code_hash_(code_hash),
         logger_{log::createLogger("WAVM Module", "wavm")} {
     BOOST_ASSERT(compartment_);
     BOOST_ASSERT(env_factory_);
@@ -103,7 +107,7 @@ namespace kagome::runtime::wavm {
         memory_origin, internal_instance, new_intrinsic_module_instance);
 
     auto instance = std::make_shared<ModuleInstanceImpl>(
-        std::move(env), internal_instance, module_, compartment_);
+        std::move(env), internal_instance, module_, compartment_, code_hash_);
 
     return instance;
   }
diff --git a/core/runtime/wavm/module.hpp b/core/runtime/wavm/module.hpp
index 71eccb55b4..4cac549ef9 100644
--- a/core/runtime/wavm/module.hpp
+++ b/core/runtime/wavm/module.hpp
@@ -10,6 +10,7 @@
 
 #include <memory>
 
+#include "common/blob.hpp"
 #include "log/logger.hpp"
 
 namespace WAVM::Runtime {
@@ -34,7 +35,8 @@ namespace kagome::runtime::wavm {
         ModuleParams &module_params,
         std::shared_ptr<IntrinsicModule> intrinsic_module,
         std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
-        gsl::span<const uint8_t> code);
+        gsl::span<const uint8_t> code,
+        const common::Hash256 &code_hash);
 
     outcome::result<std::shared_ptr<ModuleInstance>> instantiate()
         const override;
@@ -43,7 +45,8 @@ namespace kagome::runtime::wavm {
     ModuleImpl(std::shared_ptr<CompartmentWrapper> compartment,
                std::shared_ptr<const IntrinsicModule> intrinsic_module,
                std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
-               std::shared_ptr<WAVM::Runtime::Module> module);
+               std::shared_ptr<WAVM::Runtime::Module> module,
+               const common::Hash256 &code_hash);
 
     WAVM::Runtime::ImportBindings link(IntrinsicResolver &resolver) const;
 
@@ -51,6 +54,7 @@ namespace kagome::runtime::wavm {
     std::shared_ptr<CompartmentWrapper> compartment_;
     std::shared_ptr<const IntrinsicModule> intrinsic_module_;
     std::shared_ptr<WAVM::Runtime::Module> module_;
+    const common::Hash256 code_hash_;
     log::Logger logger_;
   };
 
diff --git a/core/runtime/wavm/module_factory_impl.cpp b/core/runtime/wavm/module_factory_impl.cpp
index 763c4306ec..9d5fc6866f 100644
--- a/core/runtime/wavm/module_factory_impl.cpp
+++ b/core/runtime/wavm/module_factory_impl.cpp
@@ -5,6 +5,7 @@
 
 #include "runtime/wavm/module_factory_impl.hpp"
 
+#include "crypto/hasher.hpp"
 #include "runtime/wavm/module.hpp"
 #include "runtime/wavm/module_cache.hpp"
 #include "runtime/wavm/module_params.hpp"
@@ -16,15 +17,18 @@ namespace kagome::runtime::wavm {
       std::shared_ptr<ModuleParams> module_params,
       std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
       std::shared_ptr<IntrinsicModule> intrinsic_module,
-      std::optional<std::shared_ptr<ModuleCache>> module_cache)
+      std::optional<std::shared_ptr<ModuleCache>> module_cache,
+      std::shared_ptr<crypto::Hasher> hasher)
       : compartment_{std::move(compartment)},
         module_params_{std::move(module_params)},
         env_factory_{std::move(env_factory)},
-        intrinsic_module_{std::move(intrinsic_module)} {
+        intrinsic_module_{std::move(intrinsic_module)},
+        hasher_(std::move(hasher)) {
     BOOST_ASSERT(compartment_ != nullptr);
     BOOST_ASSERT(module_params_ != nullptr);
     BOOST_ASSERT(env_factory_ != nullptr);
     BOOST_ASSERT(intrinsic_module_ != nullptr);
+    BOOST_ASSERT(hasher_ != nullptr);
 
     if (module_cache.has_value()) {
       WAVM::Runtime::setGlobalObjectCache(std::move(module_cache.value()));
@@ -33,8 +37,12 @@ namespace kagome::runtime::wavm {
 
   outcome::result<std::unique_ptr<Module>> ModuleFactoryImpl::make(
       gsl::span<const uint8_t> code) const {
-    return ModuleImpl::compileFrom(
-        compartment_, *module_params_, intrinsic_module_, env_factory_, code);
+    return ModuleImpl::compileFrom(compartment_,
+                                   *module_params_,
+                                   intrinsic_module_,
+                                   env_factory_,
+                                   code,
+                                   hasher_->sha2_256(code));
   }
 
 }  // namespace kagome::runtime::wavm
diff --git a/core/runtime/wavm/module_factory_impl.hpp b/core/runtime/wavm/module_factory_impl.hpp
index 6d70d1d4f0..1b6c36f46a 100644
--- a/core/runtime/wavm/module_factory_impl.hpp
+++ b/core/runtime/wavm/module_factory_impl.hpp
@@ -13,6 +13,9 @@
 namespace kagome::application {
   class AppConfiguration;
 }
+namespace kagome::crypto {
+  class Hasher;
+}
 
 namespace kagome::runtime::wavm {
 
@@ -29,7 +32,8 @@ namespace kagome::runtime::wavm {
         std::shared_ptr<ModuleParams> module_params,
         std::shared_ptr<const InstanceEnvironmentFactory> env_factory,
         std::shared_ptr<IntrinsicModule> intrinsic_module,
-        std::optional<std::shared_ptr<ModuleCache>> module_cache);
+        std::optional<std::shared_ptr<ModuleCache>> module_cache,
+        std::shared_ptr<crypto::Hasher> hasher);
 
     outcome::result<std::unique_ptr<Module>> make(
         gsl::span<const uint8_t> code) const override;
@@ -39,6 +43,7 @@ namespace kagome::runtime::wavm {
     std::shared_ptr<ModuleParams> module_params_;
     std::shared_ptr<const InstanceEnvironmentFactory> env_factory_;
     std::shared_ptr<IntrinsicModule> intrinsic_module_;
+    std::shared_ptr<crypto::Hasher> hasher_;
   };
 
 }  // namespace kagome::runtime::wavm
diff --git a/core/runtime/wavm/module_instance.cpp b/core/runtime/wavm/module_instance.cpp
index ef91035de9..89d5e78ee6 100644
--- a/core/runtime/wavm/module_instance.cpp
+++ b/core/runtime/wavm/module_instance.cpp
@@ -86,11 +86,13 @@ namespace kagome::runtime::wavm {
       InstanceEnvironment &&env,
       WAVM::Runtime::GCPointer<WAVM::Runtime::Instance> instance,
       WAVM::Runtime::ModuleRef module,
-      std::shared_ptr<const CompartmentWrapper> compartment)
+      std::shared_ptr<const CompartmentWrapper> compartment,
+      const common::Hash256 &code_hash)
       : env_{std::move(env)},
         instance_{std::move(instance)},
         module_{std::move(module)},
         compartment_{std::move(compartment)},
+        code_hash_(code_hash),
         logger_{log::createLogger("ModuleInstance", "wavm")} {
     BOOST_ASSERT(instance_ != nullptr);
     BOOST_ASSERT(compartment_ != nullptr);
diff --git a/core/runtime/wavm/module_instance.hpp b/core/runtime/wavm/module_instance.hpp
index fe8449d5a6..8b13e9cc20 100644
--- a/core/runtime/wavm/module_instance.hpp
+++ b/core/runtime/wavm/module_instance.hpp
@@ -36,11 +36,17 @@ namespace kagome::runtime::wavm {
       EXECUTION_ERROR,
       WRONG_RETURN_TYPE
     };
+
     ModuleInstanceImpl(
         InstanceEnvironment &&env,
         WAVM::Runtime::GCPointer<WAVM::Runtime::Instance> instance,
         WAVM::Runtime::ModuleRef module,
-        std::shared_ptr<const CompartmentWrapper> compartment);
+        std::shared_ptr<const CompartmentWrapper> compartment,
+        const common::Hash256 &code_hash);
+
+    const common::Hash256 &getCodeHash() const override {
+      return code_hash_;
+    }
 
     outcome::result<PtrSize> callExportFunction(
         std::string_view name, common::BufferView encoded_args) const override;
@@ -58,6 +64,7 @@ namespace kagome::runtime::wavm {
     WAVM::Runtime::GCPointer<WAVM::Runtime::Instance> instance_;
     WAVM::Runtime::ModuleRef module_;
     std::shared_ptr<const CompartmentWrapper> compartment_;
+    common::Hash256 code_hash_;
     log::Logger logger_;
   };
 

From 8fdc5fba9ec15ec35cd7c81a7794d4f75131ff99 Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Wed, 2 Nov 2022 14:43:02 +0800
Subject: [PATCH 03/13] feature: use cache at obtaining of version and metadata

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 core/runtime/common/executor.hpp | 69 ++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/core/runtime/common/executor.hpp b/core/runtime/common/executor.hpp
index 68826cb811..a4a170e777 100644
--- a/core/runtime/common/executor.hpp
+++ b/core/runtime/common/executor.hpp
@@ -20,6 +20,7 @@
 #include "runtime/module_instance.hpp"
 #include "runtime/module_repository.hpp"
 #include "runtime/persistent_result.hpp"
+#include "runtime/runtime_api/metadata.hpp"
 #include "runtime/runtime_environment_factory.hpp"
 #include "runtime/runtime_properties_cache.hpp"
 #include "runtime/trie_storage_provider.hpp"
@@ -27,6 +28,15 @@
 #include "storage/trie/trie_batches.hpp"
 #include "storage/trie/trie_storage.hpp"
 
+#ifdef __has_builtin
+#if __has_builtin(__builtin_expect)
+#define unlikely(x) __builtin_expect((x), 0)
+#endif
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+
 namespace kagome::runtime {
 
   /**
@@ -134,6 +144,25 @@ namespace kagome::runtime {
                                    std::string_view name,
                                    Args &&...args) {
       OUTCOME_TRY(env, env_factory_->start(block_info, storage_state)->make());
+
+      if constexpr (std::is_same_v<Result, primitives::Version>) {
+        if (unlikely(name == "Core_version")) {
+          return cache_->getVersion(env->module_instance->getCodeHash(), [&] {
+            return callInternal<Result>(
+                *env, name, std::forward<Args>(args)...);
+          });
+        }
+      }
+
+      if constexpr (std::is_same_v<Result, primitives::OpaqueMetadata>) {
+        if (unlikely(name == "Metadata_metadata")) {
+          return cache_->getMetadata(env->module_instance->getCodeHash(), [&] {
+            return callInternal<Result>(
+                *env, name, std::forward<Args>(args)...);
+          });
+        }
+      }
+
       return callInternal<Result>(*env, name, std::forward<Args>(args)...);
     }
 
@@ -148,6 +177,25 @@ namespace kagome::runtime {
                                    Args &&...args) {
       OUTCOME_TRY(env_template, env_factory_->start(block_hash));
       OUTCOME_TRY(env, env_template->make());
+
+      if constexpr (std::is_same_v<Result, primitives::Version>) {
+        if (unlikely(name == "Core_version")) {
+          return cache_->getVersion(env->module_instance->getCodeHash(), [&] {
+            return callInternal<Result>(
+                *env, name, std::forward<Args>(args)...);
+          });
+        }
+      }
+
+      if constexpr (std::is_same_v<Result, primitives::OpaqueMetadata>) {
+        if (unlikely(name == "Metadata_metadata")) {
+          return cache_->getMetadata(env->module_instance->getCodeHash(), [&] {
+            return callInternal<Result>(
+                *env, name, std::forward<Args>(args)...);
+          });
+        }
+      }
+
       return callInternal<Result>(*env, name, std::forward<Args>(args)...);
     }
 
@@ -161,6 +209,25 @@ namespace kagome::runtime {
                                           Args &&...args) {
       OUTCOME_TRY(env_template, env_factory_->start());
       OUTCOME_TRY(env, env_template->make());
+
+      if constexpr (std::is_same_v<Result, primitives::Version>) {
+        if (unlikely(name == "Core_version")) {
+          return cache_->getVersion(env->module_instance->getCodeHash(), [&] {
+            return callInternal<Result>(
+                *env, name, std::forward<Args>(args)...);
+          });
+        }
+      }
+
+      if constexpr (std::is_same_v<Result, primitives::OpaqueMetadata>) {
+        if (unlikely(name == "Metadata_metadata")) {
+          return cache_->getMetadata(env->module_instance->getCodeHash(), [&] {
+            return callInternal<Result>(
+                *env, name, std::forward<Args>(args)...);
+          });
+        }
+      }
+
       return callInternal<Result>(*env, name, std::forward<Args>(args)...);
     }
 
@@ -263,4 +330,6 @@ namespace kagome::runtime {
 
 }  // namespace kagome::runtime
 
+#undef unlikely
+
 #endif  // KAGOME_CORE_RUNTIME_COMMON_EXECUTOR_HPP

From 2b2f807d4562a06f4bce30dcea9f8a13c62a3261 Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Wed, 2 Nov 2022 17:13:21 +0800
Subject: [PATCH 04/13] fix: tests

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 .../binaryen/core_api_factory_impl.cpp        | 10 +++---
 .../binaryen/core_api_factory_impl.hpp        |  5 ++-
 .../binaryen/instance_environment_factory.cpp |  9 ++++--
 .../binaryen/instance_environment_factory.hpp |  8 ++++-
 core/runtime/wavm/core_api_factory_impl.cpp   | 10 +++---
 core/runtime/wavm/core_api_factory_impl.hpp   |  5 ++-
 .../wavm/instance_environment_factory.cpp     | 10 ++++--
 .../wavm/instance_environment_factory.hpp     |  7 ++--
 test/core/runtime/CMakeLists.txt              | 10 +++---
 .../binaryen/binaryen_runtime_test.hpp        |  7 ++--
 test/core/runtime/executor_test.cpp           | 18 +++++++++--
 test/core/runtime/runtime_test_base.hpp       | 15 ++++++++-
 test/core/runtime/wavm/wasm_executor_test.cpp | 25 +++++++++++----
 test/core/runtime/wavm/wavm_runtime_test.hpp  |  8 +++--
 .../core/runtime/module_instance_mock.hpp     |  2 ++
 .../runtime/runtime_properties_cache_mock.hpp | 32 +++++++++++++++++++
 16 files changed, 142 insertions(+), 39 deletions(-)
 create mode 100644 test/mock/core/runtime/runtime_properties_cache_mock.hpp

diff --git a/core/runtime/binaryen/core_api_factory_impl.cpp b/core/runtime/binaryen/core_api_factory_impl.cpp
index 712ccb2348..30477d099b 100644
--- a/core/runtime/binaryen/core_api_factory_impl.cpp
+++ b/core/runtime/binaryen/core_api_factory_impl.cpp
@@ -65,13 +65,16 @@ namespace kagome::runtime::binaryen {
   CoreApiFactoryImpl::CoreApiFactoryImpl(
       std::shared_ptr<const InstanceEnvironmentFactory> instance_env_factory,
       std::shared_ptr<const blockchain::BlockHeaderRepository> header_repo,
-      std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker)
+      std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
+      std::shared_ptr<runtime::RuntimePropertiesCache> cache)
       : instance_env_factory_{std::move(instance_env_factory)},
         header_repo_{std::move(header_repo)},
-        changes_tracker_{std::move(changes_tracker)} {
+        changes_tracker_{std::move(changes_tracker)},
+        cache_(std::move(cache)) {
     BOOST_ASSERT(instance_env_factory_ != nullptr);
     BOOST_ASSERT(header_repo_ != nullptr);
     BOOST_ASSERT(changes_tracker_ != nullptr);
+    BOOST_ASSERT(cache_ != nullptr);
   }
 
   std::unique_ptr<Core> CoreApiFactoryImpl::make(
@@ -83,8 +86,7 @@ namespace kagome::runtime::binaryen {
         std::make_shared<OneModuleRepository>(
             runtime_code, instance_env_factory_, code_hash),
         header_repo_);
-    auto cache = std::make_shared<runtime::RuntimePropertiesCacheImpl>();
-    auto executor = std::make_unique<Executor>(env_factory, cache);
+    auto executor = std::make_unique<Executor>(env_factory, cache_);
     return std::make_unique<CoreImpl>(
         std::move(executor), changes_tracker_, header_repo_);
   }
diff --git a/core/runtime/binaryen/core_api_factory_impl.hpp b/core/runtime/binaryen/core_api_factory_impl.hpp
index f7752b4b9a..5c939abde9 100644
--- a/core/runtime/binaryen/core_api_factory_impl.hpp
+++ b/core/runtime/binaryen/core_api_factory_impl.hpp
@@ -25,6 +25,7 @@ namespace kagome::runtime {
   class TrieStorageProvider;
   class Memory;
   class RuntimeEnvironmentFactory;
+  class RuntimePropertiesCache;
 }  // namespace kagome::runtime
 
 namespace kagome::runtime::binaryen {
@@ -39,7 +40,8 @@ namespace kagome::runtime::binaryen {
     CoreApiFactoryImpl(
         std::shared_ptr<const InstanceEnvironmentFactory> instance_env_factory,
         std::shared_ptr<const blockchain::BlockHeaderRepository> header_repo,
-        std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker);
+        std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
+        std::shared_ptr<runtime::RuntimePropertiesCache> cache);
 
     std::unique_ptr<Core> make(
         std::shared_ptr<const crypto::Hasher> hasher,
@@ -49,6 +51,7 @@ namespace kagome::runtime::binaryen {
     std::shared_ptr<const InstanceEnvironmentFactory> instance_env_factory_;
     std::shared_ptr<const blockchain::BlockHeaderRepository> header_repo_;
     std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker_;
+    std::shared_ptr<runtime::RuntimePropertiesCache> cache_;
   };
 
 }  // namespace kagome::runtime::binaryen
diff --git a/core/runtime/binaryen/instance_environment_factory.cpp b/core/runtime/binaryen/instance_environment_factory.cpp
index 02a4ff6cf7..42d4b02f29 100644
--- a/core/runtime/binaryen/instance_environment_factory.cpp
+++ b/core/runtime/binaryen/instance_environment_factory.cpp
@@ -17,17 +17,20 @@ namespace kagome::runtime::binaryen {
       std::shared_ptr<storage::trie::TrieSerializer> serializer,
       std::shared_ptr<host_api::HostApiFactory> host_api_factory,
       std::shared_ptr<blockchain::BlockHeaderRepository> block_header_repo,
-      std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker)
+      std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
+      std::shared_ptr<runtime::RuntimePropertiesCache> cache)
       : storage_{std::move(storage)},
         serializer_{std::move(serializer)},
         host_api_factory_{std::move(host_api_factory)},
         block_header_repo_{std::move(block_header_repo)},
-        changes_tracker_{std::move(changes_tracker)} {
+        changes_tracker_{std::move(changes_tracker)},
+        cache_(std::move(cache)) {
     BOOST_ASSERT(storage_);
     BOOST_ASSERT(serializer_);
     BOOST_ASSERT(host_api_factory_);
     BOOST_ASSERT(block_header_repo_);
     BOOST_ASSERT(changes_tracker_);
+    BOOST_ASSERT(cache_);
   }
 
   BinaryenInstanceEnvironment InstanceEnvironmentFactory::make() const {
@@ -37,7 +40,7 @@ namespace kagome::runtime::binaryen {
     auto new_storage_provider =
         std::make_shared<TrieStorageProviderImpl>(storage_, serializer_);
     auto core_factory = std::make_shared<CoreApiFactoryImpl>(
-        shared_from_this(), block_header_repo_, changes_tracker_);
+        shared_from_this(), block_header_repo_, changes_tracker_, cache_);
     auto host_api = std::shared_ptr<host_api::HostApi>(host_api_factory_->make(
         core_factory, new_memory_provider, new_storage_provider));
     auto rei = std::make_shared<RuntimeExternalInterface>(host_api);
diff --git a/core/runtime/binaryen/instance_environment_factory.hpp b/core/runtime/binaryen/instance_environment_factory.hpp
index 44efea914b..edca5dcc68 100644
--- a/core/runtime/binaryen/instance_environment_factory.hpp
+++ b/core/runtime/binaryen/instance_environment_factory.hpp
@@ -25,6 +25,10 @@ namespace kagome::blockchain {
   class BlockHeaderRepository;
 }
 
+namespace kagome::runtime {
+  class RuntimePropertiesCache;
+}
+
 namespace kagome::runtime::binaryen {
 
   class RuntimeExternalInterface;
@@ -42,7 +46,8 @@ namespace kagome::runtime::binaryen {
         std::shared_ptr<storage::trie::TrieSerializer> serializer,
         std::shared_ptr<host_api::HostApiFactory> host_api_factory,
         std::shared_ptr<blockchain::BlockHeaderRepository> block_header_repo,
-        std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker);
+        std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
+        std::shared_ptr<RuntimePropertiesCache> cache);
 
     [[nodiscard]] BinaryenInstanceEnvironment make() const;
 
@@ -52,6 +57,7 @@ namespace kagome::runtime::binaryen {
     std::shared_ptr<host_api::HostApiFactory> host_api_factory_;
     std::shared_ptr<blockchain::BlockHeaderRepository> block_header_repo_;
     std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker_;
+    std::shared_ptr<RuntimePropertiesCache> cache_;
   };
 
 }  // namespace kagome::runtime::binaryen
diff --git a/core/runtime/wavm/core_api_factory_impl.cpp b/core/runtime/wavm/core_api_factory_impl.cpp
index 18ff4246fe..6cbd747117 100644
--- a/core/runtime/wavm/core_api_factory_impl.cpp
+++ b/core/runtime/wavm/core_api_factory_impl.cpp
@@ -95,7 +95,8 @@ namespace kagome::runtime::wavm {
       std::shared_ptr<blockchain::BlockHeaderRepository> block_header_repo,
       std::shared_ptr<const InstanceEnvironmentFactory> instance_env_factory,
       std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
-      std::shared_ptr<SingleModuleCache> last_compiled_module)
+      std::shared_ptr<SingleModuleCache> last_compiled_module,
+      std::shared_ptr<runtime::RuntimePropertiesCache> cache)
       : instance_env_factory_{std::move(instance_env_factory)},
         compartment_{compartment},
         module_params_{std::move(module_params)},
@@ -103,7 +104,8 @@ namespace kagome::runtime::wavm {
         storage_{std::move(storage)},
         block_header_repo_{std::move(block_header_repo)},
         changes_tracker_{std::move(changes_tracker)},
-        last_compiled_module_{last_compiled_module} {
+        last_compiled_module_{last_compiled_module},
+        cache_(std::move(cache)) {
     BOOST_ASSERT(compartment_);
     BOOST_ASSERT(module_params_);
     BOOST_ASSERT(intrinsic_module_);
@@ -112,6 +114,7 @@ namespace kagome::runtime::wavm {
     BOOST_ASSERT(instance_env_factory_);
     BOOST_ASSERT(changes_tracker_);
     BOOST_ASSERT(last_compiled_module_);
+    BOOST_ASSERT(cache_);
   }
 
   std::unique_ptr<Core> CoreApiFactoryImpl::make(
@@ -132,8 +135,7 @@ namespace kagome::runtime::wavm {
             code_hash,
             last_compiled_module_),
         block_header_repo_);
-    auto cache = std::make_shared<runtime::RuntimePropertiesCacheImpl>();
-    auto executor = std::make_unique<runtime::Executor>(env_factory, cache);
+    auto executor = std::make_unique<runtime::Executor>(env_factory, cache_);
     return std::make_unique<CoreImpl>(
         std::move(executor), changes_tracker_, block_header_repo_);
   }
diff --git a/core/runtime/wavm/core_api_factory_impl.hpp b/core/runtime/wavm/core_api_factory_impl.hpp
index bdfa3a2186..941fd071a1 100644
--- a/core/runtime/wavm/core_api_factory_impl.hpp
+++ b/core/runtime/wavm/core_api_factory_impl.hpp
@@ -26,6 +26,7 @@ namespace kagome::runtime {
   class Memory;
   class ModuleRepository;
   class SingleModuleCache;
+  class RuntimePropertiesCache;
 }  // namespace kagome::runtime
 
 namespace kagome::runtime::wavm {
@@ -47,7 +48,8 @@ namespace kagome::runtime::wavm {
         std::shared_ptr<blockchain::BlockHeaderRepository> block_header_repo,
         std::shared_ptr<const InstanceEnvironmentFactory> instance_env_factory,
         std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
-        std::shared_ptr<SingleModuleCache> last_compiled_module);
+        std::shared_ptr<SingleModuleCache> last_compiled_module,
+        std::shared_ptr<runtime::RuntimePropertiesCache> cache);
 
     [[nodiscard]] std::unique_ptr<Core> make(
         std::shared_ptr<const crypto::Hasher> hasher,
@@ -62,6 +64,7 @@ namespace kagome::runtime::wavm {
     std::shared_ptr<blockchain::BlockHeaderRepository> block_header_repo_;
     std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker_;
     std::shared_ptr<SingleModuleCache> last_compiled_module_;
+    std::shared_ptr<runtime::RuntimePropertiesCache> cache_;
   };
 
 }  // namespace kagome::runtime::wavm
diff --git a/core/runtime/wavm/instance_environment_factory.cpp b/core/runtime/wavm/instance_environment_factory.cpp
index d29bbb35d2..23ce7e5b3c 100644
--- a/core/runtime/wavm/instance_environment_factory.cpp
+++ b/core/runtime/wavm/instance_environment_factory.cpp
@@ -25,7 +25,8 @@ namespace kagome::runtime::wavm {
       std::shared_ptr<host_api::HostApiFactory> host_api_factory,
       std::shared_ptr<blockchain::BlockHeaderRepository> block_header_repo,
       std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
-      std::shared_ptr<kagome::runtime::SingleModuleCache> last_compiled_module)
+      std::shared_ptr<kagome::runtime::SingleModuleCache> last_compiled_module,
+      std::shared_ptr<runtime::RuntimePropertiesCache> cache)
       : storage_{std::move(storage)},
         serializer_{std::move(serializer)},
         compartment_{std::move(compartment)},
@@ -34,7 +35,8 @@ namespace kagome::runtime::wavm {
         host_api_factory_{std::move(host_api_factory)},
         block_header_repo_{std::move(block_header_repo)},
         changes_tracker_{std::move(changes_tracker)},
-        last_compiled_module_{std::move(last_compiled_module)} {
+        last_compiled_module_{std::move(last_compiled_module)},
+        cache_(std::move(cache)) {
     BOOST_ASSERT(storage_ != nullptr);
     BOOST_ASSERT(serializer_ != nullptr);
     BOOST_ASSERT(compartment_ != nullptr);
@@ -44,6 +46,7 @@ namespace kagome::runtime::wavm {
     BOOST_ASSERT(block_header_repo_ != nullptr);
     BOOST_ASSERT(changes_tracker_ != nullptr);
     BOOST_ASSERT(last_compiled_module_ != nullptr);
+    BOOST_ASSERT(cache_ != nullptr);
   }
 
   InstanceEnvironment InstanceEnvironmentFactory::make(
@@ -60,7 +63,8 @@ namespace kagome::runtime::wavm {
                                              block_header_repo_,
                                              shared_from_this(),
                                              changes_tracker_,
-                                             last_compiled_module_);
+                                             last_compiled_module_,
+                                             cache_);
 
     std::shared_ptr<MemoryProvider> memory_provider;
     switch (memory_origin) {
diff --git a/core/runtime/wavm/instance_environment_factory.hpp b/core/runtime/wavm/instance_environment_factory.hpp
index 628859c82f..4f5dac4304 100644
--- a/core/runtime/wavm/instance_environment_factory.hpp
+++ b/core/runtime/wavm/instance_environment_factory.hpp
@@ -31,7 +31,8 @@ namespace WAVM::Runtime {
 
 namespace kagome::runtime {
   class SingleModuleCache;
-}
+  class RuntimePropertiesCache;
+}  // namespace kagome::runtime
 
 namespace kagome::runtime::wavm {
   class IntrinsicModule;
@@ -52,7 +53,8 @@ namespace kagome::runtime::wavm {
         std::shared_ptr<host_api::HostApiFactory> host_api_factory,
         std::shared_ptr<blockchain::BlockHeaderRepository> block_header_repo,
         std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker,
-        std::shared_ptr<SingleModuleCache> last_compiled_module);
+        std::shared_ptr<SingleModuleCache> last_compiled_module,
+        std::shared_ptr<RuntimePropertiesCache> cache);
 
     enum class MemoryOrigin { EXTERNAL, INTERNAL };
     [[nodiscard]] InstanceEnvironment make(
@@ -70,6 +72,7 @@ namespace kagome::runtime::wavm {
     std::shared_ptr<blockchain::BlockHeaderRepository> block_header_repo_;
     std::shared_ptr<storage::changes_trie::ChangesTracker> changes_tracker_;
     std::shared_ptr<SingleModuleCache> last_compiled_module_;
+    std::shared_ptr<RuntimePropertiesCache> cache_;
   };
 
 }  // namespace kagome::runtime::wavm
diff --git a/test/core/runtime/CMakeLists.txt b/test/core/runtime/CMakeLists.txt
index 487e0e360a..15ff726a03 100644
--- a/test/core/runtime/CMakeLists.txt
+++ b/test/core/runtime/CMakeLists.txt
@@ -62,9 +62,9 @@ target_link_libraries(runtime_upgrade_tracker_test
     )
 
 addtest(small_lru_cache_test
-        small_lru_cache_test.cpp
-        )
+    small_lru_cache_test.cpp
+    )
 target_link_libraries(small_lru_cache_test
-        module_repository
-        blob
-        )
+    module_repository
+    blob
+    )
diff --git a/test/core/runtime/binaryen/binaryen_runtime_test.hpp b/test/core/runtime/binaryen/binaryen_runtime_test.hpp
index 6cc8abc9b9..227781ed5f 100644
--- a/test/core/runtime/binaryen/binaryen_runtime_test.hpp
+++ b/test/core/runtime/binaryen/binaryen_runtime_test.hpp
@@ -18,7 +18,7 @@
 
 class BinaryenRuntimeTest : public RuntimeTestBase {
  public:
-  virtual std::shared_ptr<kagome::runtime::ModuleFactory> createModuleFactory()
+  std::shared_ptr<kagome::runtime::ModuleFactory> createModuleFactory()
       override {
     auto memory_factory =
         std::make_shared<kagome::runtime::binaryen::BinaryenMemoryFactory>();
@@ -32,11 +32,12 @@ class BinaryenRuntimeTest : public RuntimeTestBase {
             serializer_,
             host_api_factory_,
             header_repo_,
-            changes_tracker_);
+            changes_tracker_,
+            cache_);
 
     auto module_factory =
         std::make_shared<kagome::runtime::binaryen::ModuleFactoryImpl>(
-            instance_env_factory, trie_storage_);
+            instance_env_factory, trie_storage_, hasher_);
     return module_factory;
   }
 };
diff --git a/test/core/runtime/executor_test.cpp b/test/core/runtime/executor_test.cpp
index 886303d294..ed15666325 100644
--- a/test/core/runtime/executor_test.cpp
+++ b/test/core/runtime/executor_test.cpp
@@ -15,6 +15,7 @@
 #include "mock/core/runtime/module_instance_mock.hpp"
 #include "mock/core/runtime/module_repository_mock.hpp"
 #include "mock/core/runtime/runtime_environment_factory_mock.hpp"
+#include "mock/core/runtime/runtime_properties_cache_mock.hpp"
 #include "mock/core/runtime/trie_storage_provider_mock.hpp"
 #include "mock/core/storage/trie/trie_batches_mock.hpp"
 #include "mock/core/storage/trie/trie_storage_mock.hpp"
@@ -37,6 +38,7 @@ using kagome::runtime::ModuleRepositoryMock;
 using kagome::runtime::PtrSize;
 using kagome::runtime::RuntimeEnvironment;
 using kagome::runtime::RuntimeEnvironmentTemplateMock;
+using kagome::runtime::RuntimePropertiesCacheMock;
 using kagome::runtime::TrieStorageProviderMock;
 using kagome::storage::trie::PersistentTrieBatch;
 using kagome::storage::trie::PersistentTrieBatchMock;
@@ -54,14 +56,25 @@ class ExecutorTest : public testing::Test {
 
   void SetUp() override {
     memory_ = std::make_unique<MemoryMock>();
+
+    header_repo_ = std::make_shared<BlockHeaderRepositoryMock>();
+
     auto code_provider = std::make_shared<BasicCodeProvider>(
         boost::filesystem::path(__FILE__).parent_path().string()
         + "/wasm/sumtwo.wasm");
     auto module_repo = std::make_shared<ModuleRepositoryMock>();
-    header_repo_ = std::make_shared<BlockHeaderRepositoryMock>();
     env_factory_ =
         std::make_shared<kagome::runtime::RuntimeEnvironmentFactoryMock>(
             code_provider, module_repo, header_repo_);
+
+    cache_ = std::make_shared<RuntimePropertiesCacheMock>();
+    ON_CALL(*cache_, getVersion(_, _))
+        .WillByDefault(testing::Invoke(
+            [](const auto &hash, auto func) { return func(); }));
+    ON_CALL(*cache_, getMetadata(_, _))
+        .WillByDefault(testing::Invoke(
+            [](const auto &hash, auto func) { return func(); }));
+
     storage_ = std::make_shared<kagome::storage::trie::TrieStorageMock>();
   }
 
@@ -190,12 +203,13 @@ class ExecutorTest : public testing::Test {
  protected:
   std::unique_ptr<MemoryMock> memory_;
   std::shared_ptr<kagome::runtime::RuntimeEnvironmentFactoryMock> env_factory_;
+  std::shared_ptr<kagome::runtime::RuntimePropertiesCacheMock> cache_;
   std::shared_ptr<BlockHeaderRepositoryMock> header_repo_;
   std::shared_ptr<kagome::storage::trie::TrieStorageMock> storage_;
 };
 
 TEST_F(ExecutorTest, LatestStateSwitchesCorrectly) {
-  Executor executor{env_factory_};
+  Executor executor{env_factory_, cache_};
   kagome::primitives::BlockInfo block_info1{42, "block_hash1"_hash256};
   kagome::primitives::BlockInfo block_info2{43, "block_hash2"_hash256};
   kagome::primitives::BlockInfo block_info3{44, "block_hash3"_hash256};
diff --git a/test/core/runtime/runtime_test_base.hpp b/test/core/runtime/runtime_test_base.hpp
index 20fe91cb0e..750fad6294 100644
--- a/test/core/runtime/runtime_test_base.hpp
+++ b/test/core/runtime/runtime_test_base.hpp
@@ -25,8 +25,10 @@
 #include "mock/core/application/app_configuration_mock.hpp"
 #include "mock/core/blockchain/block_header_repository_mock.hpp"
 #include "mock/core/blockchain/block_storage_mock.hpp"
+#include "mock/core/crypto/hasher_mock.hpp"
 #include "mock/core/offchain/offchain_persistent_storage_mock.hpp"
 #include "mock/core/offchain/offchain_worker_pool_mock.hpp"
+#include "mock/core/runtime/runtime_properties_cache_mock.hpp"
 #include "mock/core/runtime/trie_storage_provider_mock.hpp"
 #include "mock/core/storage/changes_trie/changes_tracker_mock.hpp"
 #include "mock/core/storage/trie/polkadot_trie_cursor_mock.h"
@@ -132,6 +134,15 @@ class RuntimeTestBase : public ::testing::Test {
     initStorage();
     trie_storage_ = std::make_shared<storage::trie::TrieStorageMock>();
     serializer_ = std::make_shared<storage::trie::TrieSerializerMock>();
+    hasher_ = std::make_shared<crypto::HasherMock>();
+
+    cache_ = std::make_shared<runtime::RuntimePropertiesCacheMock>();
+    ON_CALL(*cache_, getVersion(_, _))
+        .WillByDefault(testing::Invoke(
+            [](const auto &hash, auto func) { return func(); }));
+    ON_CALL(*cache_, getMetadata(_, _))
+        .WillByDefault(testing::Invoke(
+            [](const auto &hash, auto func) { return func(); }));
 
     auto module_factory = createModuleFactory();
 
@@ -156,7 +167,8 @@ class RuntimeTestBase : public ::testing::Test {
     runtime_env_factory_ = std::make_shared<runtime::RuntimeEnvironmentFactory>(
         std::move(wasm_provider_), std::move(module_repo), header_repo_);
 
-    executor_ = std::make_shared<runtime::Executor>(runtime_env_factory_);
+    executor_ =
+        std::make_shared<runtime::Executor>(runtime_env_factory_, cache_);
   }
 
   void preparePersistentStorageExpects() {
@@ -237,6 +249,7 @@ class RuntimeTestBase : public ::testing::Test {
   std::shared_ptr<storage::trie::TrieStorageMock> trie_storage_;
   std::shared_ptr<storage::trie::TrieSerializerMock> serializer_;
   std::shared_ptr<runtime::RuntimeEnvironmentFactory> runtime_env_factory_;
+  std::shared_ptr<runtime::RuntimePropertiesCacheMock> cache_;
   std::shared_ptr<runtime::Executor> executor_;
   std::shared_ptr<storage::changes_trie::ChangesTrackerMock> changes_tracker_;
   std::shared_ptr<offchain::OffchainPersistentStorageMock> offchain_storage_;
diff --git a/test/core/runtime/wavm/wasm_executor_test.cpp b/test/core/runtime/wavm/wasm_executor_test.cpp
index 8f98169246..932223e03f 100644
--- a/test/core/runtime/wavm/wasm_executor_test.cpp
+++ b/test/core/runtime/wavm/wasm_executor_test.cpp
@@ -21,6 +21,7 @@
 #include "mock/core/blockchain/block_header_repository_mock.hpp"
 #include "mock/core/offchain/offchain_persistent_storage_mock.hpp"
 #include "mock/core/offchain/offchain_worker_pool_mock.hpp"
+#include "mock/core/runtime/runtime_properties_cache_mock.hpp"
 #include "mock/core/runtime/runtime_upgrade_tracker_mock.hpp"
 #include "mock/core/storage/changes_trie/changes_tracker_mock.hpp"
 #include "runtime/common/executor.hpp"
@@ -32,8 +33,6 @@
 #include "runtime/wavm/core_api_factory_impl.hpp"
 #include "runtime/wavm/instance_environment_factory.hpp"
 #include "runtime/wavm/intrinsics/intrinsic_module.hpp"
-#include "runtime/wavm/intrinsics/intrinsic_module_instance.hpp"
-#include "runtime/wavm/intrinsics/intrinsic_resolver_impl.hpp"
 #include "runtime/wavm/module_cache.hpp"
 #include "runtime/wavm/module_factory_impl.hpp"
 #include "runtime/wavm/module_params.hpp"
@@ -70,6 +69,7 @@ using kagome::runtime::Executor;
 using kagome::runtime::RuntimeCodeProvider;
 using kagome::runtime::RuntimeEnvironmentFactory;
 using kagome::runtime::RuntimeInstancesPool;
+using kagome::runtime::RuntimePropertiesCacheMock;
 using kagome::runtime::TrieStorageProvider;
 using kagome::runtime::TrieStorageProviderImpl;
 using kagome::runtime::wavm::ModuleParams;
@@ -180,7 +180,8 @@ class WasmExecutorTest : public ::testing::Test {
             host_api_factory,
             header_repo_,
             changes_tracker,
-            bogus_smc);
+            bogus_smc,
+            cache_);
 
     auto module_factory =
         std::make_shared<kagome::runtime::wavm::ModuleFactoryImpl>(
@@ -188,7 +189,8 @@ class WasmExecutorTest : public ::testing::Test {
             module_params,
             instance_env_factory,
             intrinsic_module,
-            std::nullopt);
+            std::nullopt,
+            hasher);
     auto module_repo = std::make_shared<kagome::runtime::ModuleRepositoryImpl>(
         std::make_shared<RuntimeInstancesPool>(),
         runtime_upgrade_tracker_,
@@ -204,14 +206,24 @@ class WasmExecutorTest : public ::testing::Test {
             header_repo_,
             instance_env_factory,
             changes_tracker,
-            std::make_shared<kagome::runtime::SingleModuleCache>());
+            std::make_shared<kagome::runtime::SingleModuleCache>(),
+            cache_);
     auto host_api =
         std::shared_ptr<kagome::host_api::HostApi>{host_api_factory->make(
             core_provider, memory_provider, storage_provider_)};
 
     auto env_factory = std::make_shared<RuntimeEnvironmentFactory>(
         wasm_provider_, module_repo, header_repo_);
-    executor_ = std::make_shared<Executor>(env_factory);
+
+    cache_ = std::make_shared<RuntimePropertiesCacheMock>();
+    ON_CALL(*cache_, getVersion(_, _))
+        .WillByDefault(testing::Invoke(
+            [](const auto &hash, auto func) { return func(); }));
+    ON_CALL(*cache_, getMetadata(_, _))
+        .WillByDefault(testing::Invoke(
+            [](const auto &hash, auto func) { return func(); }));
+
+    executor_ = std::make_shared<Executor>(env_factory, cache_);
   }
 
  protected:
@@ -219,6 +231,7 @@ class WasmExecutorTest : public ::testing::Test {
   std::shared_ptr<TrieStorageProvider> storage_provider_;
   std::shared_ptr<RuntimeCodeProvider> wasm_provider_;
   std::shared_ptr<BlockHeaderRepositoryMock> header_repo_;
+  std::shared_ptr<RuntimePropertiesCacheMock> cache_;
   std::shared_ptr<kagome::runtime::RuntimeUpgradeTrackerMock>
       runtime_upgrade_tracker_;
 };
diff --git a/test/core/runtime/wavm/wavm_runtime_test.hpp b/test/core/runtime/wavm/wavm_runtime_test.hpp
index 6abd540042..0ec47805e0 100644
--- a/test/core/runtime/wavm/wavm_runtime_test.hpp
+++ b/test/core/runtime/wavm/wavm_runtime_test.hpp
@@ -24,7 +24,7 @@
 
 class WavmRuntimeTest : public RuntimeTestBase {
  public:
-  virtual std::shared_ptr<kagome::runtime::ModuleFactory> createModuleFactory()
+  std::shared_ptr<kagome::runtime::ModuleFactory> createModuleFactory()
       override {
     auto compartment =
         std::make_shared<kagome::runtime::wavm::CompartmentWrapper>(
@@ -52,7 +52,8 @@ class WavmRuntimeTest : public RuntimeTestBase {
             host_api_factory_,
             header_repo_,
             changes_tracker,
-            std::make_shared<kagome::runtime::SingleModuleCache>());
+            std::make_shared<kagome::runtime::SingleModuleCache>(),
+            cache_);
 
     auto module_factory =
         std::make_shared<kagome::runtime::wavm::ModuleFactoryImpl>(
@@ -60,7 +61,8 @@ class WavmRuntimeTest : public RuntimeTestBase {
             module_params,
             instance_env_factory,
             intrinsic_module,
-            std::nullopt);
+            std::nullopt,
+            hasher_);
 
     return module_factory;
   }
diff --git a/test/mock/core/runtime/module_instance_mock.hpp b/test/mock/core/runtime/module_instance_mock.hpp
index 0134dd0388..7063a72b4e 100644
--- a/test/mock/core/runtime/module_instance_mock.hpp
+++ b/test/mock/core/runtime/module_instance_mock.hpp
@@ -14,6 +14,8 @@ namespace kagome::runtime {
 
   class ModuleInstanceMock : public ModuleInstance {
    public:
+    MOCK_METHOD(const common::Hash256 &, getCodeHash, (), (const, override));
+
     MOCK_METHOD(outcome::result<PtrSize>,
                 callExportFunction,
                 (std::string_view name, common::BufferView args),
diff --git a/test/mock/core/runtime/runtime_properties_cache_mock.hpp b/test/mock/core/runtime/runtime_properties_cache_mock.hpp
new file mode 100644
index 0000000000..8939184865
--- /dev/null
+++ b/test/mock/core/runtime/runtime_properties_cache_mock.hpp
@@ -0,0 +1,32 @@
+/**
+ * Copyright Soramitsu Co., Ltd. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef KAGOME_RUNTIME_RUNTIMEPROPERTIESCACHEMOCK
+#define KAGOME_RUNTIME_RUNTIMEPROPERTIESCACHEMOCK
+
+#include "runtime/runtime_properties_cache.hpp"
+
+#include <gmock/gmock.h>
+
+namespace kagome::runtime {
+
+  class RuntimePropertiesCacheMock : public RuntimePropertiesCache {
+   public:
+    MOCK_METHOD(outcome::result<primitives::Version>,
+                getVersion,
+                (const common::Hash256 &,
+                 std::function<outcome::result<primitives::Version>()>),
+                (override));
+
+    MOCK_METHOD(outcome::result<primitives::OpaqueMetadata>,
+                getMetadata,
+                (const common::Hash256 &,
+                 std::function<outcome::result<primitives::OpaqueMetadata>()>),
+                (override));
+  };
+
+}  // namespace kagome::runtime
+
+#endif  // KAGOME_RUNTIME_RUNTIMEPROPERTIESCACHEMOCK

From eaabfdcb96ef96685f6e44d3581c91454158e80d Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Wed, 2 Nov 2022 19:48:30 +0800
Subject: [PATCH 05/13] fix: tests

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 test/core/runtime/executor_test.cpp           |  8 ++++----
 test/core/runtime/runtime_test_base.hpp       |  9 +++++----
 test/core/runtime/wavm/wasm_executor_test.cpp | 10 ++++++----
 3 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/test/core/runtime/executor_test.cpp b/test/core/runtime/executor_test.cpp
index ed15666325..f674cee8ad 100644
--- a/test/core/runtime/executor_test.cpp
+++ b/test/core/runtime/executor_test.cpp
@@ -69,11 +69,11 @@ class ExecutorTest : public testing::Test {
 
     cache_ = std::make_shared<RuntimePropertiesCacheMock>();
     ON_CALL(*cache_, getVersion(_, _))
-        .WillByDefault(testing::Invoke(
-            [](const auto &hash, auto func) { return func(); }));
+        .WillByDefault(
+            Invoke([](const auto &hash, auto func) { return func(); }));
     ON_CALL(*cache_, getMetadata(_, _))
-        .WillByDefault(testing::Invoke(
-            [](const auto &hash, auto func) { return func(); }));
+        .WillByDefault(
+            Invoke([](const auto &hash, auto func) { return func(); }));
 
     storage_ = std::make_shared<kagome::storage::trie::TrieStorageMock>();
   }
diff --git a/test/core/runtime/runtime_test_base.hpp b/test/core/runtime/runtime_test_base.hpp
index 750fad6294..7750fe237e 100644
--- a/test/core/runtime/runtime_test_base.hpp
+++ b/test/core/runtime/runtime_test_base.hpp
@@ -52,6 +52,7 @@
 #include "testutil/runtime/common/basic_code_provider.hpp"
 
 using testing::_;
+using testing::Invoke;
 using testing::Return;
 
 using namespace kagome;
@@ -138,11 +139,11 @@ class RuntimeTestBase : public ::testing::Test {
 
     cache_ = std::make_shared<runtime::RuntimePropertiesCacheMock>();
     ON_CALL(*cache_, getVersion(_, _))
-        .WillByDefault(testing::Invoke(
-            [](const auto &hash, auto func) { return func(); }));
+        .WillByDefault(
+            Invoke([](const auto &hash, auto func) { return func(); }));
     ON_CALL(*cache_, getMetadata(_, _))
-        .WillByDefault(testing::Invoke(
-            [](const auto &hash, auto func) { return func(); }));
+        .WillByDefault(
+            Invoke([](const auto &hash, auto func) { return func(); }));
 
     auto module_factory = createModuleFactory();
 
diff --git a/test/core/runtime/wavm/wasm_executor_test.cpp b/test/core/runtime/wavm/wasm_executor_test.cpp
index 932223e03f..03f6643af2 100644
--- a/test/core/runtime/wavm/wasm_executor_test.cpp
+++ b/test/core/runtime/wavm/wasm_executor_test.cpp
@@ -80,6 +80,8 @@ using kagome::storage::trie::PolkadotTrieImpl;
 using kagome::storage::trie::TrieSerializerImpl;
 using kagome::storage::trie::TrieStorage;
 using kagome::storage::trie::TrieStorageImpl;
+using testing::_;
+using testing::Invoke;
 using testing::Return;
 
 namespace fs = boost::filesystem;
@@ -217,11 +219,11 @@ class WasmExecutorTest : public ::testing::Test {
 
     cache_ = std::make_shared<RuntimePropertiesCacheMock>();
     ON_CALL(*cache_, getVersion(_, _))
-        .WillByDefault(testing::Invoke(
-            [](const auto &hash, auto func) { return func(); }));
+        .WillByDefault(
+            Invoke([](const auto &hash, auto func) { return func(); }));
     ON_CALL(*cache_, getMetadata(_, _))
-        .WillByDefault(testing::Invoke(
-            [](const auto &hash, auto func) { return func(); }));
+        .WillByDefault(
+            Invoke([](const auto &hash, auto func) { return func(); }));
 
     executor_ = std::make_shared<Executor>(env_factory, cache_);
   }

From efb26c87ebd6b9fb8d331b9d4b7b01aacf95a428 Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Thu, 3 Nov 2022 15:41:00 +0800
Subject: [PATCH 06/13] refactor: move obtaining of version from block tree to
 core api

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 core/api/service/impl/api_service_impl.cpp    | 13 +++++++++----
 core/api/service/impl/api_service_impl.hpp    |  7 ++++++-
 core/blockchain/block_tree.hpp                |  6 ------
 core/blockchain/impl/block_tree_impl.hpp      |  5 -----
 core/injector/application_injector.cpp        |  4 +++-
 test/core/api/transport/listener_test.hpp     |  6 +++++-
 test/mock/core/blockchain/block_tree_mock.hpp |  5 -----
 7 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/core/api/service/impl/api_service_impl.cpp b/core/api/service/impl/api_service_impl.cpp
index eb8c5608f8..47cb55bd84 100644
--- a/core/api/service/impl/api_service_impl.cpp
+++ b/core/api/service/impl/api_service_impl.cpp
@@ -16,6 +16,7 @@
 #include "common/hexutil.hpp"
 #include "primitives/common.hpp"
 #include "primitives/transaction.hpp"
+#include "runtime/runtime_api/core.hpp"
 #include "storage/trie/trie_storage.hpp"
 #include "subscription/extrinsic_event_key_repository.hpp"
 #include "subscription/subscriber.hpp"
@@ -127,13 +128,15 @@ namespace kagome::api {
       std::shared_ptr<subscription::ExtrinsicEventKeyRepository>
           extrinsic_event_key_repo,
       std::shared_ptr<blockchain::BlockTree> block_tree,
-      std::shared_ptr<storage::trie::TrieStorage> trie_storage)
+      std::shared_ptr<storage::trie::TrieStorage> trie_storage,
+      std::shared_ptr<runtime::Core> core)
       : thread_pool_(std::move(thread_pool)),
         listeners_(std::move(listeners.listeners)),
         server_(std::move(server)),
         logger_{log::createLogger("ApiService", "api")},
         block_tree_{std::move(block_tree)},
         trie_storage_{std::move(trie_storage)},
+        core_(std::move(core)),
         subscription_engines_{.storage = std::move(storage_sub_engine),
                               .chain = std::move(chain_sub_engine),
                               .ext = std::move(ext_sub_engine)},
@@ -141,6 +144,7 @@ namespace kagome::api {
     BOOST_ASSERT(thread_pool_);
     BOOST_ASSERT(block_tree_);
     BOOST_ASSERT(trie_storage_);
+    BOOST_ASSERT(core_);
     BOOST_ASSERT(
         std::all_of(listeners_.cbegin(), listeners_.cend(), [](auto &listener) {
           return listener != nullptr;
@@ -402,14 +406,15 @@ namespace kagome::api {
         session->subscribe(
             id, primitives::events::ChainEventType::kFinalizedRuntimeVersion);
 
-        auto ver = block_tree_->runtimeVersion();
-        if (ver) {
+        auto version_res = core_->version();
+        if (version_res.has_value()) {
+          const auto &version = version_res.value();
           session_context.messages = uploadMessagesListFromCache();
           forJsonData(server_,
                       logger_,
                       id,
                       kRpcEventRuntimeVersion,
-                      makeValue(*ver),
+                      makeValue(version),
                       [&](const auto &result) {
                         session_context.messages->emplace_back(
                             uploadFromCache(result.data()));
diff --git a/core/api/service/impl/api_service_impl.hpp b/core/api/service/impl/api_service_impl.hpp
index df8eaa27bc..a90e9f1594 100644
--- a/core/api/service/impl/api_service_impl.hpp
+++ b/core/api/service/impl/api_service_impl.hpp
@@ -41,6 +41,9 @@ namespace kagome::primitives {
 namespace kagome::storage::trie {
   class TrieStorage;
 }
+namespace kagome::runtime {
+  class Core;
+}
 namespace kagome::subscription {
   class ExtrinsicEventKeyRepository;
 }
@@ -135,7 +138,8 @@ namespace kagome::api {
         std::shared_ptr<subscription::ExtrinsicEventKeyRepository>
             extrinsic_event_key_repo,
         std::shared_ptr<blockchain::BlockTree> block_tree,
-        std::shared_ptr<storage::trie::TrieStorage> trie_storage);
+        std::shared_ptr<storage::trie::TrieStorage> trie_storage,
+        std::shared_ptr<runtime::Core> core);
 
     ~ApiServiceImpl() override = default;
 
@@ -241,6 +245,7 @@ namespace kagome::api {
     log::Logger logger_;
     std::shared_ptr<blockchain::BlockTree> block_tree_;
     std::shared_ptr<storage::trie::TrieStorage> trie_storage_;
+    std::shared_ptr<runtime::Core> core_;
 
     std::mutex subscribed_sessions_cs_;
     std::unordered_map<Session::SessionId,
diff --git a/core/blockchain/block_tree.hpp b/core/blockchain/block_tree.hpp
index d3596e926f..aafc9b302b 100644
--- a/core/blockchain/block_tree.hpp
+++ b/core/blockchain/block_tree.hpp
@@ -72,12 +72,6 @@ namespace kagome::blockchain {
     virtual outcome::result<primitives::Justification> getBlockJustification(
         const primitives::BlockId &block) const = 0;
 
-    /**
-     * Method to get actual runtime version.
-     * @return runtime version.
-     */
-    virtual std::optional<primitives::Version> runtimeVersion() const = 0;
-
     /**
      * Adds header to the storage
      * @param header that we are adding
diff --git a/core/blockchain/impl/block_tree_impl.hpp b/core/blockchain/impl/block_tree_impl.hpp
index 59456b8b18..9927592450 100644
--- a/core/blockchain/impl/block_tree_impl.hpp
+++ b/core/blockchain/impl/block_tree_impl.hpp
@@ -113,10 +113,6 @@ namespace kagome::blockchain {
         const primitives::BlockHash &ancestor,
         const primitives::BlockHash &descendant) const override;
 
-    std::optional<primitives::Version> runtimeVersion() const override {
-      return actual_runtime_version_;
-    }
-
     bool hasDirectChain(const primitives::BlockHash &ancestor,
                         const primitives::BlockHash &descendant) const override;
 
@@ -190,7 +186,6 @@ namespace kagome::blockchain {
         justification_storage_policy_;
 
     std::optional<primitives::BlockHash> genesis_block_hash_;
-    std::optional<primitives::Version> actual_runtime_version_;
 
     log::Logger log_ = log::createLogger("BlockTree", "blockchain");
 
diff --git a/core/injector/application_injector.cpp b/core/injector/application_injector.cpp
index 2cd771f47e..3bdd86444c 100644
--- a/core/injector/application_injector.cpp
+++ b/core/injector/application_injector.cpp
@@ -534,6 +534,7 @@ namespace {
     auto block_tree = injector.template create<sptr<blockchain::BlockTree>>();
     auto trie_storage =
         injector.template create<sptr<storage::trie::TrieStorage>>();
+    auto core = injector.template create<sptr<runtime::Core>>();
 
     auto api_service =
         std::make_shared<api::ApiServiceImpl>(asmgr,
@@ -546,7 +547,8 @@ namespace {
                                               ext_sub_engine,
                                               extrinsic_event_key_repo,
                                               block_tree,
-                                              trie_storage);
+                                              trie_storage,
+                                              core);
 
     auto child_state_api =
         injector.template create<std::shared_ptr<api::ChildStateApi>>();
diff --git a/test/core/api/transport/listener_test.hpp b/test/core/api/transport/listener_test.hpp
index 2dba778f45..e9419e9be1 100644
--- a/test/core/api/transport/listener_test.hpp
+++ b/test/core/api/transport/listener_test.hpp
@@ -21,6 +21,7 @@
 #include "mock/core/api/transport/jrpc_processor_stub.hpp"
 #include "mock/core/application/app_state_manager_mock.hpp"
 #include "mock/core/blockchain/block_tree_mock.hpp"
+#include "mock/core/runtime/core_mock.hpp"
 #include "mock/core/storage/trie/trie_storage_mock.hpp"
 #include "primitives/event_types.hpp"
 #include "subscription/extrinsic_event_key_repository.hpp"
@@ -43,6 +44,7 @@ using kagome::primitives::events::ExtrinsicSubscriptionEngine;
 using kagome::primitives::events::ExtrinsicSubscriptionEnginePtr;
 using kagome::primitives::events::StorageSubscriptionEngine;
 using kagome::primitives::events::StorageSubscriptionEnginePtr;
+using kagome::runtime::CoreMock;
 using kagome::storage::trie::TrieStorage;
 using kagome::storage::trie::TrieStorageMock;
 using kagome::subscription::ExtrinsicEventKeyRepository;
@@ -129,6 +131,7 @@ struct ListenerTest : public ::testing::Test {
   std::shared_ptr<BlockTree> block_tree = std::make_shared<BlockTreeMock>();
   std::shared_ptr<TrieStorage> trie_storage =
       std::make_shared<TrieStorageMock>();
+  std::shared_ptr<CoreMock> core = std::make_shared<CoreMock>();
 
   sptr<ApiService> service = std::make_shared<ApiServiceImpl>(
       app_state_manager,
@@ -141,7 +144,8 @@ struct ListenerTest : public ::testing::Test {
       ext_events_engine,
       ext_event_key_repo,
       block_tree,
-      trie_storage);
+      trie_storage,
+      core);
 };
 
 #endif  // KAGOME_TEST_CORE_API_TRANSPORT_LISTENER_TEST_HPP
diff --git a/test/mock/core/blockchain/block_tree_mock.hpp b/test/mock/core/blockchain/block_tree_mock.hpp
index be1273027e..ee9d36425a 100644
--- a/test/mock/core/blockchain/block_tree_mock.hpp
+++ b/test/mock/core/blockchain/block_tree_mock.hpp
@@ -37,11 +37,6 @@ namespace kagome::blockchain {
                 (const primitives::BlockId &),
                 (const, override));
 
-    MOCK_METHOD(std::optional<primitives::Version>,
-                runtimeVersion,
-                (),
-                (const, override));
-
     MOCK_METHOD(outcome::result<void>,
                 addBlockHeader,
                 (const primitives::BlockHeader &),

From e0d1d8f498714e9e12625b7d08e8e3d96ac7986a Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Fri, 11 Nov 2022 19:22:00 +0800
Subject: [PATCH 07/13] fix: external project test

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 core/runtime/runtime_api/impl/CMakeLists.txt  | 109 ++++++++++++++----
 .../impl/runtime_properties_cache_impl.hpp    |   2 +-
 test/external-project-test/src/main.cpp       |   5 +-
 3 files changed, 90 insertions(+), 26 deletions(-)

diff --git a/core/runtime/runtime_api/impl/CMakeLists.txt b/core/runtime/runtime_api/impl/CMakeLists.txt
index 125ecee707..50764b2169 100644
--- a/core/runtime/runtime_api/impl/CMakeLists.txt
+++ b/core/runtime/runtime_api/impl/CMakeLists.txt
@@ -1,30 +1,89 @@
 
-add_library(core_api core.cpp)
-target_link_libraries(core_api executor primitives)
+add_library(core_api
+    core.cpp)
+target_link_libraries(core_api
+    executor
+    primitives
+    )
 kagome_install(core_api)
 
-add_library(account_nonce_api account_nonce_api.cpp)
-target_link_libraries(account_nonce_api executor)
-add_library(authority_discovery_api authority_discovery_api.cpp)
-target_link_libraries(authority_discovery_api executor)
-add_library(babe_api babe_api.cpp)
-target_link_libraries(babe_api executor)
-add_library(block_builder_api block_builder.cpp)
-target_link_libraries(block_builder_api executor primitives)
-add_library(grandpa_api grandpa_api.cpp)
-target_link_libraries(grandpa_api block_header_repository executor)
-add_library(metadata_api metadata.cpp)
-target_link_libraries(metadata_api executor)
-add_library(parachain_host_api parachain_host.cpp parachain_host_types_serde.cpp)
-target_link_libraries(parachain_host_api executor)
-add_library(tagged_transaction_queue_api tagged_transaction_queue.cpp)
-target_link_libraries(tagged_transaction_queue_api executor)
-add_library(transaction_payment_api transaction_payment_api.cpp)
-target_link_libraries(transaction_payment_api executor)
-add_library(offchain_worker_api offchain_worker_api.cpp)
-target_link_libraries(offchain_worker_api offchain_worker)
-add_library(session_keys_api session_keys_api.cpp)
-target_link_libraries(session_keys_api executor)
+add_library(account_nonce_api
+    account_nonce_api.cpp
+    )
+target_link_libraries(account_nonce_api
+    executor
+    )
+
+add_library(authority_discovery_api
+    authority_discovery_api.cpp)
+target_link_libraries(authority_discovery_api
+    executor
+    )
+
+add_library(babe_api
+    babe_api.cpp
+    )
+target_link_libraries(babe_api
+    executor
+    )
+
+add_library(block_builder_api
+    block_builder.cpp
+    )
+target_link_libraries(block_builder_api
+    executor primitives
+    )
+
+add_library(grandpa_api
+    grandpa_api.cpp
+    )
+target_link_libraries(grandpa_api
+    block_header_repository
+    executor
+    )
+
+add_library(metadata_api
+    metadata.cpp
+    )
+target_link_libraries(metadata_api
+    executor
+    )
+
+add_library(parachain_host_api
+    parachain_host.cpp
+    parachain_host_types_serde.cpp
+    )
+target_link_libraries(parachain_host_api
+    executor
+    )
+
+add_library(tagged_transaction_queue_api
+    tagged_transaction_queue.cpp
+    )
+target_link_libraries(tagged_transaction_queue_api
+    executor
+    )
+
+add_library(transaction_payment_api
+    transaction_payment_api.cpp
+    )
+target_link_libraries(transaction_payment_api
+    executor
+    )
+
+add_library(offchain_worker_api
+    offchain_worker_api.cpp
+    )
+target_link_libraries(offchain_worker_api
+    offchain_worker
+    )
+
+add_library(session_keys_api
+    session_keys_api.cpp
+    )
+target_link_libraries(session_keys_api
+    executor
+    )
 
 add_library(runtime_properties_cache
     runtime_properties_cache_impl.cpp
@@ -32,5 +91,7 @@ add_library(runtime_properties_cache
 target_link_libraries(runtime_properties_cache
     executor
     )
+kagome_install(runtime_properties_cache)
+
 
 
diff --git a/core/runtime/runtime_api/impl/runtime_properties_cache_impl.hpp b/core/runtime/runtime_api/impl/runtime_properties_cache_impl.hpp
index c380efb19a..a67e1af994 100644
--- a/core/runtime/runtime_api/impl/runtime_properties_cache_impl.hpp
+++ b/core/runtime/runtime_api/impl/runtime_properties_cache_impl.hpp
@@ -12,7 +12,7 @@ namespace kagome::runtime {
 
   class RuntimePropertiesCacheImpl final : public RuntimePropertiesCache {
    public:
-    RuntimePropertiesCacheImpl() {}
+    RuntimePropertiesCacheImpl() = default;
 
     outcome::result<primitives::Version> getVersion(
         const common::Hash256 &hash,
diff --git a/test/external-project-test/src/main.cpp b/test/external-project-test/src/main.cpp
index 29bcde99fd..735c84a70b 100644
--- a/test/external-project-test/src/main.cpp
+++ b/test/external-project-test/src/main.cpp
@@ -26,6 +26,7 @@
 #include <kagome/runtime/common/runtime_upgrade_tracker_impl.hpp>
 #include <kagome/runtime/common/storage_code_provider.hpp>
 #include <kagome/runtime/module.hpp>
+#include <kagome/runtime/runtime_api/impl/runtime_properties_cache_impl.hpp>
 #include <kagome/runtime/wavm/compartment_wrapper.hpp>
 #include <kagome/runtime/wavm/instance_environment_factory.hpp>
 #include <kagome/runtime/wavm/intrinsics/intrinsic_module.hpp>
@@ -218,8 +219,10 @@ int main() {
   auto env_factory =
       std::make_shared<kagome::runtime::RuntimeEnvironmentFactory>(
           code_provider, module_repo, header_repo);
+  auto cache = std::make_shared<kagome::runtime::RuntimePropertiesCacheImpl>();
 
-  [[maybe_unused]] auto executor = kagome::runtime::Executor(env_factory);
+  [[maybe_unused]] auto executor =
+      kagome::runtime::Executor(env_factory, cache);
 
   // TODO(Harrm): Currently, the test only checks if kagome builds as
   // a dependency in some project. However, we can use the test to run

From 8f5293f96cdbab6d18a3f7a124d076c5ab31df12 Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Fri, 11 Nov 2022 19:33:19 +0800
Subject: [PATCH 08/13] fix: review issues

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 core/runtime/binaryen/module/module_impl.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/runtime/binaryen/module/module_impl.hpp b/core/runtime/binaryen/module/module_impl.hpp
index 656f1c3b39..92634cc395 100644
--- a/core/runtime/binaryen/module/module_impl.hpp
+++ b/core/runtime/binaryen/module/module_impl.hpp
@@ -36,7 +36,7 @@ namespace kagome::runtime::binaryen {
     enum class Error { EMPTY_STATE_CODE = 1, INVALID_STATE_CODE };
 
     ModuleImpl(ModuleImpl &&) = default;
-    //    ModuleImpl &operator=(ModuleImpl &&) = default;
+    ModuleImpl &operator=(ModuleImpl &&) = default;
 
     ModuleImpl(const ModuleImpl &) = delete;
     ModuleImpl &operator=(const ModuleImpl &) = delete;

From 5346cf8c053f1afe8bee8f578e9139277a77f5cd Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Fri, 11 Nov 2022 19:55:34 +0800
Subject: [PATCH 09/13] fix: review issues

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 core/runtime/binaryen/module/module_impl.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/runtime/binaryen/module/module_impl.hpp b/core/runtime/binaryen/module/module_impl.hpp
index 92634cc395..42177152ed 100644
--- a/core/runtime/binaryen/module/module_impl.hpp
+++ b/core/runtime/binaryen/module/module_impl.hpp
@@ -36,7 +36,7 @@ namespace kagome::runtime::binaryen {
     enum class Error { EMPTY_STATE_CODE = 1, INVALID_STATE_CODE };
 
     ModuleImpl(ModuleImpl &&) = default;
-    ModuleImpl &operator=(ModuleImpl &&) = default;
+    ModuleImpl &operator=(ModuleImpl &&) = delete;
 
     ModuleImpl(const ModuleImpl &) = delete;
     ModuleImpl &operator=(const ModuleImpl &) = delete;

From 91d9de5c456d878bc61a5ccfdc8d244b596073ec Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Fri, 11 Nov 2022 21:07:27 +0800
Subject: [PATCH 10/13] fix: external project test

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 test/external-project-test/src/main.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/test/external-project-test/src/main.cpp b/test/external-project-test/src/main.cpp
index 735c84a70b..d26d69987f 100644
--- a/test/external-project-test/src/main.cpp
+++ b/test/external-project-test/src/main.cpp
@@ -193,7 +193,10 @@ int main() {
           offchain_persistent_storage,
           offchain_worker_pool);
 
+  auto cache = std::make_shared<kagome::runtime::RuntimePropertiesCacheImpl>();
+
   auto smc = std::make_shared<kagome::runtime::SingleModuleCache>();
+
   auto instance_env_factory =
       std::make_shared<const kagome::runtime::wavm::InstanceEnvironmentFactory>(
           trie_storage,
@@ -204,7 +207,8 @@ int main() {
           host_api_factory,
           header_repo,
           changes_tracker,
-          smc);
+          smc,
+          cache);
   auto module_factory =
       std::make_shared<kagome::runtime::wavm::ModuleFactoryImpl>(
           compartment,
@@ -219,7 +223,6 @@ int main() {
   auto env_factory =
       std::make_shared<kagome::runtime::RuntimeEnvironmentFactory>(
           code_provider, module_repo, header_repo);
-  auto cache = std::make_shared<kagome::runtime::RuntimePropertiesCacheImpl>();
 
   [[maybe_unused]] auto executor =
       kagome::runtime::Executor(env_factory, cache);

From 3b4fddacac9c7f8bdb7a545b6212e6763f7be0a7 Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Sat, 12 Nov 2022 01:42:06 +0800
Subject: [PATCH 11/13] fix: external project test

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 test/external-project-test/src/main.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/test/external-project-test/src/main.cpp b/test/external-project-test/src/main.cpp
index d26d69987f..6a2826c840 100644
--- a/test/external-project-test/src/main.cpp
+++ b/test/external-project-test/src/main.cpp
@@ -215,7 +215,8 @@ int main() {
           module_params,
           instance_env_factory,
           intrinsic_module,
-          std::nullopt);
+          std::nullopt,
+          hasher);
   auto runtime_instances_pool =
       std::make_shared<kagome::runtime::RuntimeInstancesPool>();
   auto module_repo = std::make_shared<kagome::runtime::ModuleRepositoryImpl>(

From 412ede918b94b1701387f36c82548dfa2083d2b0 Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Sat, 12 Nov 2022 04:38:44 +0800
Subject: [PATCH 12/13] fix: external project test

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 test/external-project-test/CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/external-project-test/CMakeLists.txt b/test/external-project-test/CMakeLists.txt
index fd11602feb..e9872bbc87 100644
--- a/test/external-project-test/CMakeLists.txt
+++ b/test/external-project-test/CMakeLists.txt
@@ -58,4 +58,5 @@ target_link_libraries(main
     kagome::offchain_worker_pool
     kagome::block_header_repository
     kagome::runtime_upgrade_tracker
+    kagome::runtime_properties_cache
     )

From 14191c1689040b860d5f319f73a0c03aa6a77292 Mon Sep 17 00:00:00 2001
From: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
Date: Sat, 12 Nov 2022 05:43:57 +0800
Subject: [PATCH 13/13] fix: review issues

Signed-off-by: Dmitriy Khaustov aka xDimon <khaustov.dm@gmail.com>
---
 core/api/service/impl/api_service_impl.cpp |   2 +-
 core/injector/application_injector.cpp     |  12 ---
 core/runtime/common/executor.hpp           | 104 ++++++++-------------
 3 files changed, 41 insertions(+), 77 deletions(-)

diff --git a/core/api/service/impl/api_service_impl.cpp b/core/api/service/impl/api_service_impl.cpp
index 47cb55bd84..6b2571986e 100644
--- a/core/api/service/impl/api_service_impl.cpp
+++ b/core/api/service/impl/api_service_impl.cpp
@@ -406,7 +406,7 @@ namespace kagome::api {
         session->subscribe(
             id, primitives::events::ChainEventType::kFinalizedRuntimeVersion);
 
-        auto version_res = core_->version();
+        auto version_res = core_->version(block_tree_->getLastFinalized().hash);
         if (version_res.has_value()) {
           const auto &version = version_res.value();
           session_context.messages = uploadMessagesListFromCache();
diff --git a/core/injector/application_injector.cpp b/core/injector/application_injector.cpp
index 3bdd86444c..8b367644f9 100644
--- a/core/injector/application_injector.cpp
+++ b/core/injector/application_injector.cpp
@@ -913,18 +913,6 @@ namespace {
                   runtime::binaryen::ModuleFactoryImpl,
                   runtime::wavm::ModuleFactoryImpl>(injector, method);
             }),
-        di::bind<runtime::Executor>.template to([](const auto &injector) {
-          static std::optional<std::shared_ptr<runtime::Executor>> initialized;
-          if (!initialized) {
-            auto env_factory = injector.template create<
-                std::shared_ptr<runtime::RuntimeEnvironmentFactory>>();
-            auto cache = injector.template create<
-                std::shared_ptr<runtime::RuntimePropertiesCache>>();
-            initialized = std::make_shared<runtime::Executor>(
-                std::move(env_factory), std::move(cache));
-          }
-          return initialized.value();
-        }),
         di::bind<runtime::RawExecutor>.template to<runtime::Executor>(),
         di::bind<runtime::TaggedTransactionQueue>.template to<runtime::TaggedTransactionQueueImpl>(),
         di::bind<runtime::ParachainHost>.template to<runtime::ParachainHostImpl>(),
diff --git a/core/runtime/common/executor.hpp b/core/runtime/common/executor.hpp
index a4a170e777..479ccd7a72 100644
--- a/core/runtime/common/executor.hpp
+++ b/core/runtime/common/executor.hpp
@@ -30,11 +30,11 @@
 
 #ifdef __has_builtin
 #if __has_builtin(__builtin_expect)
-#define unlikely(x) __builtin_expect((x), 0)
+#define likely(x) __builtin_expect((x), 1)
 #endif
 #endif
-#ifndef unlikely
-#define unlikely(x) (x)
+#ifndef likely
+#define likely(x) (x)
 #endif
 
 namespace kagome::runtime {
@@ -144,26 +144,8 @@ namespace kagome::runtime {
                                    std::string_view name,
                                    Args &&...args) {
       OUTCOME_TRY(env, env_factory_->start(block_info, storage_state)->make());
-
-      if constexpr (std::is_same_v<Result, primitives::Version>) {
-        if (unlikely(name == "Core_version")) {
-          return cache_->getVersion(env->module_instance->getCodeHash(), [&] {
-            return callInternal<Result>(
-                *env, name, std::forward<Args>(args)...);
-          });
-        }
-      }
-
-      if constexpr (std::is_same_v<Result, primitives::OpaqueMetadata>) {
-        if (unlikely(name == "Metadata_metadata")) {
-          return cache_->getMetadata(env->module_instance->getCodeHash(), [&] {
-            return callInternal<Result>(
-                *env, name, std::forward<Args>(args)...);
-          });
-        }
-      }
-
-      return callInternal<Result>(*env, name, std::forward<Args>(args)...);
+      return callMediateInternal<Result>(
+          *env, name, std::forward<Args>(args)...);
     }
 
     /**
@@ -177,26 +159,8 @@ namespace kagome::runtime {
                                    Args &&...args) {
       OUTCOME_TRY(env_template, env_factory_->start(block_hash));
       OUTCOME_TRY(env, env_template->make());
-
-      if constexpr (std::is_same_v<Result, primitives::Version>) {
-        if (unlikely(name == "Core_version")) {
-          return cache_->getVersion(env->module_instance->getCodeHash(), [&] {
-            return callInternal<Result>(
-                *env, name, std::forward<Args>(args)...);
-          });
-        }
-      }
-
-      if constexpr (std::is_same_v<Result, primitives::OpaqueMetadata>) {
-        if (unlikely(name == "Metadata_metadata")) {
-          return cache_->getMetadata(env->module_instance->getCodeHash(), [&] {
-            return callInternal<Result>(
-                *env, name, std::forward<Args>(args)...);
-          });
-        }
-      }
-
-      return callInternal<Result>(*env, name, std::forward<Args>(args)...);
+      return callMediateInternal<Result>(
+          *env, name, std::forward<Args>(args)...);
     }
 
     /**
@@ -209,26 +173,8 @@ namespace kagome::runtime {
                                           Args &&...args) {
       OUTCOME_TRY(env_template, env_factory_->start());
       OUTCOME_TRY(env, env_template->make());
-
-      if constexpr (std::is_same_v<Result, primitives::Version>) {
-        if (unlikely(name == "Core_version")) {
-          return cache_->getVersion(env->module_instance->getCodeHash(), [&] {
-            return callInternal<Result>(
-                *env, name, std::forward<Args>(args)...);
-          });
-        }
-      }
-
-      if constexpr (std::is_same_v<Result, primitives::OpaqueMetadata>) {
-        if (unlikely(name == "Metadata_metadata")) {
-          return cache_->getMetadata(env->module_instance->getCodeHash(), [&] {
-            return callInternal<Result>(
-                *env, name, std::forward<Args>(args)...);
-          });
-        }
-      }
-
-      return callInternal<Result>(*env, name, std::forward<Args>(args)...);
+      return callMediateInternal<Result>(
+          *env, name, std::forward<Args>(args)...);
     }
 
     outcome::result<common::Buffer> callAtRaw(
@@ -255,6 +201,36 @@ namespace kagome::runtime {
     }
 
    private:
+    /**
+     * Internal method for calling a Runtime API method
+     * Resets the runtime memory with the module's heap base,
+     * encodes the arguments with SCALE codec, calls the method from the
+     * provided module instance and  returns a result, decoded from SCALE.
+     * Changes, made to the Host API state, are reset after the call.
+     */
+    template <typename Result, typename... Args>
+    inline outcome::result<Result> callMediateInternal(RuntimeEnvironment &env,
+                                                       std::string_view name,
+                                                       Args &&...args) {
+      if constexpr (std::is_same_v<Result, primitives::Version>) {
+        if (likely(name == "Core_version")) {
+          return cache_->getVersion(env.module_instance->getCodeHash(), [&] {
+            return callInternal<Result>(env, name, std::forward<Args>(args)...);
+          });
+        }
+      }
+
+      if constexpr (std::is_same_v<Result, primitives::OpaqueMetadata>) {
+        if (likely(name == "Metadata_metadata")) {
+          return cache_->getMetadata(env.module_instance->getCodeHash(), [&] {
+            return callInternal<Result>(env, name, std::forward<Args>(args)...);
+          });
+        }
+      }
+
+      return callInternal<Result>(env, name, std::forward<Args>(args)...);
+    }
+
     /**
      * Internal method for calling a Runtime API method
      * Resets the runtime memory with the module's heap base,
@@ -330,6 +306,6 @@ namespace kagome::runtime {
 
 }  // namespace kagome::runtime
 
-#undef unlikely
+#undef likely
 
 #endif  // KAGOME_CORE_RUNTIME_COMMON_EXECUTOR_HPP