Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Fix database rebuild functionality #5826

Merged
merged 3 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 4 additions & 2 deletions aleth/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,10 @@ int main(int argc, char** argv)
addClientOption("admin", po::value<string>()->value_name("<password>"),
"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<string>()->value_name("<file>"),
"Import a pre-sale key; you'll need to specify the password to this key");
Expand Down
1 change: 1 addition & 0 deletions libethcore/Exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
54 changes: 39 additions & 15 deletions libethereum/BlockChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,27 +328,31 @@ void BlockChain::rebuild(fs::path const& _path, std::function<void(unsigned, uns
{
if (!db::isDiskDatabase())
{
cwarn <<"In-memory database detected, skipping rebuild (since there's no existing database to rebuild)";
LOG(m_loggerWarn) << "In-memory database detected, skipping rebuild (since there's no "
"existing database to rebuild)";
return;
}

fs::path path = _path.empty() ? db::databasePath() : _path;
fs::path chainPath = path / fs::path(toHex(m_genesisHash.ref().cropped(0, 4)));
fs::path extrasPath = chainPath / fs::path(toString(c_databaseVersion));
auto const chainPath = path / fs::path(toHex(m_genesisHash.ref().cropped(0, 4)));
auto const extrasPath = chainPath / fs::path(toString(c_databaseVersion));
auto const extrasSubPathExtras = extrasPath / fs::path("extras");
auto const extrasSubPathOldExtras = extrasPath / fs::path("extras.old");

unsigned originalNumber = m_lastBlockNumber;
unsigned const originalNumber = m_lastBlockNumber;

///////////////////////////////
// TODO
// - KILL ALL STATE/CHAIN
// - REINSERT ALL BLOCKS
///////////////////////////////

// Keep extras DB around, but under a temp name
m_extrasDB.reset();
fs::rename(extrasPath / fs::path("extras"), extrasPath / fs::path("extras.old"));
std::unique_ptr<db::DatabaseFace> 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<db::DatabaseFace> 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));
Expand All @@ -369,13 +373,24 @@ void BlockChain::rebuild(fs::path const& _path, std::function<void(unsigned, uns
m_extrasDB->insert(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
Expand All @@ -388,23 +403,31 @@ void BlockChain::rebuild(fs::path const& _path, std::function<void(unsigned, uns

if (bi.parentHash() != lastHash)
{
cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> 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
Expand Down Expand Up @@ -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");

Expand Down
2 changes: 2 additions & 0 deletions libethereum/BlockChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down