diff --git a/src/esperanza/settings.cpp b/src/esperanza/settings.cpp index 213574e973..a789aecf9b 100644 --- a/src/esperanza/settings.cpp +++ b/src/esperanza/settings.cpp @@ -11,15 +11,7 @@ Settings::Settings(::ArgsManager &args) : Settings(args, Settings::Default()) {} //! initializes the settings by reading them from an args manager. Settings::Settings(::ArgsManager &args, const Settings &defaultConfig) : m_proposing(args.GetBoolArg("-proposing", defaultConfig.m_proposing)), - m_validating(args.GetBoolArg("-validating", defaultConfig.m_validating)), - m_numberOfProposerThreads(static_cast(args.GetArg( - "-proposerthreads", - static_cast(defaultConfig.m_numberOfProposerThreads)))), - m_proposerSleep(std::chrono::milliseconds(args.GetArg( - "-proposersleep", - static_cast(defaultConfig.m_proposerSleep.count())))), - m_minProposeInterval(std::chrono::milliseconds(args.GetArg( - "-minproposeinterval", - static_cast(defaultConfig.m_minProposeInterval.count())))) {} + m_validating(args.GetBoolArg("-validating", defaultConfig.m_validating)) { +} } // namespace esperanza diff --git a/src/esperanza/settings.h b/src/esperanza/settings.h index f737dd4972..ed9fe0aef2 100644 --- a/src/esperanza/settings.h +++ b/src/esperanza/settings.h @@ -19,17 +19,6 @@ struct Settings { //! Whether this node should be a validator. bool m_validating = false; - //! How many threads to use for proposing. At least 1, at most number of - //! wallets. - size_t m_numberOfProposerThreads = 1; - - std::chrono::milliseconds m_proposerSleep = std::chrono::seconds(30); - - //! Minimum interval between proposing blocks - std::chrono::milliseconds m_minProposeInterval = std::chrono::seconds(4); - - std::string m_proposerThreadName = "proposer"; - Settings(::ArgsManager &args); Settings(::ArgsManager &args, const Settings &defaultConfig); diff --git a/src/injector.h b/src/injector.h index 13fafe0e8e..760aaed1ea 100644 --- a/src/injector.h +++ b/src/injector.h @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include @@ -16,10 +18,15 @@ class UnitEInjector : public Injector { + COMPONENT(CliArgs, proposer::CliArgs, proposer::CliArgs::MakeCliArgs) + COMPONENT(Network, proposer::Network, proposer::Network::MakeNetwork) COMPONENT(ChainState, proposer::ChainState, proposer::ChainState::MakeChain) + COMPONENT(MultiWallet, proposer::MultiWallet, + proposer::MultiWallet::MakeMultiWallet); + COMPONENT(TransactionPicker, proposer::TransactionPicker, proposer::TransactionPicker::MakeBlockAssemblerAdapter) @@ -29,6 +36,10 @@ class UnitEInjector : public Injector { COMPONENT(ProposerSettings, proposer::Settings, proposer::Settings::MakeSettings) + + COMPONENT(Proposer, proposer::Proposer, proposer::Proposer::MakeProposer, + proposer::Settings, proposer::MultiWallet, proposer::Network, + proposer::ChainState, proposer::BlockProposer) }; #endif // UNIT_E_INJECTOR_H diff --git a/src/proposer/cliargs.cpp b/src/proposer/cliargs.cpp new file mode 100644 index 0000000000..7023d7a774 --- /dev/null +++ b/src/proposer/cliargs.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2018 The unit-e core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +namespace proposer { + +class ArgsManagerAdapter : public CliArgs { + public: + ArgsManager &GetArgsManager() { return gArgs; } +}; + +static std::unique_ptr CliArgs::MakeCliArgs() { + return std::unique_ptr(new ArgsManagerAdapter()); +} + +} // namespace proposer diff --git a/src/proposer/cliargs.h b/src/proposer/cliargs.h new file mode 100644 index 0000000000..0dcbd78d30 --- /dev/null +++ b/src/proposer/cliargs.h @@ -0,0 +1,20 @@ +// Copyright (c) 2018 The unit-e core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef UNIT_E_PROPOSER_CLIARGS_H +#define UNIT_E_PROPOSER_CLIARGS_H + +#include + +namespace proposer { + +class CliArgs { + public: + virtual ~CliArgs() = default; + static std::unique_ptr MakeCliArgs(); +}; + +} // namespace proposer + +#endif // UNIT_E_PROPOSER_CLIARGS_H diff --git a/src/proposer/multiwallet.cpp b/src/proposer/multiwallet.cpp index f2152407da..f809f92205 100644 --- a/src/proposer/multiwallet.cpp +++ b/src/proposer/multiwallet.cpp @@ -12,7 +12,9 @@ namespace proposer { class MultiWalletAdapter : public MultiWallet { public: - const std::vector GetWallets() const override { return vpwallets; } + const std::vector &GetWallets() const override { + return vpwallets; + } }; std::unique_ptr MultiWallet::MakeMultiWallet() { diff --git a/src/proposer/multiwallet.h b/src/proposer/multiwallet.h index 724cdc64d8..5a988f0fbb 100644 --- a/src/proposer/multiwallet.h +++ b/src/proposer/multiwallet.h @@ -15,7 +15,7 @@ namespace proposer { class MultiWallet { public: - virtual const std::vector GetWallets() const = 0; + virtual const std::vector &GetWallets() const = 0; virtual ~MultiWallet() = default; diff --git a/src/proposer/proposer.cpp b/src/proposer/proposer.cpp index 950baac893..9cd2529e1a 100644 --- a/src/proposer/proposer.cpp +++ b/src/proposer/proposer.cpp @@ -50,11 +50,12 @@ void Proposer::Thread::SetStatus(const Status status, CWallet *const wallet) { } std::vector> Proposer::CreateProposerThreads( - const std::vector &wallets) { + Dependency multiWallet) { + const std::vector &wallets = multiWallet->GetWallets(); // total number of threads can not exceed number of wallets const size_t numThreads = std::min(wallets.size(), - std::max(1, m_settings.m_numberOfProposerThreads)); + std::max(1, m_settings->m_numberOfProposerThreads)); using WalletIndex = size_t; using ThreadIndex = size_t; @@ -76,7 +77,7 @@ std::vector> Proposer::CreateProposerThreads( thisThreadsWallets.push_back(wallets[entry->second]); } std::string threadName = - m_settings.m_proposerThreadName + "-" + std::to_string(threadIx); + m_settings->m_proposerThreadName + "-" + std::to_string(threadIx); threads.emplace_back(std::unique_ptr( new Proposer::Thread(threadName, *this, thisThreadsWallets))); } @@ -87,8 +88,8 @@ std::vector> Proposer::CreateProposerThreads( return threads; } -Proposer::Proposer(const esperanza::Settings &settings, - const std::vector &wallets, +Proposer::Proposer(Dependency settings, + Dependency multiWallet, Dependency networkInterface, Dependency chainInterface, Dependency blockProposer) @@ -99,7 +100,7 @@ Proposer::Proposer(const esperanza::Settings &settings, m_initSemaphore(0), m_startSemaphore(0), m_stopSemaphore(0), - m_threads(CreateProposerThreads(wallets)) {} + m_threads(CreateProposerThreads(multiWallet)) {} Proposer::~Proposer() { Stop(); } @@ -173,7 +174,7 @@ void Proposer::Run(Proposer::Thread &thread) { continue; } - int bestHeight; + uint32_t bestHeight; int64_t bestTime; { LOCK(thread.m_proposer.m_chain->GetLock()); @@ -187,7 +188,7 @@ void Proposer::Run(Proposer::Thread &thread) { for (auto *wallet : thread.m_wallets) { const int64_t gracePeriod = - seconds(thread.m_proposer.m_settings.m_minProposeInterval); + seconds(thread.m_proposer.m_settings->m_minProposeInterval); const int64_t lastTimeProposed = wallet->GetWalletExtension().m_proposerState.m_lastTimeProposed; const int64_t timeSinceLastProposal = currentTime - lastTimeProposed; @@ -221,7 +222,7 @@ void Proposer::Run(Proposer::Thread &thread) { // and induce a sleep for a different duration. The thread as a whole // only has to sleep as long as the minimum of these durations to check // the wallet which is due next in time. - auto sleepFor = thread.m_proposer.m_settings.m_proposerSleep; + auto sleepFor = thread.m_proposer.m_settings->m_proposerSleep; const auto setSleepDuration = [&sleepFor](const decltype(sleepFor) amount) { sleepFor = std::min(sleepFor, amount); @@ -231,7 +232,7 @@ void Proposer::Run(Proposer::Thread &thread) { const int64_t waitTill = walletExt.m_proposerState.m_lastTimeProposed + - seconds(thread.m_proposer.m_settings.m_minProposeInterval); + seconds(thread.m_proposer.m_settings->m_minProposeInterval); if (bestTime < waitTill) { const decltype(sleepFor) amount = std::chrono::seconds(waitTill - bestTime); @@ -298,4 +299,12 @@ void Proposer::Run(Proposer::Thread &thread) { thread.m_proposer.m_stopSemaphore.release(); } +std::unique_ptr Proposer::MakeProposer( + Dependency settings, Dependency multiWallet, + Dependency network, Dependency chainState, + Dependency blockProposer) { + return MakeUnique(settings, multiWallet, network, chainState, + blockProposer); +} + } // namespace proposer diff --git a/src/proposer/proposer.h b/src/proposer/proposer.h index ec687b3f7c..f2955f5c3f 100644 --- a/src/proposer/proposer.h +++ b/src/proposer/proposer.h @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -38,17 +40,14 @@ class Proposer { friend struct ProposerAccess; public: - Proposer( - //! [in] esperanza settings - const esperanza::Settings &, - //! [in] a reference to all wallets to propose from - const std::vector &, - //! dependency on network interface - Dependency, - //! dependency on chain interface - Dependency, - //! dependency on block proposer - Dependency); + static std::unique_ptr MakeProposer(Dependency, + Dependency, + Dependency, + Dependency, + Dependency); + + Proposer(Dependency, Dependency, Dependency, + Dependency, Dependency); ~Proposer(); @@ -105,13 +104,9 @@ class Proposer { } }; - //! reference to esperanza settings - const esperanza::Settings &m_settings; - + Dependency m_settings; Dependency m_network; - Dependency m_chain; - Dependency m_blockProposer; //! a semaphore for synchronizing initialization @@ -126,7 +121,7 @@ class Proposer { const std::vector> m_threads; std::vector> CreateProposerThreads( - const std::vector &wallets); + Dependency); static void Run(Thread &); }; diff --git a/src/proposer/proposer_settings.h b/src/proposer/proposer_settings.h index c63a03c91b..eb56707d1e 100644 --- a/src/proposer/proposer_settings.h +++ b/src/proposer/proposer_settings.h @@ -15,6 +15,17 @@ namespace proposer { struct Settings { + //! How many threads to use for proposing. At least 1, at most number of + //! wallets. + size_t m_numberOfProposerThreads = 1; + + std::chrono::milliseconds m_proposerSleep = std::chrono::seconds(30); + + //! Minimum interval between proposing blocks + std::chrono::milliseconds m_minProposeInterval = std::chrono::seconds(4); + + std::string m_proposerThreadName = "proposer"; + //! for regtest, don't stake above nStakeLimitHeight int m_stakeLimitHeight = 0; diff --git a/src/test/proposer/proposer_tests.cpp b/src/test/proposer/proposer_tests.cpp index 3e29090b9b..9edaa619c3 100644 --- a/src/test/proposer/proposer_tests.cpp +++ b/src/test/proposer/proposer_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include @@ -34,6 +35,15 @@ typedef ProposerAccess ProposerSpy; } // namespace proposer +struct WalletMock : public proposer::MultiWallet { + std::vector m_wallets; + CWallet m_wallet; + + WalletMock() { m_wallets.emplace_back(&m_wallet); } + + const std::vector &GetWallets() const { return m_wallets; } +}; + BOOST_AUTO_TEST_SUITE(proposer_tests) fakeit::Mock networkMock; @@ -45,27 +55,23 @@ Dependency chain = &chainMock.get(); Dependency blockProposer = &blockProposerMock.get(); BOOST_AUTO_TEST_CASE(start_stop) { - esperanza::Settings config; + proposer::Settings config; config.m_numberOfProposerThreads = 0; - std::vector wallets; - CWallet wallet; - wallets.emplace_back(&wallet); + WalletMock wallets; - proposer::Proposer proposer(config, wallets, network, chain, blockProposer); + proposer::Proposer proposer(&config, &wallets, network, chain, blockProposer); proposer.Start(); proposer.Stop(); } BOOST_AUTO_TEST_CASE(stop_twice) { - esperanza::Settings config; - std::vector wallets; - CWallet wallet; - wallets.emplace_back(&wallet); + proposer::Settings config; + WalletMock wallets; - proposer::Proposer proposer(config, wallets, network, chain, blockProposer); + proposer::Proposer proposer(&config, &wallets, network, chain, blockProposer); proposer.Start(); proposer.Stop(); @@ -73,50 +79,47 @@ BOOST_AUTO_TEST_CASE(stop_twice) { } BOOST_AUTO_TEST_CASE(stop_without_start) { - esperanza::Settings config; - std::vector wallets; - CWallet wallet; - wallets.emplace_back(&wallet); + proposer::Settings config; + WalletMock wallets; - proposer::Proposer proposer(config, wallets, network, chain, blockProposer); + proposer::Proposer proposer(&config, &wallets, network, chain, blockProposer); proposer.Stop(); } BOOST_AUTO_TEST_CASE(stop_twice_without_start) { - esperanza::Settings config; - std::vector wallets; - CWallet wallet; - wallets.emplace_back(&wallet); + proposer::Settings config; + WalletMock wallets; - proposer::Proposer proposer(config, wallets, network, chain, blockProposer); + proposer::Proposer proposer(&config, &wallets, network, chain, blockProposer); proposer.Stop(); proposer.Stop(); } BOOST_AUTO_TEST_CASE(wallet_distribution) { - esperanza::Settings config; + proposer::Settings config; config.m_numberOfProposerThreads = 3; - std::vector wallets; + WalletMock wallets; + wallets.m_wallets.clear(); CWallet w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11; - wallets.emplace_back(&w1); - wallets.emplace_back(&w2); - wallets.emplace_back(&w3); - wallets.emplace_back(&w4); - wallets.emplace_back(&w5); - wallets.emplace_back(&w6); - wallets.emplace_back(&w7); - wallets.emplace_back(&w8); - wallets.emplace_back(&w9); - wallets.emplace_back(&w10); - wallets.emplace_back(&w11); - - proposer::Proposer proposer(config, wallets, network, chain, blockProposer); + wallets.m_wallets.emplace_back(&w1); + wallets.m_wallets.emplace_back(&w2); + wallets.m_wallets.emplace_back(&w3); + wallets.m_wallets.emplace_back(&w4); + wallets.m_wallets.emplace_back(&w5); + wallets.m_wallets.emplace_back(&w6); + wallets.m_wallets.emplace_back(&w7); + wallets.m_wallets.emplace_back(&w8); + wallets.m_wallets.emplace_back(&w9); + wallets.m_wallets.emplace_back(&w10); + wallets.m_wallets.emplace_back(&w11); + + proposer::Proposer proposer(&config, &wallets, network, chain, blockProposer); proposer::ProposerSpy spy(proposer); BOOST_CHECK(spy.numThreads() == 3); @@ -138,37 +141,33 @@ BOOST_AUTO_TEST_CASE(wallet_distribution) { } BOOST_AUTO_TEST_CASE(single_wallet_too_many_threads_specified) { - esperanza::Settings config; + proposer::Settings config; config.m_numberOfProposerThreads = 17; - std::vector wallets; - CWallet wallet; - wallets.emplace_back(&wallet); + WalletMock wallets; - proposer::Proposer proposer(config, wallets, network, chain, blockProposer); + proposer::Proposer proposer(&config, &wallets, network, chain, blockProposer); proposer::ProposerSpy spy(proposer); BOOST_CHECK(spy.numThreads() == 1); BOOST_CHECK(spy.wallets(0).size() == 1); - BOOST_CHECK(spy.wallets(0)[0] == &wallet); + BOOST_CHECK(spy.wallets(0)[0] == &wallets.m_wallet); } BOOST_AUTO_TEST_CASE(single_wallet_too_few_threads_specified) { - esperanza::Settings config; + proposer::Settings config; config.m_numberOfProposerThreads = 0; - std::vector wallets; - CWallet wallet; - wallets.emplace_back(&wallet); + WalletMock wallets; - proposer::Proposer proposer(config, wallets, network, chain, blockProposer); + proposer::Proposer proposer(&config, &wallets, network, chain, blockProposer); proposer::ProposerSpy spy(proposer); BOOST_CHECK(spy.numThreads() == 1); BOOST_CHECK(spy.wallets(0).size() == 1); - BOOST_CHECK(spy.wallets(0)[0] == &wallet); + BOOST_CHECK(spy.wallets(0)[0] == &wallets.m_wallet); } BOOST_AUTO_TEST_SUITE_END()