diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e329337b85..a392c4d082f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Fixed: [#5792](https://github.com/ethereum/aleth/pull/5792) Faster and cheaper execution of RPC functions which query blockchain state (e.g. getBalance). - Fixed: [#5811](https://github.com/ethereum/aleth/pull/5811) RPC methods querying transactions (`eth_getTransactionByHash`, `eth_getBlockByNumber`) return correct `v` value. - Fixed: [#5821](https://github.com/ethereum/aleth/pull/5821) `test_setChainParams` correctly initializes custom configuration of precompiled contracts. +- Fixed: [#5826](https://github.com/ethereum/aleth/pull/5826) Fix blocking bug in database rebuild functionality - users can now rebuild their databases via Aleth's '-R' switch. ## [1.7.0] - 2019-11-14 diff --git a/aleth/main.cpp b/aleth/main.cpp index 0693bcf5009..c8b7855c44b 100644 --- a/aleth/main.cpp +++ b/aleth/main.cpp @@ -217,8 +217,10 @@ int main(int argc, char** argv) addClientOption("admin", po::value()->value_name(""), "Specify admin session key for JSON-RPC (default: auto-generated and printed at " "start-up)"); - addClientOption("kill,K", "Kill the blockchain first"); - addClientOption("rebuild,R", "Rebuild the blockchain from the existing database"); + addClientOption("kill,K", "Kill the blockchain first. This will remove all blocks and state."); + addClientOption("rebuild,R", + "Rebuild the blockchain from the existing database. This involves reimporting all blocks " + "and will probably take a while."); addClientOption("rescue", "Attempt to rescue a corrupt database\n"); addClientOption("import-presale", po::value()->value_name(""), "Import a pre-sale key; you'll need to specify the password to this key"); diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 1b4c6b45783..81eac09ed5d 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -67,6 +67,7 @@ DEV_SIMPLE_EXCEPTION(PendingTransactionAlreadyExists); DEV_SIMPLE_EXCEPTION(TransactionAlreadyInChain); DEV_SIMPLE_EXCEPTION(BlockNotFound); DEV_SIMPLE_EXCEPTION(UnknownParent); +DEV_SIMPLE_EXCEPTION(DisjointChain); DEV_SIMPLE_EXCEPTION(AddressAlreadyUsed); DEV_SIMPLE_EXCEPTION(ZeroSignatureTransaction); DEV_SIMPLE_EXCEPTION(UnknownTransactionValidationError); diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 83d59592d83..45ac2172c00 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -328,27 +328,31 @@ void BlockChain::rebuild(fs::path const& _path, std::function oldExtrasDB(db::DBFactory::create(extrasPath / fs::path("extras.old"))); - m_extrasDB = db::DBFactory::create(extrasPath / fs::path("extras")); + LOG(m_loggerDetail) << "Renaming extras path " << extrasSubPathExtras << " to " + << extrasSubPathOldExtras; + fs::rename(extrasSubPathExtras, extrasSubPathOldExtras); + std::unique_ptr oldExtrasDB(db::DBFactory::create(extrasSubPathOldExtras)); + m_extrasDB = db::DBFactory::create(extrasSubPathExtras); // Open a fresh state DB Block s = genesisBlock(State::openDB(path.string(), m_genesisHash, WithExisting::Kill)); @@ -369,13 +373,24 @@ void BlockChain::rebuild(fs::path const& _path, std::functioninsert(toSlice(m_lastBlockHash, ExtraDetails), (db::Slice)dev::ref(m_details[m_lastBlockHash].rlp())); + // Manually insert the genesis block details so that they're available during import of the + // first block. + auto const genesisDetails = BlockDetails{0, s.info().difficulty(), h256(), {}}; + m_details[m_genesisHash] = genesisDetails; + auto const genesisDetailsRlp = genesisDetails.rlp(); + m_extrasDB->insert( + toSlice(m_genesisHash, ExtraDetails), (db::Slice)dev::ref(genesisDetailsRlp)); + + LOG(m_loggerInfo) << "Rebuilding the extras and state databases by reimporting blocks 0 -> " + << originalNumber << ", this will probably take a while"; h256 lastHash = m_lastBlockHash; Timer t; for (unsigned d = 1; d <= originalNumber; ++d) { if (!(d % 1000)) { - cerr << "\n1000 blocks in " << t.elapsed() << "s = " << (1000.0 / t.elapsed()) << "b/s" << endl; + LOG(m_loggerInfo) << "\n1000 blocks in " << t.elapsed() + << "s = " << (1000.0 / t.elapsed()) << "b/s" << endl; t.restart(); } try @@ -388,23 +403,31 @@ void BlockChain::rebuild(fs::path const& _path, std::function parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); - return; + LOG(m_loggerError) + << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" + << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); + BOOST_THROW_EXCEPTION(DisjointChain()); } lastHash = bi.hash(); import(b, s.db(), 0); } catch (...) { - // Failed to import - stop here. + LOG(m_loggerError) << "Rebuild failed with error: " + << boost::current_exception_diagnostic_information(); + LOG(m_loggerError) + << "Please re-run Aleth with --kill option to delete all databases. This will " + "remove all local chain data and require you to resync from genesis."; break; } if (_progress) _progress(d, originalNumber); } - - fs::remove_all(path / fs::path("extras.old")); + LOG(m_loggerInfo) << "Rebuild complete! Reimported " << originalNumber << " blocks!"; + LOG(m_loggerDetail) << "Removing old extras database: " << extrasSubPathOldExtras; + oldExtrasDB.reset(); + fs::remove_all(extrasSubPathOldExtras); } string BlockChain::dumpDatabase() const @@ -680,7 +703,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Verify parent-critical parts verifyBlock(_block.block, m_onBad, ImportRequirements::InOrderChecks); - LOG(m_loggerDetail) << "Attempting import of " << _block.info.hash() << " ..."; + LOG(m_loggerDetail) << "Attempting import of block " << _block.info.hash() << " (#" + << _block.info.number() << ") ..."; performanceLogger.onStageFinished("preliminaryChecks"); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 48a99a95eda..b64c0e5dc5d 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -414,6 +414,8 @@ class BlockChain mutable Logger m_logger{createLogger(VerbosityDebug, "chain")}; mutable Logger m_loggerDetail{createLogger(VerbosityTrace, "chain")}; + mutable Logger m_loggerWarn{createLogger(VerbosityWarning, "chain")}; + mutable Logger m_loggerInfo{createLogger(VerbosityInfo, "chain")}; mutable Logger m_loggerError{createLogger(VerbosityError, "chain")}; friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);