1 #include <boost/throw_exception.hpp> 7 #if defined(BACKWARD_HAS_BACKTRACE) 8 #include <backward.hpp> 14 #include <boost/algorithm/string/predicate.hpp> 15 #include <boost/di.hpp> 16 #include <soralog/impl/configurator_from_yaml.hpp> 37 namespace di = boost::di;
40 using namespace storage::trie;
43 using sptr = std::shared_ptr<T>;
53 if (not res.has_value()) {
55 throw std::runtime_error(
"No value");
60 return std::forward<T>(res);
64 std::string embedded_config(R
"( 78 - name: kagome-db-editor 101 kagome-db-editor <db-path> <root-state> <command> 103 <db-path> full or relative path to kagome database. It is usually path 104 polkadot/db inside base path set in kagome options. 105 <root-state> root state hash in 0x prefixed hex format. [Optional] 107 dump: dumps the state from the DB to file hex_full_state.yaml in 108 format ready for use in polkadot-test. 109 compact: compacts the kagome DB. Leaves only keys of the state passed 110 as an arguments. Removes all other keys. [Default] 113 kagome-db-editor base-path/polkadot/db 0x1e22e dump 114 kagome-db-editor base-path/polkadot/db 120 const std::unique_ptr<TrieStorageImpl> &trie,
const RootHash &hash) {
122 auto cursor = batch->trieCursor();
123 auto res =
check(cursor->next());
127 TicToc t1(
"Process state.", log);
128 while (cursor->key().has_value()) {
130 res =
check(cursor->next());
133 log->trace(
"{} keys were processed at the state.", ++count);
134 return std::move(batch);
138 const std::unique_ptr<PersistentTrieBatch> &batch,
139 std::set<RootHash> &hashes) {
144 auto res = cursor->seekUpperBound(child_prefix);
145 if (res.has_value()) {
146 auto key = cursor->key();
147 while (key.has_value() && boost::starts_with(key.value(), child_prefix)) {
148 if (
auto value_res = batch->
tryGet(key.value());
149 value_res.has_value() && value_res.value().has_value()) {
150 auto &value_opt = value_res.value();
151 log->trace(
"Found child root hash {}", value_opt.value().get().toHex());
153 common::Hash256::fromSpan(value_opt.value().get()).value());
155 res = cursor->next();
162 return std::strlen(s) == common::Hash256::size() * 2 + 2
163 && std::equal(s, s + 2,
"0x");
166 int main(
int argc,
char *argv[]) {
167 #if defined(BACKWARD_HAS_BACKTRACE) 168 backward::SignalHandling sh;
172 if (argc == 2 or (argc == 3 &&
is_hash(argv[2]))
173 or (argc == 4 and std::strcmp(argv[
MODE],
"compact") == 0)) {
175 }
else if (argc == 4 and std::strcmp(argv[MODE],
"dump") == 0) {
181 std::optional<RootHash> target_state_param;
184 std::cout <<
"ERROR: Invalid state hash\n";
188 target_state_param = RootHash::fromHexWithPrefix(argv[2]).value();
191 auto logging_system = std::make_shared<soralog::LoggingSystem>(
192 std::make_shared<Configurator>());
193 std::ignore = logging_system->configure();
199 bool need_additional_compaction =
false;
201 auto factory = std::make_shared<PolkadotTrieFactoryImpl>();
203 std::shared_ptr<storage::RocksDB> storage;
206 storage::RocksDB::create(argv[
DB_PATH], rocksdb::Options()).value();
207 }
catch (std::system_error &e) {
208 log->error(
"{}", e.what());
213 auto injector = di::make_injector(
214 di::bind<TrieSerializer>.
template to([](
const auto &injector) {
215 return std::make_shared<TrieSerializerImpl>(
216 injector.template create<sptr<PolkadotTrieFactory>>(),
220 di::bind<TrieStorageBackend>.
template to(
221 [&storage, &prefix](
const auto &) {
223 std::make_shared<TrieStorageBackendImpl>(storage, prefix);
226 di::bind<storage::changes_trie::ChangesTracker>.
template to<storage::changes_trie::StorageChangesTrackerImpl>(),
227 di::bind<Codec>.template to<PolkadotCodec>(),
228 di::bind<PolkadotTrieFactory>.to(factory),
229 di::bind<crypto::Hasher>.template to<crypto::HasherImpl>(),
230 di::bind<blockchain::BlockHeaderRepository>.
template to<blockchain::BlockHeaderRepositoryImpl>(),
231 di::bind<network::ExtrinsicObserver>.template to<network::ExtrinsicObserverImpl>());
233 auto hasher = injector.template create<sptr<crypto::Hasher>>();
236 check(blockchain::BlockStorageImpl::create({}, storage, hasher))
239 auto block_tree_leaf_hashes =
240 check(block_storage->getBlockTreeLeaves()).value();
242 BOOST_ASSERT_MSG(not block_tree_leaf_hashes.empty(),
243 "Must be known or calculated at least one leaf");
246 std::set<primitives::BlockInfo> leafs;
248 std::numeric_limits<primitives::BlockNumber>::max(), {});
250 std::numeric_limits<primitives::BlockNumber>::min(), {});
251 for (
auto hash : block_tree_leaf_hashes) {
252 auto number =
check(
check(block_storage->getBlockHeader(hash)).value())
255 const auto &leaf = *leafs.emplace(number, hash).first;
256 SL_TRACE(log,
"Leaf {} found", leaf);
257 if (leaf.number <= least_leaf.number) {
260 if (leaf.number >= best_leaf.number) {
270 std::set<primitives::BlockInfo> to_remove;
274 auto it = leafs.rbegin();
275 auto node = leafs.extract((++it).base());
276 auto &block = node.value();
279 check(
check(block_storage->getBlockHeader(block.hash)).value())
281 if (header.number == 0) {
282 last_finalized_block = block;
283 last_finalized_block_header = header;
284 last_finalized_block_state_root = header.state_root;
288 auto justifications =
289 check(block_storage->getJustification(block.hash)).value();
290 if (justifications.has_value()) {
291 last_finalized_block = block;
292 last_finalized_block_header = header;
293 last_finalized_block_state_root = header.state_root;
297 after_finalized_block_state_root = header.state_root;
299 leafs.emplace(header.number - 1, header.parent_hash);
300 to_remove.insert(std::move(node));
303 target_state_param.value_or(last_finalized_block_state_root);
305 log->trace(
"Autodetected finalized block is {}, state root is {:l}",
306 last_finalized_block,
307 last_finalized_block_state_root);
309 for (
auto it = to_remove.rbegin(); it != to_remove.rend(); ++it) {
310 check(block_storage->removeBlock(*it)).value();
313 SL_TRACE(log,
"Save {} as single leaf", last_finalized_block);
314 check(block_storage->setBlockTreeLeaves({last_finalized_block.hash}))
320 std::vector<runtime::RuntimeUpgradeTrackerImpl::RuntimeUpgradeData>
321 runtime_upgrade_data{};
322 runtime_upgrade_data.emplace_back(last_finalized_block,
324 auto encoded_res =
check(scale::encode(runtime_upgrade_data));
331 TrieStorageImpl::createFromStorage(
340 auto finalized_batch =
343 std::vector<std::unique_ptr<PersistentTrieBatch>> child_batches;
345 std::set<RootHash> child_root_hashes;
348 for (
const auto &child_root_hash : child_root_hashes) {
350 if (child_batch_res.has_value()) {
351 child_batches.emplace_back(std::move(child_batch_res.value()));
353 log->error(
"Child batch 0x{} not found in the storage",
354 child_root_hash.toHex());
359 auto db_cursor = storage->cursor();
360 auto db_batch = storage->batch();
361 auto res =
check(db_cursor->seek(prefix));
364 TicToc t2(
"Process DB.", log);
365 while (db_cursor->isValid() && db_cursor->key().has_value()
366 && boost::starts_with(db_cursor->key().value(), prefix)) {
367 auto res2 =
check(db_batch->remove(db_cursor->key().value()));
369 if (not(count % 10000000)) {
370 log->trace(
"{} keys were processed at the db.", count);
371 res2 =
check(db_batch->commit());
373 ->compact(prefix,
check(db_cursor->key()).value());
374 db_cursor = storage->
cursor();
375 db_batch = storage->batch();
376 res =
check(db_cursor->seek(prefix));
378 res2 =
check(db_cursor->next());
380 std::ignore =
check(db_batch->commit());
382 log->trace(
"{} keys were processed at the db.", ++count);
385 TicToc t3(
"Commit state.", log);
386 check(finalized_batch->commit()).value();
387 check(batch->commit()).value();
388 for (
const auto &child_batch : child_batches) {
389 check(child_batch->commit()).value();
394 TicToc t4(
"Compaction 1.", log);
399 need_additional_compaction =
true;
400 }
else if (
DUMP == cmd) {
402 check(trie->getEphemeralBatchAt(last_finalized_block.
hash)).value();
403 auto cursor = batch->trieCursor();
404 auto res =
check(cursor->next());
406 TicToc t1(
"Dump full state.", log);
409 ofs.open(
"hex_full_state.yaml");
411 while (cursor->key().has_value()) {
412 ofs <<
" - " << cursor->key().value().toHex() <<
"\n";
413 if (not(++count % 10000)) {
414 log->trace(
"{} keys were dumped.", count);
416 res = cursor->next();
419 cursor = batch->trieCursor();
420 res =
check(cursor->next());
423 while (cursor->key().has_value()) {
425 <<
check(batch->get(
check(cursor->key()).value())).value().get()
427 if (not(++count % 50000)) {
428 log->trace(
"{} values were dumped.", count);
430 res =
check(cursor->next());
437 if (need_additional_compaction) {
438 TicToc t5(
"Compaction 2.", log);
440 check(storage::RocksDB::create(argv[1], rocksdb::Options())).value();
Class represents arbitrary (including empty) byte buffer.
void raise(T t)
throws outcome::result error as boost exception
outcome::result< std::unique_ptr< PersistentTrieBatch > > persistent_batch(const std::unique_ptr< TrieStorageImpl > &trie, const RootHash &hash)
std::shared_ptr< T > sptr
void child_storage_root_hashes(const std::unique_ptr< PersistentTrieBatch > &batch, std::set< RootHash > &hashes)
std::unique_ptr< Cursor > cursor() override
Returns new key-value iterator.
const common::Buffer kChildStorageDefaultPrefix
void setLoggingSystem(std::shared_ptr< soralog::LoggingSystem > logging_system)
virtual std::unique_ptr< PolkadotTrieCursor > trieCursor()=0
outcome::result< std::unique_ptr< PersistentTrieBatch > > getPersistentBatchAt(const RootHash &root) override
auto is_hash(const char *s)
int main(int argc, char *argv[])
virtual outcome::result< std::optional< ConstValueView > > tryGet(const Key &key) const =0
Get value by key.
Logger createLogger(const std::string &tag)
const common::Buffer kRuntimeHashesLookupKey