diff --git a/newcoind.cfg b/newcoind.cfg index 774a32129d..ac87d7aa8d 100644 --- a/newcoind.cfg +++ b/newcoind.cfg @@ -5,31 +5,8 @@ # or Mac style end of lines. Blank lines and lines beginning with '#' are # ignored. Undefined sections are reserved. No escapes are currently defined. # -# When you launch newcoind, it will attempt to find this file. -# -# --conf=: -# You may specify the location of this file with --conf=. The config -# directory is the directory containing this file. The data directory is a -# the subdirectory named "dbs". -# -# Windows and no --conf: -# The config directory is the same directory as the newcoind program. The -# data directory is a the subdirectory named "dbs". -# -# Other OSes and no --conf: -# This file will be looked for in these places in the following order: -# ./newcoind.cfg -# $XDG_CONFIG_HOME/newcoin/newcoind.cfg -# -# If newcoind.cfg, is found in the current working directory, the directory -# will be used as the config directory. The data directory is a the -# subdirectory named "dbs". -# -# Otherwise, the data directory data is: -# $XDG_DATA_HOME/newcoin/ -# -# Note: $XDG_CONFIG_HOME defaults to $HOME/.config -# $XDG_DATA_HOME defaults to $HOME/.local/share +# When you launch newcoind, it will attempt to find this file. For details, +# refer to the manual page for --conf command line option. # # [debug_logfile] # Specifies were a debug logfile is kept. By default, no debug log is kept diff --git a/src/Application.cpp b/src/Application.cpp index 45adfccf43..00aea956aa 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -36,7 +36,7 @@ DatabaseCon::~DatabaseCon() } Application::Application() : - mUNL(mIOService), + mIOWork(mIOService), mAuxWork(mAuxService), mUNL(mIOService), mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300), mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), @@ -51,10 +51,10 @@ extern int RpcDBCount, TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount void Application::stop() { - mAuxService.stop(); mIOService.stop(); mHashedObjectStore.bulkWrite(); mValidations.flush(); + mAuxService.stop(); Log(lsINFO) << "Stopped: " << mIOService.stopped(); } diff --git a/src/Application.h b/src/Application.h index 6511d0f566..8ab7f83ed2 100644 --- a/src/Application.h +++ b/src/Application.h @@ -39,7 +39,8 @@ public: class Application { - boost::asio::io_service mIOService, mAuxService; + boost::asio::io_service mIOService, mAuxService; + boost::asio::io_service::work mIOWork, mAuxWork; Wallet mWallet; UniqueNodeList mUNL; diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 48b26bdc12..2b2af08a78 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -358,13 +358,18 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) SHAMap::pointer initialSet = initialLedger.peekTransactionMap()->snapShot(false); uint256 txSet = initialSet->getHash(); Log(lsINFO) << "initial position " << txSet; + mapComplete(txSet, initialSet, false); if (mValidating) mOurPosition = boost::make_shared (mValSeed, initialLedger.getParentHash(), txSet, mCloseTime); else mOurPosition = boost::make_shared(initialLedger.getParentHash(), txSet, mCloseTime); - mapComplete(txSet, initialSet, false); + + BOOST_FOREACH(u256_lct_pair& it, mDisputes) + { + it.second->setOurVote(initialLedger.hasTransaction(it.first)); + } // if any peers have taken a contrary position, process disputes boost::unordered_set found; @@ -372,7 +377,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) { uint256 set = it.second->getCurrentHash(); if (found.insert(set).second) - { // OPTIMIZEME: Don't process the same set more than once + { boost::unordered_map::iterator iit = mAcquired.find(set); if (iit != mAcquired.end()) createDisputes(initialSet, iit->second); @@ -827,6 +832,16 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec if (cit != mAcquired.end() && cit->second) txn->setVote(pit.first, cit->second->hasItem(txID)); } + + if (!ourVote && theApp->isNew(txID)) + { + newcoin::TMTransaction msg; + msg.set_rawtransaction(&(tx.front()), tx.size()); + msg.set_status(newcoin::tsNEW); + msg.set_receivetimestamp(theApp->getOPs().getNetworkTimeNC()); + PackedMessage::pointer packet = boost::make_shared(msg, newcoin::mtTRANSACTION); + theApp->getConnectionPool().relayMessage(NULL, packet); + } } bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 3833c300b3..44b4db409f 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -62,6 +62,7 @@ public: const uint256& getTransactionID() const { return mTransactionID; } bool getOurVote() const { return mOurVote; } Serializer& peekTransaction() { return transaction; } + void setOurVote(bool o) { mOurVote = o; } void setVote(const uint160& peer, bool votesYes); void unVote(const uint160& peer); diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index bb1daa098b..cdafc0698f 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -47,16 +47,13 @@ static uint8_t SNTPQueryData[48] = SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTimer(service), mResolver(service), mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256) { - if (!theConfig.RUN_STANDALONE) - { - mSocket.open(boost::asio::ip::udp::v4()); - mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint, - boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + mSocket.open(boost::asio::ip::udp::v4()); + mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint, + boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); - mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY)); - mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); - } + mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY)); + mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); } void SNTPClient::resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator it) diff --git a/src/main.cpp b/src/main.cpp index 444231ba3a..b9154261d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -96,7 +96,7 @@ int main(int argc, char* argv[]) ("standalone,a", "Run with no peers.") ("test,t", "Perform unit tests.") ("parameters", po::value< vector >(), "Specify comma separated parameters.") - ("verbose,v", "Increase log level") + ("verbose,v", "Increase log level.") ; // Interpret positional arguments as --parameters. diff --git a/test/config.js b/test/config.js new file mode 100644 index 0000000000..6b320f248f --- /dev/null +++ b/test/config.js @@ -0,0 +1,23 @@ +// +// Configuration for unit tests +// + +var path = require("path"); + +// Where to find the binary. +exports.newcoind = path.join(process.cwd(), "newcoind"); + +// Configuration for servers. +exports.servers = { + alpha : { + // "peer_ip" : "0.0.0.0", + // "peer_port" : 51235, + "rpc_ip" : "0.0.0.0", + "rpc_port" : 5005, + "websocket_ip" : "127.0.0.1", + "websocket_port" : 6005, + "validation_seed" : "shhDFVsmS2GSu5vUyZSPXYfj1r79h", + "validators" : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta" + } +}; +// vim:ts=4 diff --git a/test/server.js b/test/server.js index 404df4060c..0be028cc59 100644 --- a/test/server.js +++ b/test/server.js @@ -5,22 +5,22 @@ // Servers are created in tmp/server/$server // -console.log("server.js>"); - var config = require("./config.js"); var utils = require("./utils.js"); var fs = require("fs"); var path = require("path"); var util = require("util"); -// var child = require("child"); +var child = require("child_process"); + +var servers = {}; var serverPath = function(name) { return "tmp/server/" + name; }; // Return a server's newcoind.cfg as string. -var serverConfig = function(name) { +var configContent = function(name) { var cfg = config.servers[name]; return Object.keys(cfg).map(function (o) { @@ -28,17 +28,47 @@ var serverConfig = function(name) { }).join(""); }; +var configPath = function(name) { + return path.join(serverPath(name), "newcoind.cfg"); +}; + +// Write a server's newcoind.cfg. var writeConfig = function(name, done) { - fs.writeFile(path.join(serverPath(name), "newcoind.cfg"), serverConfig(name), 'utf8', done); + fs.writeFile(configPath(name), configContent(name), 'utf8', done); +}; + +var serverSpawnSync = function(name) { + // Spawn in standalone mode for now. + var server = child.spawn( + config.newcoind, + [ + "-a", + "--conf=newcoind.cfg" + ], + { + cwd: serverPath(name), + env: process.env, + stdio: 'inherit' + }); + + servers[name] = server; + console.log("server: %s: %s -a --conf=%s", server.pid, config.newcoind, configPath(name)); + console.log("sever: start: servers = %s", Object.keys(servers).toString()); + + server.on('exit', function (code, signal) { + // If could not exec: code=127, signal=null + // If regular exit: code=0, signal=null + console.log("sever: spawn: server exited code=%s: signal=%s", code, signal); + delete servers[name]; + }); + }; var makeBase = function(name, done) { var path = serverPath(name); - console.log("start> %s: %s", name, path); - // Reset the server directory, build it if needed. - utils.resetPath(path, parseInt('0777', 8), function (e) { + utils.resetPath(path, '0777', function (e) { if (e) { throw e; } @@ -46,15 +76,38 @@ var makeBase = function(name, done) { writeConfig(name, done); } }); - - console.log("start< %s", name); }; -var start = function(name, done) { - makeBase(name, done); +// Prepare the working directory and spawn the server. +exports.start = function(name, done) { + makeBase(name, function (e) { + if (e) { + throw e; + } + else { + serverSpawnSync(name); + done(); + } + }); }; -exports.start = start; +exports.stop = function(name, done) { + console.log("sever: stop: servers = %s", Object.keys(servers).toString()); + var server = servers[name]; + + if (server) { + server.on('exit', function (code, signal) { + console.log("sever: stop: server exited"); + delete servers[name]; + done(); + }); + server.kill(); + } + else + { + console.log("sever: stop: no such server"); + done(); + } +}; -console.log("server.js<"); // vim:ts=4 diff --git a/test/standalone-test.js b/test/standalone-test.js index 81221d7d19..a3a7a561a2 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -6,10 +6,14 @@ var buster = require("buster"); var server = require("./server.js"); buster.testCase("Check standalone server startup", { - "Start": function (done) { - server.start("alpha", function(e) { + "server start and stop": function (done) { + server.start("alpha", + function (e) { buster.refute(e); - done(); + server.stop("alpha", function (e) { + buster.refute(e); + done(); + }); }); } }); diff --git a/test/utils.js b/test/utils.js index c840431213..0bf10b18ea 100644 --- a/test/utils.js +++ b/test/utils.js @@ -37,9 +37,9 @@ var mapOr = function(func, array, done) { // Make a directory and sub-directories. var mkPath = function(dirPath, mode, done) { - fs.mkdir(dirPath, mode, function (e) { - if (e && e.code === "EEXIST") { - // Already exists, done. + fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function (e) { + if (!e || e.code === "EEXIST") { + // Created or already exists, done. done(); } else if (e.code === "ENOENT") { @@ -74,7 +74,7 @@ var emptyPath = function(dirPath, done) { // Remove path recursively. var rmPath = function(dirPath, done) { - console.log("rmPath: %s", dirPath); +// console.log("rmPath: %s", dirPath); fs.lstat(dirPath, function (err, stats) { if (err && err.code == "ENOENT") {