// Copyright (c) 2011-2016 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "InProcTestNode.h" #include #include #include #include "CryptoNoteCore/Core.h" #include "CryptoNoteCore/CoreConfig.h" #include "CryptoNoteCore/Miner.h" #include "CryptoNoteProtocol/CryptoNoteProtocolHandler.h" #include "P2p/NetNode.h" #include "InProcessNode/InProcessNode.h" using namespace CryptoNote; #undef ERROR namespace Tests { namespace { bool parse_peer_from_string(NetworkAddress &pe, const std::string &node_addr) { return ::Common::parseIpAddressAndPort(pe.ip, pe.port, node_addr); } } InProcTestNode::InProcTestNode(const TestNodeConfiguration& cfg, const CryptoNote::Currency& currency) : m_cfg(cfg), m_currency(currency) { std::promise initPromise; std::future initFuture = initPromise.get_future(); m_thread = std::thread(std::bind(&InProcTestNode::workerThread, this, std::ref(initPromise))); auto initError = initFuture.get(); if (!initError.empty()) { m_thread.join(); throw std::runtime_error(initError); } } InProcTestNode::~InProcTestNode() { if (m_thread.joinable()) { m_thread.join(); } } void InProcTestNode::workerThread(std::promise& initPromise) { System::Dispatcher dispatcher; Logging::ConsoleLogger log; Logging::LoggerRef logger(log, "InProcTestNode"); try { core.reset(new CryptoNote::core(m_currency, NULL, log)); protocol.reset(new CryptoNote::CryptoNoteProtocolHandler(m_currency, dispatcher, *core, NULL, log)); p2pNode.reset(new CryptoNote::NodeServer(dispatcher, *protocol, log)); protocol->set_p2p_endpoint(p2pNode.get()); core->set_cryptonote_protocol(protocol.get()); CryptoNote::NetNodeConfig p2pConfig; p2pConfig.setBindIp("127.0.0.1"); p2pConfig.setBindPort(m_cfg.p2pPort); p2pConfig.setExternalPort(0); p2pConfig.setAllowLocalIp(false); p2pConfig.setHideMyPort(false); p2pConfig.setConfigFolder(m_cfg.dataDir); std::vector exclusiveNodes; for (const auto& en : m_cfg.exclusiveNodes) { NetworkAddress na; parse_peer_from_string(na, en); exclusiveNodes.push_back(na); } p2pConfig.setExclusiveNodes(exclusiveNodes); if (!p2pNode->init(p2pConfig)) { throw std::runtime_error("Failed to init p2pNode"); } CryptoNote::MinerConfig emptyMiner; CryptoNote::CoreConfig coreConfig; coreConfig.configFolder = m_cfg.dataDir; if (!core->init(coreConfig, emptyMiner, true)) { throw std::runtime_error("Core failed to initialize"); } initPromise.set_value(std::string()); } catch (std::exception& e) { logger(Logging::ERROR) << "Failed to initialize: " << e.what(); initPromise.set_value(e.what()); return; } try { p2pNode->run(); } catch (std::exception& e) { logger(Logging::ERROR) << "exception in p2p::run: " << e.what(); } core->deinit(); p2pNode->deinit(); core->set_cryptonote_protocol(NULL); protocol->set_p2p_endpoint(NULL); p2pNode.reset(); protocol.reset(); core.reset(); } bool InProcTestNode::startMining(size_t threadsCount, const std::string &address) { assert(core.get()); AccountPublicAddress addr; m_currency.parseAccountAddressString(address, addr); return core->get_miner().start(addr, threadsCount); } bool InProcTestNode::stopMining() { assert(core.get()); return core->get_miner().stop(); } bool InProcTestNode::stopDaemon() { if (!p2pNode.get()) { return false; } p2pNode->sendStopSignal(); m_thread.join(); return true; } bool InProcTestNode::getBlockTemplate(const std::string &minerAddress, CryptoNote::Block &blockTemplate, uint64_t &difficulty) { AccountPublicAddress addr; m_currency.parseAccountAddressString(minerAddress, addr); uint32_t height = 0; return core->get_block_template(blockTemplate, addr, difficulty, height, BinaryArray()); } bool InProcTestNode::submitBlock(const std::string& block) { block_verification_context bvc = boost::value_initialized(); core->handle_incoming_block_blob(Common::fromHex(block), bvc, true, true); return bvc.m_added_to_main_chain; } bool InProcTestNode::getTailBlockId(Crypto::Hash &tailBlockId) { tailBlockId = core->get_tail_id(); return true; } bool InProcTestNode::makeINode(std::unique_ptr &node) { std::unique_ptr inprocNode(new CryptoNote::InProcessNode(*core, *protocol)); std::promise p; auto future = p.get_future(); inprocNode->init([&p](std::error_code ec) { std::promise localPromise(std::move(p)); localPromise.set_value(ec); }); auto ec = future.get(); if (!ec) { node = std::move(inprocNode); return true; } return false; } uint64_t InProcTestNode::getLocalHeight() { return core->get_current_blockchain_height(); } }