Skip to content

Commit

Permalink
Synchronize wallet import and chain reindexing
Browse files Browse the repository at this point in the history
Signed-off-by: Dmitry Saveliev <dima@thirdhash.com>
  • Loading branch information
dsaveliev committed Apr 3, 2019
1 parent e082ca6 commit d6d06b6
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 11 deletions.
27 changes: 17 additions & 10 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,17 @@ void CleanupBlockRevFiles()
}
}

namespace { // Variables internal to initialization process only

int nMaxConnections;
int nUserMaxConnections;
int nFD;
ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED);
std::mutex m_import;
std::condition_variable cv_import;

} // namespace

void ThreadImport(std::vector<fs::path> vImportFiles)
{
const CChainParams& chainparams = Params();
Expand Down Expand Up @@ -738,6 +749,8 @@ void ThreadImport(std::vector<fs::path> vImportFiles)
LoadMempool();
fDumpMempoolLater = !fRequestShutdown;
}
// Notify parent thread about the finished import
cv_import.notify_all();
}

/** Sanity checks
Expand Down Expand Up @@ -901,15 +914,6 @@ void InitLogging()
LogPrintf(PACKAGE_NAME " version %s\n", version_string);
}

namespace { // Variables internal to initialization process only

int nMaxConnections;
int nUserMaxConnections;
int nFD;
ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED);

} // namespace

[[noreturn]] static void new_handler_terminate()
{
// Rather than throwing std::bad-alloc if allocation fails, terminate
Expand Down Expand Up @@ -1663,7 +1667,8 @@ bool AppInitMain()
// UNIT-E TODO: Snapshot must start working once we can trust commits
// (commits merkle root added to the header and FROM_COMMITS is dropped).
// Check #836 for details.
if (!snapshot::IsISDEnabled()) {
// In case of reindex, don't restore finalization's state, since it will be built from scratch.
if (!snapshot::IsISDEnabled() && !fReindex) {
LOCK(cs_main);
auto state_repository = GetComponent<finalization::StateRepository>();
auto state_processor = GetComponent<finalization::StateProcessor>();
Expand Down Expand Up @@ -1901,6 +1906,8 @@ bool AppInitMain()
uiInterface.InitMessage(_("Done loading"));

#ifdef ENABLE_WALLET
std::unique_lock<std::mutex> lk(m_import);
cv_import.wait(lk, [&]{return !fReindex.load();});
StartWallets(scheduler);
#endif

Expand Down
5 changes: 4 additions & 1 deletion src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4171,7 +4171,10 @@ CWallet* CWallet::CreateWalletFromFile(const esperanza::WalletExtensionDeps& dep
}
}

walletInstance->m_wallet_extension.ReadValidatorStateFromFile();
// In case of reindex, don't restore validator's state, since it will be built from scratch.
if (!fReindex) {
walletInstance->m_wallet_extension.ReadValidatorStateFromFile();
}

LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);

Expand Down
129 changes: 129 additions & 0 deletions test/functional/feature_reindex_commits.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/usr/bin/env python3
# Copyright (c) 2019 The Unit-e developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
Test running united with -reindex options and with finalization transactions
- Start a pair of nodes - validator and proposer
- Run a validator for some time
- Restart both nodes and check if finalization can continue with restarted state
"""

from test_framework.test_framework import UnitETestFramework
from test_framework.util import (
assert_equal,
connect_nodes,
connect_nodes_bi,
disconnect_nodes,
json,
sync_blocks,
wait_until,
)

MIN_DEPOSIT = 1500
EPOCH_LENGTH = 10


class FeatureReindexCommits(UnitETestFramework):

def get_extra_args(self, reindex):
finalization_params = json.dumps({
'epochLength': EPOCH_LENGTH,
'minDepositSize': MIN_DEPOSIT,
'dynastyLogoutDelay': 2,
'withdrawalEpochDelay': 2
})
proposer_args = ['-proposing=1', '-debug=all', '-whitelist=127.0.0.1',
'-esperanzaconfig=' + finalization_params]

validator_args = [
'-validating=1',
'-debug=all',
'-whitelist=127.0.0.1',
'-esperanzaconfig=' +
finalization_params]

if reindex:
proposer_args.append('-reindex')
validator_args.append('-reindex')

return [proposer_args, validator_args]

def set_test_params(self):
self.setup_clean_chain = True
self.extra_args = self.get_extra_args(False)
self.num_nodes = len(self.extra_args)

def run_test(self):
proposer = self.nodes[0]
finalizer = self.nodes[1]

self.setup_stake_coins(proposer, finalizer)
self.generate_sync(proposer)
wait_until(lambda: finalizer.getvalidatorinfo()[
'validator_status'] == 'NOT_VALIDATING', timeout=5)

self.generate_deposit()
wait_until(lambda: finalizer.getvalidatorinfo()[
'validator_status'] == 'IS_VALIDATING', timeout=5)

self.assert_votes(count=10)

self.restart_nodes(True)
wait_until(lambda: finalizer.getvalidatorinfo()[
'validator_status'] == 'IS_VALIDATING', timeout=5)

self.generate_sync(proposer, EPOCH_LENGTH)

self.restart_nodes(False)
wait_until(lambda: finalizer.getvalidatorinfo()[
'validator_status'] == 'IS_VALIDATING', timeout=5)

last_fin_epoch = finalizer.getfinalizationstate()['lastFinalizedEpoch']
self.assert_votes(count=10)
assert_equal(
last_fin_epoch + 10,
finalizer.getfinalizationstate()['lastFinalizedEpoch'])

def generate_deposit(self):
proposer = self.nodes[0]
finalizer = self.nodes[1]

deposit_tx = finalizer.deposit(
finalizer.getnewaddress(
"", "legacy"), MIN_DEPOSIT)
self.wait_for_transaction(deposit_tx)

proposer.generatetoaddress(51, proposer.getnewaddress('', 'bech32'))
assert_equal(proposer.getblockcount(), 52)

def assert_votes(self, count):
proposer = self.nodes[0]
finalizer = self.nodes[1]

disconnect_nodes(proposer, finalizer.index)
votes = self.generate_epoch(
EPOCH_LENGTH,
proposer=proposer,
finalizer=finalizer,
count=count)
assert_equal(len(votes), count)
connect_nodes(finalizer, proposer.index)
sync_blocks(self.nodes)

def restart_nodes(self, reindex):
node0 = self.nodes[0]
block_count_before = node0.getblockcount()

self.stop_nodes()
self.start_nodes(self.get_extra_args(reindex))

for i in range(self.num_nodes - 1):
connect_nodes_bi(self.nodes, i, i + 1)

wait_until(lambda: node0.getblockcount() == block_count_before)
sync_blocks(self.nodes)


if __name__ == '__main__':
FeatureReindexCommits().main()
15 changes: 15 additions & 0 deletions test/functional/test_framework/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,21 @@ def generate_sync(self, generator_node, nblocks=1):

return generated_blocks

@classmethod
def generate_epoch(self, epoch_length, proposer, finalizer, count=1):
"""
Generate count epochs and collect votes.
"""
assert(epoch_length > 1)
votes=[]
for _ in range(count):
proposer.generatetoaddress(epoch_length - 1, proposer.getnewaddress('', 'bech32'))
self.wait_for_vote_and_disconnect(finalizer, proposer)
for tx in proposer.getrawmempool():
votes.append(FromHex(CTransaction(), proposer.getrawtransaction(tx)))
proposer.generatetoaddress(1, proposer.getnewaddress('', 'bech32'))
return votes

def enable_mocktime(self):
"""Enable mocktime for the script.
Expand Down
1 change: 1 addition & 0 deletions test/functional/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
'esperanza_vote.py',
'wallet_listsinceblock.py',
'feature_minchainwork.py',
'feature_reindex_commits.py',
'p2p_unrequested_blocks.py',
'rpc_finalization.py',
'feature_logging.py',
Expand Down

0 comments on commit d6d06b6

Please sign in to comment.