From 7744f7c11111956860ddc331d952c93134dbd338 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 16 Sep 2012 20:58:38 -0700 Subject: [PATCH 01/45] Cleanups and improved comments. Fix a race condition if a peer ledger comes in before we take our initial position. --- src/LedgerConsensus.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index aff9f7bdaf..48b26bdc12 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -359,6 +359,13 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) uint256 txSet = initialSet->getHash(); Log(lsINFO) << "initial position " << txSet; + if (mValidating) + mOurPosition = boost::make_shared + (mValSeed, initialLedger.getParentHash(), txSet, mCloseTime); + else + mOurPosition = boost::make_shared(initialLedger.getParentHash(), txSet, mCloseTime); + mapComplete(txSet, initialSet, false); + // if any peers have taken a contrary position, process disputes boost::unordered_set found; BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) @@ -372,12 +379,6 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) } } - if (mValidating) - mOurPosition = boost::make_shared - (mValSeed, initialLedger.getParentHash(), txSet, mCloseTime); - else - mOurPosition = boost::make_shared(initialLedger.getParentHash(), txSet, mCloseTime); - mapComplete(txSet, initialSet, false); if (mProposing) propose(); } @@ -389,16 +390,17 @@ void LedgerConsensus::createDisputes(SHAMap::ref m1, SHAMap::ref m2) for (SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos) { // create disputed transactions (from the ledger that has them) if (pos->second.first) - { + { // transaction is in first map assert(!pos->second.second); addDisputedTransaction(pos->first, pos->second.first->peekData()); } else if (pos->second.second) - { + { // transaction is in second map assert(!pos->second.first); addDisputedTransaction(pos->first, pos->second.second->peekData()); } - else assert(false); + else // No other disagreement over a transaction should be possible + assert(false); } } @@ -417,7 +419,10 @@ void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::ref map, bool acq assert(hash == map->getHash()); if (mAcquired.find(hash) != mAcquired.end()) + { + mAcquiring.erase(hash); return; // we already have this map + } if (mOurPosition && (!mOurPosition->isBowOut()) && (hash != mOurPosition->getCurrentHash())) { // this could create disputed transactions @@ -799,19 +804,20 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec { Log(lsTRACE) << "Transaction " << txID << " is disputed"; boost::unordered_map::iterator it = mDisputes.find(txID); - if (it != mDisputes.end()) return; + if (it != mDisputes.end()) + return; - bool ourPosition = false; + bool ourVote = false; if (mOurPosition) { boost::unordered_map::iterator mit = mAcquired.find(mOurPosition->getCurrentHash()); if (mit != mAcquired.end()) - ourPosition = mit->second->hasItem(txID); + ourVote = mit->second->hasItem(txID); else assert(false); // We don't have our own position? } - LCTransaction::pointer txn = boost::make_shared(txID, tx, ourPosition); + LCTransaction::pointer txn = boost::make_shared(txID, tx, ourVote); mDisputes[txID] = txn; BOOST_FOREACH(u160_prop_pair& pit, mPeerPositions) From 89518e23cc8cfd00c8fbfd140f5f4cec7d420148 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 17 Sep 2012 00:38:47 -0700 Subject: [PATCH 02/45] Fix two more race conditions involving us taking our position late. Remove an incorrect comment. --- src/LedgerConsensus.cpp | 9 +++++++-- src/LedgerConsensus.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 48b26bdc12..0745329de7 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); 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); From 92fbff0efc05fcf0fd466be005c188a3a22ec307 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 17 Sep 2012 00:54:48 -0700 Subject: [PATCH 03/45] If a new transaction is discovered in the consensus process and we have not relayed it recently, do so. This is not the perfect solution, it would be better to relay it when we accept the new ledger, relaying only if it fits in the consensus ledger. --- src/LedgerConsensus.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 0745329de7..2b2af08a78 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -832,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) From d28bb9f771416c3f6c4507028907a937a85cfc9c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 18 Sep 2012 12:23:14 -0700 Subject: [PATCH 04/45] Ugly workaround for Boost I/O service weirdness. I/O service unconditionally terminates if it has no work to do and cannot be used to wait around for 'post' calls. --- src/Application.cpp | 11 ++++++++++- src/Application.h | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 45adfccf43..c78427d7b2 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -35,8 +35,14 @@ DatabaseCon::~DatabaseCon() delete mDatabase; } +static void resetTimer(boost::asio::deadline_timer* timer) +{ // ugly workaround for Boost IO service weirdness + timer->expires_from_now(boost::posix_time::hours(24)); + timer->async_wait(boost::bind(resetTimer, timer)); +} + Application::Application() : - mUNL(mIOService), + mIOTimer(mIOService), mAuxTimer(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), @@ -44,6 +50,9 @@ Application::Application() : { RAND_bytes(mNonce256.begin(), mNonce256.size()); RAND_bytes(reinterpret_cast(&mNonceST), sizeof(mNonceST)); + + resetTimer(&mIOTimer); + resetTimer(&mAuxTimer); } extern const char *RpcDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[], *NetNodeDBInit[]; diff --git a/src/Application.h b/src/Application.h index 6511d0f566..78fc2e425c 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::deadline_timer mIOTimer, mAuxTimer; Wallet mWallet; UniqueNodeList mUNL; From 77c06a1ca0864a1543b21976a9964a3c55363401 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 18 Sep 2012 12:24:09 -0700 Subject: [PATCH 05/45] Allow SNTP in standalone mode. It was partially disabled before. --- src/SNTPClient.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) 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) From 73c5b6addbbca2faa2e1791ce1d9d3f85ec790a9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 18 Sep 2012 13:21:07 -0700 Subject: [PATCH 06/45] There's a proper way to workaround the silliness, io_service::work --- src/Application.cpp | 13 ++----------- src/Application.h | 4 ++-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index c78427d7b2..00aea956aa 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -35,14 +35,8 @@ DatabaseCon::~DatabaseCon() delete mDatabase; } -static void resetTimer(boost::asio::deadline_timer* timer) -{ // ugly workaround for Boost IO service weirdness - timer->expires_from_now(boost::posix_time::hours(24)); - timer->async_wait(boost::bind(resetTimer, timer)); -} - Application::Application() : - mIOTimer(mIOService), mAuxTimer(mAuxService), 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), @@ -50,9 +44,6 @@ Application::Application() : { RAND_bytes(mNonce256.begin(), mNonce256.size()); RAND_bytes(reinterpret_cast(&mNonceST), sizeof(mNonceST)); - - resetTimer(&mIOTimer); - resetTimer(&mAuxTimer); } extern const char *RpcDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[], *NetNodeDBInit[]; @@ -60,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 78fc2e425c..8ab7f83ed2 100644 --- a/src/Application.h +++ b/src/Application.h @@ -39,8 +39,8 @@ public: class Application { - boost::asio::io_service mIOService, mAuxService; - boost::asio::deadline_timer mIOTimer, mAuxTimer; + boost::asio::io_service mIOService, mAuxService; + boost::asio::io_service::work mIOWork, mAuxWork; Wallet mWallet; UniqueNodeList mUNL; From 8c354f46b784c69b3940bf74542d8793a1402fe6 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 19 Sep 2012 23:41:06 -0700 Subject: [PATCH 07/45] Fix the bug Jed reported. --- src/Ledger.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 2348ef63ec..b419a493fc 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -505,7 +505,6 @@ void Ledger::addJson(Json::Value& ret, int options) { SerializerIterator sit(item->peekSerializer()); Serializer sTxn(sit.getVL()); - Serializer sMeta(sit.getVL()); SerializerIterator tsit(sTxn); SerializedTransaction txn(tsit); From 02b3bcb089c57dbda8616028c83453490f06c718 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 20 Sep 2012 00:15:48 -0700 Subject: [PATCH 08/45] Put the threading in the correct owner node for unthreaded nodes. Add some additional debug to threading. --- src/LedgerEntrySet.cpp | 37 ++++++++++++++++++++++--------------- src/LedgerEntrySet.h | 8 +++----- src/SerializedLedger.cpp | 2 ++ src/TransactionMeta.cpp | 6 +++++- src/TransactionMeta.h | 3 ++- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 4dbef407b1..5408a4dca8 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -291,7 +291,7 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger, } -bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger, +bool LedgerEntrySet::threadTx(const NewcoinAddress& threadTo, Ledger::ref ledger, boost::unordered_map& newMods) { Log(lsTRACE) << "Thread to " << threadTo.getAccountID(); @@ -301,32 +301,36 @@ bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddres assert(false); return false; } - return threadTx(metaNode, sle, ledger, newMods); + return threadTx(sle, ledger, newMods); } -bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::ref threadTo, Ledger::ref ledger, - boost::unordered_map& newMods) +bool LedgerEntrySet::threadTx(SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map& newMods) { // node = the node that was modified/deleted/created // threadTo = the node that needs to know uint256 prevTxID; uint32 prevLgrID; if (!threadTo->thread(mSet.getTxID(), mSet.getLgrSeq(), prevTxID, prevLgrID)) return false; - if (metaNode.thread(prevTxID, prevLgrID)) + if (mSet.getAffectedNode(threadTo->getIndex(), TMNModifiedNode, false).thread(prevTxID, prevLgrID)) return true; assert(false); return false; } -bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::ref node, Ledger::ref ledger, - boost::unordered_map& newMods) +bool LedgerEntrySet::threadOwners(SLE::ref node, Ledger::ref ledger, boost::unordered_map& newMods) { // thread new or modified node to owner or owners if (node->hasOneOwner()) // thread to owner's account - return threadTx(metaNode, node->getOwner(), ledger, newMods); - else if (node->hasTwoOwners()) // thread to owner's accounts + { + Log(lsTRACE) << "Thread to single owner"; + return threadTx(node->getOwner(), ledger, newMods); + } + else if (node->hasTwoOwners()) // thread to owner's accounts] + { + Log(lsTRACE) << "Thread to two owners"; return - threadTx(metaNode, node->getFirstOwner(), ledger, newMods) || - threadTx(metaNode, node->getSecondOwner(), ledger, newMods); + threadTx(node->getFirstOwner(), ledger, newMods) && + threadTx(node->getSecondOwner(), ledger, newMods); + } else return false; } @@ -369,12 +373,12 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) continue; SLE::pointer curNode = it->second.mEntry; - TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType); + TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType, true); if (nType == TMNDeletedNode) { assert(origNode); - threadOwners(metaNode, origNode, mLedger, newMod); + threadOwners(origNode, mLedger, newMod); if (origNode->getIFieldPresent(sfAmount)) { // node has an amount, covers ripple state nodes @@ -408,13 +412,16 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) if (nType == TMNCreatedNode) // if created, thread to owner(s) { assert(!origNode); - threadOwners(metaNode, curNode, mLedger, newMod); + threadOwners(curNode, mLedger, newMod); } if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) { if (curNode->isThreadedType()) // always thread to self - threadTx(metaNode, curNode, mLedger, newMod); + { + Log(lsTRACE) << "Thread to self"; + threadTx(curNode, mLedger, newMod); + } } if (nType == TMNModifiedNode) diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 92d96294e9..150a5ae891 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -42,14 +42,12 @@ protected: SLE::pointer getForMod(const uint256& node, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger, + bool threadTx(const NewcoinAddress& threadTo, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadTx(TransactionMetaNode& metaNode, SLE::ref threadTo, Ledger::ref ledger, - boost::unordered_map& newMods); + bool threadTx(SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadOwners(TransactionMetaNode& metaNode, SLE::ref node, Ledger::ref ledger, - boost::unordered_map& newMods); + bool threadOwners(SLE::ref node, Ledger::ref ledger, boost::unordered_map& newMods); public: diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 41c4bc7fb8..0353df8b69 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -3,6 +3,7 @@ #include #include "Ledger.h" +#include "Log.h" SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint256& index) : SerializedType("LedgerEntry"), mIndex(index) @@ -99,6 +100,7 @@ uint32 SerializedLedgerEntry::getThreadedLedger() bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID) { uint256 oldPrevTxID = getIFieldH256(sfLastTxnID); + Log(lsTRACE) << "Thread Tx:" << txID << " prev:" << oldPrevTxID; if (oldPrevTxID == txID) return false; prevTxID = oldPrevTxID; diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index d43e55e343..4c179f0b70 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -294,11 +294,15 @@ bool TransactionMetaSet::isNodeAffected(const uint256& node) const return mNodes.find(node) != mNodes.end(); } -TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type) +TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type, bool overrideType) { std::map::iterator it = mNodes.find(node); if (it != mNodes.end()) + { + if (overrideType) + it->second.setType(type); return it->second; + } return mNodes.insert(std::make_pair(node, TransactionMetaNode(node, type))).first->second; } diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index 10423aeda9..e3ac3b6cd4 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -158,6 +158,7 @@ public: TransactionMetaNode(int type, const uint256& node, SerializerIterator&); void addRaw(Serializer&); + void setType(int t) { mType = t; } Json::Value getJson(int) const; bool addAmount(int nodeType, const STAmount& amount); @@ -189,7 +190,7 @@ public: uint32 getLgrSeq() { return mLedger; } bool isNodeAffected(const uint256&) const; - TransactionMetaNode& getAffectedNode(const uint256&, int type); + TransactionMetaNode& getAffectedNode(const uint256&, int type, bool overrideType); const TransactionMetaNode& peekAffectedNode(const uint256&) const; Json::Value getJson(int) const; From 169f0f487a47627ae1928bd12863a27bdee1c2ef Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 21 Sep 2012 14:37:16 -0700 Subject: [PATCH 09/45] UT: Rework server module to provide an object. --- {test => js}/utils.js | 23 +++++--- test/server.js | 122 ++++++++++++++++++++++++++-------------- test/standalone-test.js | 7 +-- 3 files changed, 98 insertions(+), 54 deletions(-) rename {test => js}/utils.js (83%) diff --git a/test/utils.js b/js/utils.js similarity index 83% rename from test/utils.js rename to js/utils.js index 0bf10b18ea..6bb4ae7a2d 100644 --- a/test/utils.js +++ b/js/utils.js @@ -1,15 +1,22 @@ +// YYY Should probably have two versions: node vs browser var fs = require("fs"); var path = require("path"); +Function.prototype.method = function(name,func) { + this.prototype[name] = func; + + return this; +}; + var filterErr = function(code, done) { - return function (e) { + return function(e) { done(e.code !== code ? e : undefined); }; }; var throwErr = function(done) { - return function (e) { + return function(e) { if (e) throw e; @@ -20,7 +27,7 @@ var throwErr = function(done) { // apply function to elements of array. Return first true value to done or undefined. var mapOr = function(func, array, done) { if (array.length) { - func(array[array.length-1], function (v) { + func(array[array.length-1], function(v) { if (v) { done(v); } @@ -37,7 +44,7 @@ var mapOr = function(func, array, done) { // Make a directory and sub-directories. var mkPath = function(dirPath, mode, done) { - fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function (e) { + fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function(e) { if (!e || e.code === "EEXIST") { // Created or already exists, done. done(); @@ -62,7 +69,7 @@ var mkPath = function(dirPath, mode, done) { // Empty a directory. var emptyPath = function(dirPath, done) { - fs.readdir(dirPath, function (err, files) { + fs.readdir(dirPath, function(err, files) { if (err) { done(err); } @@ -76,7 +83,7 @@ var emptyPath = function(dirPath, done) { var rmPath = function(dirPath, done) { // console.log("rmPath: %s", dirPath); - fs.lstat(dirPath, function (err, stats) { + fs.lstat(dirPath, function(err, stats) { if (err && err.code == "ENOENT") { done(); } @@ -84,7 +91,7 @@ var rmPath = function(dirPath, done) { done(err); } else if (stats.isDirectory()) { - emptyPath(dirPath, function (e) { + emptyPath(dirPath, function(e) { if (e) { done(e); } @@ -103,7 +110,7 @@ var rmPath = function(dirPath, done) { // Create directory if needed and empty if needed. var resetPath = function(dirPath, mode, done) { - mkPath(dirPath, mode, function (e) { + mkPath(dirPath, mode, function(e) { if (e) { done(e); } diff --git a/test/server.js b/test/server.js index 0be028cc59..0bd0f582c3 100644 --- a/test/server.js +++ b/test/server.js @@ -6,7 +6,7 @@ // var config = require("./config.js"); -var utils = require("./utils.js"); +var utils = require("../js/utils.js"); var fs = require("fs"); var path = require("path"); @@ -15,99 +15,137 @@ var child = require("child_process"); var servers = {}; -var serverPath = function(name) { - return "tmp/server/" + name; +// Create a server object +var Server = function(name) { + this.name = name; }; // Return a server's newcoind.cfg as string. -var configContent = function(name) { - var cfg = config.servers[name]; +Server.method('configContent', function() { + var cfg = config.servers[this.name]; - return Object.keys(cfg).map(function (o) { + return Object.keys(cfg).map(function(o) { return util.format("[%s]\n%s\n", o, cfg[o]); }).join(""); -}; +}); -var configPath = function(name) { - return path.join(serverPath(name), "newcoind.cfg"); -}; +Server.method('serverPath', function() { + return "tmp/server/" + this.name; +}); + +Server.method('configPath', function() { + return path.join(this.serverPath(), "newcoind.cfg"); +}); // Write a server's newcoind.cfg. -var writeConfig = function(name, done) { - fs.writeFile(configPath(name), configContent(name), 'utf8', done); -}; +Server.method('writeConfig', function(done) { + fs.writeFile(this.configPath(), this.configContent(), 'utf8', done); +}); -var serverSpawnSync = function(name) { +// Spawn the server. +Server.method('serverSpawnSync', function() { // Spawn in standalone mode for now. - var server = child.spawn( + this.child = child.spawn( config.newcoind, [ "-a", "--conf=newcoind.cfg" ], { - cwd: serverPath(name), + cwd: this.serverPath(), 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()); + console.log("server: start %s: %s -a --conf=%s", this.child.pid, config.newcoind, this.configPath()); - server.on('exit', function (code, signal) { + // By default, just log exits. + this.child.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]; + console.log("server: spawn: server exited code=%s: signal=%s", code, signal); }); -}; +}); -var makeBase = function(name, done) { - var path = serverPath(name); +// Prepare server's working directory. +Server.method('makeBase', function(done) { + var path = this.serverPath(); + var self = this; // Reset the server directory, build it if needed. - utils.resetPath(path, '0777', function (e) { + utils.resetPath(path, '0777', function(e) { if (e) { throw e; } else { - writeConfig(name, done); + self.writeConfig(done); } }); -}; +}); +// Create a standalone server. // Prepare the working directory and spawn the server. -exports.start = function(name, done) { - makeBase(name, function (e) { +Server.method('start', function(done) { + var self = this; + + this.makeBase(function(e) { if (e) { throw e; } else { - serverSpawnSync(name); + self.serverSpawnSync(); done(); } }); -}; +}); -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]; +// Stop a standalone server. +Server.method('stop', function(done) { + if (this.child) { + // Update the on exit to invoke done. + this.child.on('exit', function(code, signal) { + console.log("server: stop: server exited"); done(); }); - server.kill(); + this.child.kill(); } else { - console.log("sever: stop: no such server"); + console.log("server: stop: no such server"); done(); } +}); + +// Start the named server. +exports.start = function(name, done) { + if (servers[name]) + { + console.log("server: start: server already started."); + } + else + { + var server = new Server(name); + + servers[name] = server; + + console.log("server: start: %s", JSON.stringify(server)); + + server.start(done); + } }; +// Delete the named server. +exports.stop = function(name, done) { + console.log("server: stop: %s of %s", name, Object.keys(servers).toString()); + + var server = servers[name]; + if (server) { + server.stop(done); + delete servers[name]; + } +}; + +exports.Server = Server; + // vim:ts=4 diff --git a/test/standalone-test.js b/test/standalone-test.js index a3a7a561a2..d707baeca3 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -6,11 +6,11 @@ var buster = require("buster"); var server = require("./server.js"); buster.testCase("Check standalone server startup", { - "server start and stop": function (done) { + "server start and stop": function(done) { server.start("alpha", - function (e) { + function(e) { buster.refute(e); - server.stop("alpha", function (e) { + server.stop("alpha", function(e) { buster.refute(e); done(); }); @@ -18,5 +18,4 @@ buster.testCase("Check standalone server startup", { } }); -// console.log("standalone-test.js<"); // vim:ts=4 From a4070de73eddb1c54414b5e1d38d4b828b7bb7c1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 13:04:24 -0700 Subject: [PATCH 10/45] Some work on the new binary formats that doesn't break current code. --- src/FieldNames.cpp | 98 ++++++++++++++++++++++++++++++++++++++ src/FieldNames.h | 15 ++++++ src/LedgerEntrySet.cpp | 3 ++ src/SerializedObject.h | 13 ++++- src/SerializedTypes.h | 37 +++++++------- src/Transaction.cpp | 6 +-- src/TransactionAction.cpp | 4 +- src/TransactionFormats.cpp | 6 +-- 8 files changed, 156 insertions(+), 26 deletions(-) create mode 100644 src/FieldNames.cpp create mode 100644 src/FieldNames.h diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp new file mode 100644 index 0000000000..5f1ff6130c --- /dev/null +++ b/src/FieldNames.cpp @@ -0,0 +1,98 @@ + +#include "FieldNames.h" + +#define S_FIELD(x) sf##x, #x + +FieldName FieldNames[]= +{ + + // 8-bit integers + { S_FIELD(CloseResolution), STI_UINT8, 1 }, + + // 32-bit integers (common) + { S_FIELD(Flags), STI_UINT32, 1 }, + { S_FIELD(SourceTag), STI_UINT32, 2 }, + { S_FIELD(Sequence), STI_UINT32, 3 }, + { S_FIELD(LastTxnSeq), STI_UINT32, 4 }, + { S_FIELD(LedgerSequence), STI_UINT32, 5 }, + { S_FIELD(CloseTime), STI_UINT32, 6 }, + { S_FIELD(ParentCloseTime), STI_UINT32, 7 }, + { S_FIELD(SigningTime), STI_UINT32, 8 }, + { S_FIELD(Expiration), STI_UINT32, 9 }, + { S_FIELD(TransferRate), STI_UINT32, 10 }, + { S_FIELD(PublishSize), STI_UINT32, 11 }, + + // 32-bit integers (rare) + { S_FIELD(HighQualityIn), STI_UINT32, 16 }, + { S_FIELD(HighQualityOut), STI_UINT32, 17 }, + { S_FIELD(LowQualityIn), STI_UINT32, 18 }, + { S_FIELD(LowQualityOut), STI_UINT32, 19 }, + { S_FIELD(QualityIn), STI_UINT32, 20 }, + { S_FIELD(QualityOut), STI_UINT32, 21 }, + { S_FIELD(StampEscrow), STI_UINT32, 22 }, + { S_FIELD(BondAmount), STI_UINT32, 23 }, + { S_FIELD(LoadFee), STI_UINT32, 24 }, + + // 64-bit integers + { S_FIELD(IndexNext), STI_UINT64, 1 }, + { S_FIELD(IndexPrevious), STI_UINT64, 2 }, + { S_FIELD(BookNode), STI_UINT64, 3 }, + { S_FIELD(OwnerNode), STI_UINT64, 4 }, + { S_FIELD(BaseFee), STI_UINT64, 5 }, + + // 128-bit + { S_FIELD(PublishSize), STI_HASH128, 1 }, + { S_FIELD(EmailHash), STI_HASH128, 2 }, + + // 256-bit + { S_FIELD(LedgerHash), STI_HASH256, 1 }, + { S_FIELD(ParentHash), STI_HASH256, 2 }, + { S_FIELD(TransactionHash), STI_HASH256, 3 }, + { S_FIELD(AccountHash), STI_HASH256, 4 }, + { S_FIELD(LastTxnID), STI_HASH256, 5 }, + { S_FIELD(WalletLocator), STI_HASH256, 6 }, + { S_FIELD(PublishHash), STI_HASH256, 7 }, + { S_FIELD(Nickname), STI_HASH256, 8 }, + + // currency amount + { S_FIELD(Amount), STI_AMOUNT, 1 }, + { S_FIELD(Balance), STI_AMOUNT, 2 }, + { S_FIELD(LimitAmount), STI_AMOUNT, 3 }, + { S_FIELD(TakerPays), STI_AMOUNT, 4 }, + { S_FIELD(TakerGets), STI_AMOUNT, 5 }, + { S_FIELD(LowLimit), STI_AMOUNT, 6 }, + { S_FIELD(HighLimit), STI_AMOUNT, 7 }, + { S_FIELD(MinimumOffer), STI_AMOUNT, 8 }, + + // variable length + { S_FIELD(PublicKey), STI_VL, 1 }, + { S_FIELD(MessageKey), STI_VL, 2 }, + { S_FIELD(SigningKey), STI_VL, 3 }, + { S_FIELD(Signature), STI_VL, 4 }, + { S_FIELD(Generator), STI_VL, 5 }, + { S_FIELD(Domain), STI_VL, 6 }, + + // account + { S_FIELD(Account), STI_ACCOUNT, 1 }, + { S_FIELD(Owner), STI_ACCOUNT, 2 }, + { S_FIELD(Destination), STI_ACCOUNT, 3 }, + { S_FIELD(Issuer), STI_ACCOUNT, 4 }, + { S_FIELD(HighID), STI_ACCOUNT, 5 }, + { S_FIELD(LowID), STI_ACCOUNT, 6 }, + { S_FIELD(Target), STI_ACCOUNT, 7 }, + + // path set + { S_FIELD(Paths), STI_PATHSET, 1 }, + + // vector of 256-bit + { S_FIELD(Indexes), STI_VECTOR256, 1 }, + + // inner object + { S_FIELD(MiddleTransaction), STI_OBJECT, 1 }, + { S_FIELD(InnerTransaction), STI_OBJECT, 2 }, + // OBJECT/15 is reserved for end of object + + // array of objects + { S_FIELD(SigningAccounts), STI_ARRAY, 1 }, + // ARRAY/15 is reserved for end of array +}; diff --git a/src/FieldNames.h b/src/FieldNames.h new file mode 100644 index 0000000000..5d4979a302 --- /dev/null +++ b/src/FieldNames.h @@ -0,0 +1,15 @@ +#ifndef __FIELDNAMES__ +#define __FIELDNAMES__ + +#include "SerializedTypes.h" +#include "SerializedObject.h" + +struct FieldName +{ + SOE_Field field; + const char *fieldName; + SerializedTypeID fieldType; + int fieldValue; +}; + +#endif diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 5408a4dca8..59bc7359a2 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -349,14 +349,17 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) switch (it->second.mAction) { case taaMODIFY: + Log(lsTRACE) << "Modified Node " << it->first; nType = TMNModifiedNode; break; case taaDELETE: + Log(lsTRACE) << "Deleted Node " << it->first; nType = TMNDeletedNode; break; case taaCREATE: + Log(lsTRACE) << "Created Node " << it->first; nType = TMNCreatedNode; break; diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 08377304c1..e46bf479aa 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -30,9 +30,11 @@ enum SOE_Field sfAcceptRate, sfAcceptStart, sfAccount, + sfAccountHash, sfAmount, sfAuthorizedKey, sfBalance, + sfBaseFee, sfBondAmount, sfBookDirectory, sfBookNode, @@ -42,6 +44,7 @@ enum SOE_Field sfBorrower, sfCreateCode, sfCloseTime, + sfCloseResolution, sfCurrency, sfCurrencyIn, sfCurrencyOut, @@ -65,18 +68,22 @@ enum SOE_Field sfIndexes, sfIndexNext, sfIndexPrevious, + sfInnerTransaction, sfInvoiceID, sfIssuer, sfLastNode, sfLastTxnID, sfLastTxnSeq, sfLedgerHash, + sfLedgerSequence, sfLimitAmount, + sfLoadFee, sfLowID, sfLowLimit, sfLowQualityIn, sfLowQualityOut, sfMessageKey, + sfMiddleTransaction, sfMinimumOffer, sfNextAcceptExpire, sfNextAcceptRate, @@ -88,8 +95,10 @@ enum SOE_Field sfOfferSequence, sfOwner, sfOwnerNode, + sfParentCloseTime, + sfParentHash, sfPaths, - sfPubKey, + sfPublicKey, sfPublishHash, sfPublishSize, sfQualityIn, @@ -99,6 +108,7 @@ enum SOE_Field sfSendMax, sfSequence, sfSignature, + sfSigningAccounts, sfSigningKey, sfSigningTime, sfSourceTag, @@ -107,6 +117,7 @@ enum SOE_Field sfTakerPays, sfTarget, sfTransferRate, + sfTransactionHash, sfVersion, sfWalletLocator, diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 3a6417986e..e7735bfc8e 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -15,25 +15,28 @@ enum SerializedTypeID STI_DONE = -1, STI_NOTPRESENT = 0, - // standard types - STI_OBJECT = 1, - STI_UINT8 = 2, - STI_UINT16 = 3, - STI_UINT32 = 4, - STI_UINT64 = 5, - STI_HASH128 = 6, - STI_HASH160 = 7, - STI_HASH256 = 8, - STI_VL = 9, - STI_TL = 10, - STI_AMOUNT = 11, - STI_PATHSET = 12, - STI_VECTOR256 = 13, + // common types + STI_UINT32 = 1, + STI_UINT64 = 2, + STI_HASH128 = 3, + STI_HASH256 = 4, + STI_TL = 5, + STI_AMOUNT = 6, + STI_VL = 7, + STI_ACCOUNT = 8, + STI_OBJECT = 14, + STI_ARRAY = 15, + + // uncommon types + STI_UINT8 = 16, + STI_UINT16 = 17, + STI_HASH160 = 18, + STI_PATHSET = 19, + STI_VECTOR256 = 20, // high level types - STI_ACCOUNT = 100, - STI_TRANSACTION = 101, - STI_LEDGERENTRY = 102 + STI_TRANSACTION = 100001, + STI_LEDGERENTRY = 100002 }; enum PathFlags diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 00988712d9..526f433bf1 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -194,7 +194,7 @@ Transaction::pointer Transaction::setClaim( const std::vector& vucSignature) { mTransaction->setITFieldVL(sfGenerator, vucGenerator); - mTransaction->setITFieldVL(sfPubKey, vucPubKey); + mTransaction->setITFieldVL(sfPublicKey, vucPubKey); mTransaction->setITFieldVL(sfSignature, vucSignature); sign(naPrivateKey); @@ -455,7 +455,7 @@ Transaction::pointer Transaction::setPasswordSet( { mTransaction->setITFieldAccount(sfAuthorizedKey, naAuthKeyID); mTransaction->setITFieldVL(sfGenerator, vucGenerator); - mTransaction->setITFieldVL(sfPubKey, vucPubKey); + mTransaction->setITFieldVL(sfPublicKey, vucPubKey); mTransaction->setITFieldVL(sfSignature, vucSignature); sign(naPrivateKey); @@ -542,7 +542,7 @@ Transaction::pointer Transaction::setWalletAdd( { mTransaction->setITFieldAmount(sfAmount, saAmount); mTransaction->setITFieldAccount(sfAuthorizedKey, naAuthKeyID); - mTransaction->setITFieldVL(sfPubKey, naNewPubKey.getAccountPublic()); + mTransaction->setITFieldVL(sfPublicKey, naNewPubKey.getAccountPublic()); mTransaction->setITFieldVL(sfSignature, vucSignature); sign(naPrivateKey); diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index f60ae0af57..19db581da2 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -30,7 +30,7 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus // std::vector vucCipher = txn.getITFieldVL(sfGenerator); - std::vector vucPubKey = txn.getITFieldVL(sfPubKey); + std::vector vucPubKey = txn.getITFieldVL(sfPublicKey); std::vector vucSignature = txn.getITFieldVL(sfSignature); NewcoinAddress naAccountPublic = NewcoinAddress::createAccountPublic(vucPubKey); @@ -620,7 +620,7 @@ TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) { std::cerr << "WalletAdd>" << std::endl; - const std::vector vucPubKey = txn.getITFieldVL(sfPubKey); + const std::vector vucPubKey = txn.getITFieldVL(sfPublicKey); const std::vector vucSignature = txn.getITFieldVL(sfSignature); const uint160 uAuthKeyID = txn.getITFieldAccount(sfAuthorizedKey); const NewcoinAddress naMasterPubKey = NewcoinAddress::createAccountPublic(vucPubKey); diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index de18524c7c..542e2683c5 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -21,7 +21,7 @@ TransactionFormat InnerTxnFormats[]= { "Claim", ttCLAIM, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, @@ -85,7 +85,7 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, @@ -106,7 +106,7 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, From 8f88575b8e2fec3321d1b309ad68330b2142fa2e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 13:19:28 -0700 Subject: [PATCH 11/45] Low-level serializer functions for new type/name field. --- src/Serializer.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++ src/Serializer.h | 5 ++++ 2 files changed, 67 insertions(+) diff --git a/src/Serializer.cpp b/src/Serializer.cpp index 51fd734668..cd7e0d6a8e 100644 --- a/src/Serializer.cpp +++ b/src/Serializer.cpp @@ -154,6 +154,57 @@ uint256 Serializer::get256(int offset) const return ret; } +int Serializer::addFieldID(int type, int name) +{ + int ret = mData.size(); + assert((type > 0) && (type < 256) && (name > 0) && (name < 256)); + if (type < 16) + { + if (name < 16) // common type, common name + mData.push_back(static_cast((type << 4) | name)); + else + { // common type, uncommon name + mData.push_back(static_cast(type << 4)); + mData.push_back(static_cast(name)); + } + } + else if (name < 16) + { // uncommon type, common name + mData.push_back(static_cast(name)); + mData.push_back(static_cast(type)); + } + else + { // uncommon type, uncommon name + mData.push_back(static_cast(0)); + mData.push_back(static_cast(type)); + mData.push_back(static_cast(name)); + } + return ret; +} + +bool Serializer::getFieldID(int& type, int & name, int offset) const +{ + if (!get8(type, offset)) + return false; + name = type & 15; + type >>= 4; + if (type == 0) + { // uncommon type + if (!get8(type, ++offset)) + return false; + if ((type == 0) || (type < 16)) + return false; + } + if (name == 0) + { // uncommon name + if (!get8(name, ++offset)) + return false; + if ((name == 0) || (name < 16)) + return false; + } + return true; +} + int Serializer::add8(unsigned char byte) { int ret = mData.size(); @@ -535,6 +586,17 @@ int SerializerIterator::getBytesLeft() return mSerializer.size() - mPos; } +void SerializerIterator::getFieldID(int& type, int& field) +{ + if (!mSerializer.getFieldID(type, field, mPos)) + throw std::runtime_error("invalid serializer getFieldID"); + ++mPos; + if (type >= 16) + ++mPos; + if (field >= 16) + ++mPos; +} + unsigned char SerializerIterator::get8() { int val; diff --git a/src/Serializer.h b/src/Serializer.h index 5c687e2984..e1c251508c 100644 --- a/src/Serializer.h +++ b/src/Serializer.h @@ -67,6 +67,9 @@ public: bool getTaggedList(std::list&, int offset, int& length) const; bool getTaggedList(std::vector&, int offset, int& length) const; + bool getFieldID(int& type, int& name, int offset) const; + int addFieldID(int type, int name); + // normal hash functions uint160 getRIPEMD160(int size=-1) const; uint256 getSHA256(int size=-1) const; @@ -156,6 +159,8 @@ public: uint160 get160(); uint256 get256(); + void getFieldID(int& type, int& field); + std::vector getRaw(int iLength); std::vector getVL(); From 3c5ea7020f995696a3231c52165060148ac73777 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 14:30:24 -0700 Subject: [PATCH 12/45] Start of STAmount issuer fixes. --- src/Amount.cpp | 24 ++++++++++++++++++------ src/SerializedTypes.h | 12 +++++++----- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 4c35c46a06..9fc46089e3 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -359,19 +359,16 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset)) throw std::runtime_error("invalid currency value"); - sapResult = new STAmount(name, uCurrencyID, value, offset, isNegative); + sapResult = new STAmount(name, uCurrencyID, uIssuerID, value, offset, isNegative); } else { if (offset != 512) throw std::runtime_error("invalid currency value"); - sapResult = new STAmount(name, uCurrencyID); + sapResult = new STAmount(name, uCurrencyID, uIssuerID); } - if (sapResult) - sapResult->setIssuer(uIssuerID); - return sapResult; } @@ -522,7 +519,22 @@ STAmount& STAmount::operator-=(const STAmount& a) STAmount STAmount::operator-(void) const { if (mValue == 0) return *this; - return STAmount(name, mCurrency, mValue, mOffset, mIsNative, !mIsNegative); + return STAmount(name, mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative); +} + +STAmount& STAmount::operator=(const STAmount &a) +{ + if (name == NULL) + name = a.name; + + mCurrency = a.mCurrency; + mIssuer = a.mIssuer; + mValue = a.mValue; + mOffset = a.mOffset; + mIsNative = a.mIsNative; + mIsNegative = a.mIsNegative; + + return *this; } STAmount& STAmount::operator=(uint64 v) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index e7735bfc8e..fef6664123 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -250,9 +250,9 @@ protected: STAmount(const char *name, uint64 value, bool isNegative) : SerializedType(name), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) { ; } - STAmount(const char *n, const uint160& cur, uint64 val, int off, bool isNative, bool isNegative) - : SerializedType(n), mCurrency(cur), mValue(val), mOffset(off), mIsNative(isNative), mIsNegative(isNegative) - { ; } + STAmount(const char *n, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) + : SerializedType(n), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), + mIsNative(isNat), mIsNegative(isNeg) { ; } uint64 toUInt64() const; static uint64 muldiv(uint64, uint64, uint64); @@ -272,8 +272,9 @@ public: { canonicalize(); } // YYY This should probably require issuer too. - STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) : - SerializedType(n), mCurrency(currency), mValue(v), mOffset(off), mIsNegative(isNeg) + STAmount(const char* n, const uint160& currency, const uint160& issuer, + uint64 v = 0, int off = 0, bool isNeg = false) : + SerializedType(n), mCurrency(currency), mIssuer(issuer), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } STAmount(const char* n, int64 v); @@ -347,6 +348,7 @@ public: STAmount operator-(uint64) const; STAmount operator-(void) const; + STAmount& operator=(const STAmount&); STAmount& operator+=(const STAmount&); STAmount& operator-=(const STAmount&); STAmount& operator+=(uint64); From 7ef8001505eec94bcef5c7843e1e71675f8e1a7c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 14:36:48 -0700 Subject: [PATCH 13/45] Audit all construction cases, fix broken ones. --- src/Amount.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 9fc46089e3..ebd2597a99 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -632,9 +632,9 @@ STAmount operator+(const STAmount& v1, const STAmount& v2) int64 fv = vv1 + vv2; if (fv >= 0) - return STAmount(v1.name, v1.mCurrency, fv, ov1, false); + return STAmount(v1.name, v1.mCurrency, v1.mIssuer, fv, ov1, false); else - return STAmount(v1.name, v1.mCurrency, -fv, ov1, true); + return STAmount(v1.name, v1.mCurrency, v1.mIssuer, -fv, ov1, true); } STAmount operator-(const STAmount& v1, const STAmount& v2) @@ -664,9 +664,9 @@ STAmount operator-(const STAmount& v1, const STAmount& v2) int64 fv = vv1 - vv2; if (fv >= 0) - return STAmount(v1.name, v1.mCurrency, fv, ov1, false); + return STAmount(v1.name, v1.mCurrency, v1.mIssuer, fv, ov1, false); else - return STAmount(v1.name, v1.mCurrency, -fv, ov1, true); + return STAmount(v1.name, v1.mCurrency, v1.mIssuer, -fv, ov1, true); } STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID) From 9432d35f14a862dca021672569a1b1b49d2d824f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 14:45:44 -0700 Subject: [PATCH 14/45] You don't need to customize operator=(const&) since the base class does it for you. --- src/Amount.cpp | 15 --------------- src/SerializedTypes.h | 1 - 2 files changed, 16 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index ebd2597a99..f0692f2af7 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -522,21 +522,6 @@ STAmount STAmount::operator-(void) const return STAmount(name, mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative); } -STAmount& STAmount::operator=(const STAmount &a) -{ - if (name == NULL) - name = a.name; - - mCurrency = a.mCurrency; - mIssuer = a.mIssuer; - mValue = a.mValue; - mOffset = a.mOffset; - mIsNative = a.mIsNative; - mIsNegative = a.mIsNegative; - - return *this; -} - STAmount& STAmount::operator=(uint64 v) { // does not copy name, does not change currency type mOffset = 0; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index fef6664123..6c9099df50 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -348,7 +348,6 @@ public: STAmount operator-(uint64) const; STAmount operator-(void) const; - STAmount& operator=(const STAmount&); STAmount& operator+=(const STAmount&); STAmount& operator-=(const STAmount&); STAmount& operator+=(uint64); From 173b6ce5581e5c7e78dc5d7137fb58ebc48f0834 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 16:21:40 -0700 Subject: [PATCH 15/45] More changes to the new serialization format that don't break compatibility. --- src/FieldNames.cpp | 97 ++-------------------------- src/FieldNames.h | 1 + src/LedgerFormats.cpp | 7 --- src/SerializeProto.h | 125 +++++++++++++++++++++++++++++++++++++ src/SerializedObject.h | 100 ++--------------------------- src/TransactionFormats.cpp | 13 ---- 6 files changed, 137 insertions(+), 206 deletions(-) create mode 100644 src/SerializeProto.h diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 5f1ff6130c..3053c2c960 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -1,98 +1,13 @@ #include "FieldNames.h" -#define S_FIELD(x) sf##x, #x +#define FIELD(name, type, index) { sf##name, #name, STI_##type, index }, +#define TYPE(type, index) FieldName FieldNames[]= { - - // 8-bit integers - { S_FIELD(CloseResolution), STI_UINT8, 1 }, - - // 32-bit integers (common) - { S_FIELD(Flags), STI_UINT32, 1 }, - { S_FIELD(SourceTag), STI_UINT32, 2 }, - { S_FIELD(Sequence), STI_UINT32, 3 }, - { S_FIELD(LastTxnSeq), STI_UINT32, 4 }, - { S_FIELD(LedgerSequence), STI_UINT32, 5 }, - { S_FIELD(CloseTime), STI_UINT32, 6 }, - { S_FIELD(ParentCloseTime), STI_UINT32, 7 }, - { S_FIELD(SigningTime), STI_UINT32, 8 }, - { S_FIELD(Expiration), STI_UINT32, 9 }, - { S_FIELD(TransferRate), STI_UINT32, 10 }, - { S_FIELD(PublishSize), STI_UINT32, 11 }, - - // 32-bit integers (rare) - { S_FIELD(HighQualityIn), STI_UINT32, 16 }, - { S_FIELD(HighQualityOut), STI_UINT32, 17 }, - { S_FIELD(LowQualityIn), STI_UINT32, 18 }, - { S_FIELD(LowQualityOut), STI_UINT32, 19 }, - { S_FIELD(QualityIn), STI_UINT32, 20 }, - { S_FIELD(QualityOut), STI_UINT32, 21 }, - { S_FIELD(StampEscrow), STI_UINT32, 22 }, - { S_FIELD(BondAmount), STI_UINT32, 23 }, - { S_FIELD(LoadFee), STI_UINT32, 24 }, - - // 64-bit integers - { S_FIELD(IndexNext), STI_UINT64, 1 }, - { S_FIELD(IndexPrevious), STI_UINT64, 2 }, - { S_FIELD(BookNode), STI_UINT64, 3 }, - { S_FIELD(OwnerNode), STI_UINT64, 4 }, - { S_FIELD(BaseFee), STI_UINT64, 5 }, - - // 128-bit - { S_FIELD(PublishSize), STI_HASH128, 1 }, - { S_FIELD(EmailHash), STI_HASH128, 2 }, - - // 256-bit - { S_FIELD(LedgerHash), STI_HASH256, 1 }, - { S_FIELD(ParentHash), STI_HASH256, 2 }, - { S_FIELD(TransactionHash), STI_HASH256, 3 }, - { S_FIELD(AccountHash), STI_HASH256, 4 }, - { S_FIELD(LastTxnID), STI_HASH256, 5 }, - { S_FIELD(WalletLocator), STI_HASH256, 6 }, - { S_FIELD(PublishHash), STI_HASH256, 7 }, - { S_FIELD(Nickname), STI_HASH256, 8 }, - - // currency amount - { S_FIELD(Amount), STI_AMOUNT, 1 }, - { S_FIELD(Balance), STI_AMOUNT, 2 }, - { S_FIELD(LimitAmount), STI_AMOUNT, 3 }, - { S_FIELD(TakerPays), STI_AMOUNT, 4 }, - { S_FIELD(TakerGets), STI_AMOUNT, 5 }, - { S_FIELD(LowLimit), STI_AMOUNT, 6 }, - { S_FIELD(HighLimit), STI_AMOUNT, 7 }, - { S_FIELD(MinimumOffer), STI_AMOUNT, 8 }, - - // variable length - { S_FIELD(PublicKey), STI_VL, 1 }, - { S_FIELD(MessageKey), STI_VL, 2 }, - { S_FIELD(SigningKey), STI_VL, 3 }, - { S_FIELD(Signature), STI_VL, 4 }, - { S_FIELD(Generator), STI_VL, 5 }, - { S_FIELD(Domain), STI_VL, 6 }, - - // account - { S_FIELD(Account), STI_ACCOUNT, 1 }, - { S_FIELD(Owner), STI_ACCOUNT, 2 }, - { S_FIELD(Destination), STI_ACCOUNT, 3 }, - { S_FIELD(Issuer), STI_ACCOUNT, 4 }, - { S_FIELD(HighID), STI_ACCOUNT, 5 }, - { S_FIELD(LowID), STI_ACCOUNT, 6 }, - { S_FIELD(Target), STI_ACCOUNT, 7 }, - - // path set - { S_FIELD(Paths), STI_PATHSET, 1 }, - - // vector of 256-bit - { S_FIELD(Indexes), STI_VECTOR256, 1 }, - - // inner object - { S_FIELD(MiddleTransaction), STI_OBJECT, 1 }, - { S_FIELD(InnerTransaction), STI_OBJECT, 2 }, - // OBJECT/15 is reserved for end of object - - // array of objects - { S_FIELD(SigningAccounts), STI_ARRAY, 1 }, - // ARRAY/15 is reserved for end of array +#include "SerializeProto.h" }; + +#undef FIELD +#undef TYPE diff --git a/src/FieldNames.h b/src/FieldNames.h index 5d4979a302..af760127f6 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -10,6 +10,7 @@ struct FieldName const char *fieldName; SerializedTypeID fieldType; int fieldValue; + int fieldID; }; #endif diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index ef991c9f62..1db310a4c1 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -20,7 +20,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Domain), STI_VL, SOE_IFFLAG, 32 }, { S_FIELD(PublishHash), STI_HASH256, SOE_IFFLAG, 64 }, { S_FIELD(PublishSize), STI_UINT32, SOE_IFFLAG, 128 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Contract", ltCONTRACT, { @@ -37,7 +36,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "DirectoryNode", ltDIR_NODE, { @@ -45,20 +43,17 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Indexes), STI_VECTOR256, SOE_REQUIRED, 0 }, { S_FIELD(IndexNext), STI_UINT64, SOE_IFFLAG, 1 }, { S_FIELD(IndexPrevious), STI_UINT64, SOE_IFFLAG, 2 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "GeneratorMap", ltGENERATOR_MAP, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Nickname", ltNICKNAME, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Offer", ltOFFER, { @@ -73,7 +68,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "RippleState", ltRIPPLE_STATE, { @@ -89,7 +83,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(LowQualityOut), STI_UINT32, SOE_IFFLAG, 2 }, { S_FIELD(HighQualityIn), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(HighQualityOut), STI_UINT32, SOE_IFFLAG, 8 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { NULL, ltINVALID } diff --git a/src/SerializeProto.h b/src/SerializeProto.h new file mode 100644 index 0000000000..fc02af1d12 --- /dev/null +++ b/src/SerializeProto.h @@ -0,0 +1,125 @@ +// This is not really a header file, but it can be used as one with +// appropriate #define statements. + + // types (common) + TYPE(UINT32, 1) + TYPE(UINT64, 2) + TYPE(HASH128, 3) + TYPE(HASH256, 4) + // 5 is reserved + TYPE(AMOUNT, 6) + TYPE(VL, 7) + TYPE(ACCOUNT, 8) + // 9-13 are reserved + TYPE(OBJECT, 14) + TYPE(ARRAY, 15) + + // types (uncommon) + TYPE(UINT8, 16) + TYPE(UINT16, 17) + TYPE(HASH160, 18) + TYPE(PATHSET, 19) + TYPE(VECTOR256, 20) + + // 8-bit integers + FIELD(CloseResolution, UINT8, 1) + + // 32-bit integers (common) + FIELD(Flags, UINT32, 1) + FIELD(SourceTag, UINT32, 2) + FIELD(Sequence, UINT32, 3) + FIELD(LastTxnSeq, UINT32, 4) + FIELD(LedgerSequence, UINT32, 5) + FIELD(CloseTime, UINT32, 6) + FIELD(ParentCloseTime, UINT32, 7) + FIELD(SigningTime, UINT32, 8) + FIELD(Expiration, UINT32, 9) + FIELD(TransferRate, UINT32, 10) + FIELD(PublishSize, UINT32, 11) + + // 32-bit integers (uncommon) + FIELD(HighQualityIn, UINT32, 16) + FIELD(HighQualityOut, UINT32, 17) + FIELD(LowQualityIn, UINT32, 18) + FIELD(LowQualityOut, UINT32, 19) + FIELD(QualityIn, UINT32, 20) + FIELD(QualityOut, UINT32, 21) + FIELD(StampEscrow, UINT32, 22) + FIELD(BondAmount, UINT32, 23) + FIELD(LoadFee, UINT32, 24) + FIELD(OfferSequence, UINT32, 25) + + // 64-bit integers + FIELD(IndexNext, UINT64, 1) + FIELD(IndexPrevious, UINT64, 2) + FIELD(BookNode, UINT64, 3) + FIELD(OwnerNode, UINT64, 4) + FIELD(BaseFee, UINT64, 5) + + // 128-bit + FIELD(EmailHash, HASH128, 2) + + // 256-bit (common) + FIELD(LedgerHash, HASH256, 1) + FIELD(ParentHash, HASH256, 2) + FIELD(TransactionHash, HASH256, 3) + FIELD(AccountHash, HASH256, 4) + FIELD(LastTxnID, HASH256, 5) + FIELD(WalletLocator, HASH256, 6) + FIELD(PublishHash, HASH256, 7) + + // 256-bit (uncommon) + FIELD(BookDirectory, HASH256, 16) + FIELD(InvoiceID, HASH256, 17) + FIELD(Nickname, HASH256, 18) + + // currency amount (common) + FIELD(Amount, AMOUNT, 1) + FIELD(Balance, AMOUNT, 2) + FIELD(LimitAmount, AMOUNT, 3) + FIELD(TakerPays, AMOUNT, 4) + FIELD(TakerGets, AMOUNT, 5) + FIELD(LowLimit, AMOUNT, 6) + FIELD(HighLimit, AMOUNT, 7) + FIELD(SendMax, AMOUNT, 9) + + // current amount (uncommon) + FIELD(MinimumOffer, AMOUNT, 16) + FIELD(RippleEscrow, AMOUNT, 17) + + // variable length + FIELD(PublicKey, VL, 1) + FIELD(MessageKey, VL, 2) + FIELD(SigningKey, VL, 3) + FIELD(Signature, VL, 4) + FIELD(Generator, VL, 5) + FIELD(Domain, VL, 6) + FIELD(FundCode, VL, 7) + FIELD(RemoveCode, VL, 8) + FIELD(ExpireCode, VL, 9) + FIELD(CreateCode, VL, 10) + + // account + FIELD(Account, ACCOUNT, 1) + FIELD(Owner, ACCOUNT, 2) + FIELD(Destination, ACCOUNT, 3) + FIELD(Issuer, ACCOUNT, 4) + FIELD(HighID, ACCOUNT, 5) + FIELD(LowID, ACCOUNT, 6) + FIELD(Target, ACCOUNT, 7) + FIELD(AuthorizedKey, ACCOUNT, 8) + + // path set + FIELD(Paths, PATHSET, 1) + + // vector of 256-bit + FIELD(Indexes, VECTOR256, 1) + + // inner object + // OBJECT/1 is reserved for end of object + FIELD(MiddleTransaction, OBJECT, 2) + FIELD(InnerTransaction, OBJECT, 3) + + // array of objects + // ARRAY/1 is reserved for end of array + FIELD(SigningAccounts, ARRAY, 2) diff --git a/src/SerializedObject.h b/src/SerializedObject.h index e46bf479aa..b0e0b5e4b4 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -25,101 +25,11 @@ enum SOE_Field sfInvalid = -1, sfGeneric = 0, - // common fields - sfAcceptExpire, - sfAcceptRate, - sfAcceptStart, - sfAccount, - sfAccountHash, - sfAmount, - sfAuthorizedKey, - sfBalance, - sfBaseFee, - sfBondAmount, - sfBookDirectory, - sfBookNode, - sfBorrowExpire, - sfBorrowRate, - sfBorrowStart, - sfBorrower, - sfCreateCode, - sfCloseTime, - sfCloseResolution, - sfCurrency, - sfCurrencyIn, - sfCurrencyOut, - sfDestination, - sfDomain, - sfEmailHash, - sfExpiration, - sfExpireCode, - sfExtensions, - sfFirstNode, - sfFlags, - sfFundCode, - sfGenerator, - sfGeneratorID, - sfHash, - sfHighID, - sfHighLimit, - sfHighQualityIn, - sfHighQualityOut, - sfIdentifier, - sfIndexes, - sfIndexNext, - sfIndexPrevious, - sfInnerTransaction, - sfInvoiceID, - sfIssuer, - sfLastNode, - sfLastTxnID, - sfLastTxnSeq, - sfLedgerHash, - sfLedgerSequence, - sfLimitAmount, - sfLoadFee, - sfLowID, - sfLowLimit, - sfLowQualityIn, - sfLowQualityOut, - sfMessageKey, - sfMiddleTransaction, - sfMinimumOffer, - sfNextAcceptExpire, - sfNextAcceptRate, - sfNextAcceptStart, - sfNextTransitExpire, - sfNextTransitRate, - sfNextTransitStart, - sfNickname, - sfOfferSequence, - sfOwner, - sfOwnerNode, - sfParentCloseTime, - sfParentHash, - sfPaths, - sfPublicKey, - sfPublishHash, - sfPublishSize, - sfQualityIn, - sfQualityOut, - sfRemoveCode, - sfRippleEscrow, - sfSendMax, - sfSequence, - sfSignature, - sfSigningAccounts, - sfSigningKey, - sfSigningTime, - sfSourceTag, - sfStampEscrow, - sfTakerGets, - sfTakerPays, - sfTarget, - sfTransferRate, - sfTransactionHash, - sfVersion, - sfWalletLocator, +#define FIELD(name, type, index) sf##name, +#define TYPE(name, index) +#include "SerializeProto.h" +#undef FIELD +#undef TYPE // test fields sfTest1, sfTest2, sfTest3, sfTest4 diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 542e2683c5..3ab00f7dea 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -15,7 +15,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(TransferRate), STI_UINT32, SOE_IFFLAG, 32 }, { S_FIELD(PublishHash), STI_HASH256, SOE_IFFLAG, 64 }, { S_FIELD(PublishSize), STI_UINT32, SOE_IFFLAG, 128 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Claim", ttCLAIM, { @@ -24,7 +23,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "CreditSet", ttCREDIT_SET, { @@ -34,7 +32,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(LimitAmount), STI_AMOUNT, SOE_IFFLAG, 2 }, { S_FIELD(QualityIn), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(QualityOut), STI_UINT32, SOE_IFFLAG, 8 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, /* @@ -45,7 +42,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 2 }, { S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 4 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, */ @@ -55,7 +51,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 }, { S_FIELD(Signature), STI_VL, SOE_IFFLAG, 2 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "OfferCreate", ttOFFER_CREATE, { @@ -64,21 +59,18 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 2 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "OfferCancel", ttOFFER_CANCEL, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(OfferSequence), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "PasswordFund", ttPASSWORD_FUND, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "PasswordSet", ttPASSWORD_SET, { @@ -88,7 +80,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Payment", ttPAYMENT, { @@ -99,7 +90,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Paths), STI_PATHSET, SOE_IFFLAG, 2 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(InvoiceID), STI_HASH256, SOE_IFFLAG, 8 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "WalletAdd", ttWALLET_ADD, { @@ -109,7 +99,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Contract", ttCONTRACT, { @@ -122,13 +111,11 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Contract", ttCONTRACT_REMOVE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { NULL, ttINVALID } From 8d633bf065f85f542dc0ef97bf8daaec2a62aa37 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 16:23:09 -0700 Subject: [PATCH 16/45] Remove a FIXME since it's fixed. --- src/SerializedObject.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/SerializedObject.h b/src/SerializedObject.h index b0e0b5e4b4..89732a063d 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -18,8 +18,6 @@ enum SOE_Type SOE_IFNFLAG = 3 // present if flag not set }; -// JED: seems like there would be a better way to do this -// maybe something that inherits from SerializedTransaction enum SOE_Field { sfInvalid = -1, From 19ee517d9f2a0f64d6874a6dfccbbc1b07b6e56b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 16:28:08 -0700 Subject: [PATCH 17/45] Neaten this up a bit. --- src/FieldNames.cpp | 2 +- src/SerializeProto.h | 30 ++++++++++++++++-------------- src/SerializedObject.h | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 3053c2c960..a65ce1bc93 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -2,7 +2,7 @@ #include "FieldNames.h" #define FIELD(name, type, index) { sf##name, #name, STI_##type, index }, -#define TYPE(type, index) +#define TYPE(name, type, index) FieldName FieldNames[]= { diff --git a/src/SerializeProto.h b/src/SerializeProto.h index fc02af1d12..d2336e8971 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -2,24 +2,26 @@ // appropriate #define statements. // types (common) - TYPE(UINT32, 1) - TYPE(UINT64, 2) - TYPE(HASH128, 3) - TYPE(HASH256, 4) + TYPE("Int32", UINT32, 1) + TYPE("Int64", UINT64, 2) + TYPE("Hash128", HASH128, 3) + TYPE("Hash256", HASH256, 4) // 5 is reserved - TYPE(AMOUNT, 6) - TYPE(VL, 7) - TYPE(ACCOUNT, 8) + TYPE("Amount", AMOUNT, 6) + TYPE("VariableLength", VL, 7) + TYPE("Account", ACCOUNT, 8) // 9-13 are reserved - TYPE(OBJECT, 14) - TYPE(ARRAY, 15) + TYPE("Object", OBJECT, 14) + TYPE("Array", ARRAY, 15) // types (uncommon) - TYPE(UINT8, 16) - TYPE(UINT16, 17) - TYPE(HASH160, 18) - TYPE(PATHSET, 19) - TYPE(VECTOR256, 20) + TYPE("Int8", UINT8, 16) + TYPE("Int16", UINT16, 17) + TYPE("Hash160", HASH160, 18) + TYPE("PathSet", PATHSET, 19) + TYPE("Vector256", VECTOR256, 20) + + // 8-bit integers FIELD(CloseResolution, UINT8, 1) diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 89732a063d..3ff352a793 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -24,7 +24,7 @@ enum SOE_Field sfGeneric = 0, #define FIELD(name, type, index) sf##name, -#define TYPE(name, index) +#define TYPE(name, type, index) #include "SerializeProto.h" #undef FIELD #undef TYPE From 8cc760ad8d671ac217f6289a67bbbaaf8271b422 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 24 Sep 2012 19:50:57 -0700 Subject: [PATCH 18/45] Clean up offer processing. --- src/LedgerEntrySet.cpp | 37 +++++++++------------------- src/TransactionAction.cpp | 52 +++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 5408a4dca8..c1f4919fde 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -938,24 +938,19 @@ STAmount LedgerEntrySet::accountHolds(const uint160& uAccountID, const uint160& if (!uCurrencyID) { - SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID)); + SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID)); saAmount = sleAccount->getIValueFieldAmount(sfBalance); - - Log(lsINFO) << "accountHolds: stamps: " << saAmount.getText(); } else { saAmount = rippleHolds(uAccountID, uCurrencyID, uIssuerID); - - Log(lsINFO) << "accountHolds: " - << saAmount.getFullText() - << " : " - << STAmount::createHumanCurrency(uCurrencyID) - << "/" - << NewcoinAddress::createHumanAccountID(uIssuerID); } + Log(lsINFO) << boost::str(boost::format("accountHolds: uAccountID=%s saAmount=%s") + % NewcoinAddress::createHumanAccountID(uAccountID) + % saAmount.getFullText()); + return saAmount; } @@ -968,30 +963,22 @@ STAmount LedgerEntrySet::accountFunds(const uint160& uAccountID, const STAmount& { STAmount saFunds; - Log(lsINFO) << "accountFunds: uAccountID=" - << NewcoinAddress::createHumanAccountID(uAccountID); - Log(lsINFO) << "accountFunds: saDefault.isNative()=" << saDefault.isNative(); - Log(lsINFO) << "accountFunds: saDefault.getIssuer()=" - << NewcoinAddress::createHumanAccountID(saDefault.getIssuer()); - if (!saDefault.isNative() && saDefault.getIssuer() == uAccountID) { saFunds = saDefault; - Log(lsINFO) << "accountFunds: offer funds: ripple self-funded: " << saFunds.getText(); + Log(lsINFO) << boost::str(boost::format("accountFunds: uAccountID=%s saDefault=%s SELF-FUNDED") + % NewcoinAddress::createHumanAccountID(uAccountID) + % saDefault.getFullText()); } else { saFunds = accountHolds(uAccountID, saDefault.getCurrency(), saDefault.getIssuer()); - Log(lsINFO) << "accountFunds: offer funds: uAccountID =" - << NewcoinAddress::createHumanAccountID(uAccountID) - << " : " - << saFunds.getText() - << "/" - << saDefault.getHumanCurrency() - << "/" - << NewcoinAddress::createHumanAccountID(saDefault.getIssuer()); + Log(lsINFO) << boost::str(boost::format("accountFunds: uAccountID=%s saDefault=%s saFunds=%s") + % NewcoinAddress::createHumanAccountID(uAccountID) + % saDefault.getFullText() + % saFunds.getFullText()); } return saFunds; diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index f60ae0af57..2862a1d427 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -710,8 +710,8 @@ TER TransactionEngine::takeOffers( boost::unordered_set usOfferUnfundedBecame; // Offers that became unfunded. boost::unordered_set usAccountTouched; // Accounts touched. - saTakerPaid = 0; - saTakerGot = 0; + saTakerPaid = STAmount(saTakerPays.getCurrency(), saTakerPays.getIssuer()); + saTakerGot = STAmount(saTakerGets.getCurrency(), saTakerGets.getIssuer()); while (temUNCERTAIN == terResult) { @@ -915,8 +915,11 @@ Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); const bool bPassive = isSetBit(txFlags, tfPassive); STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); -Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText(); -Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); + +Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGets=%s") + % saTakerPays.getFullText() + % saTakerGets.getFullText()); + const uint160 uPaysIssuerID = saTakerPays.getIssuer(); const uint160 uGetsIssuerID = saTakerGets.getIssuer(); const uint32 uExpiration = txn.getITFieldU32(sfExpiration); @@ -999,14 +1002,14 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); STAmount saOfferGot; const uint256 uTakeBookBase = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); - Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s : %s/%s -> %s/%s") + Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s for %s -> %s") % uTakeBookBase.ToString() - % saTakerGets.getHumanCurrency() - % NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()) - % saTakerPays.getHumanCurrency() - % NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer())); + % saTakerGets.getFullText() + % saTakerPays.getFullText()); // Take using the parameters of the offer. +#if 1 + Log(lsWARNING) << "doOfferCreate: takeOffers: BEFORE saTakerGets=" << saTakerGets.getFullText(); terResult = takeOffers( bPassive, uTakeBookBase, @@ -1017,12 +1020,14 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); saOfferPaid, // How much was spent. saOfferGot // How much was got. ); - +#else + terResult = tesSUCCESS; +#endif Log(lsWARNING) << "doOfferCreate: takeOffers=" << terResult; Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferPaid=" << saOfferPaid.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferGot=" << saOfferGot.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); - Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: AFTER saTakerGets=" << saTakerGets.getFullText(); if (tesSUCCESS == terResult) { @@ -1033,19 +1038,21 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); - Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()); Log(lsWARNING) << "doOfferCreate: takeOffers: mTxnAccountID=" << NewcoinAddress::createHumanAccountID(mTxnAccountID); - Log(lsWARNING) << "doOfferCreate: takeOffers: funds=" << mNodes.accountFunds(mTxnAccountID, saTakerGets).getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: FUNDS=" << mNodes.accountFunds(mTxnAccountID, saTakerGets).getFullText(); // Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); if (tesSUCCESS == terResult - && saTakerPays // Still wanting something. - && saTakerGets // Still offering something. + && saTakerPays // Still wanting something. + && saTakerGets // Still offering something. && mNodes.accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. { // We need to place the remainder of the offer into its order book. + Log(lsINFO) << boost::str(boost::format("doOfferCreate: offer not fully consumed: saTakerPays=%s saTakerGets=%s") + % saTakerPays.getFullText() + % saTakerGets.getFullText()); // Add offer to owner's directory. terResult = mNodes.dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex); @@ -1069,12 +1076,13 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); if (tesSUCCESS == terResult) { - // Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); - // Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); - // Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative(); - // Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative(); - // Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency(); - // Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency(); + Log(lsWARNING) << "doOfferCreate: sfAccount=" << NewcoinAddress::createHumanAccountID(mTxnAccountID); + Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); + Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); + Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative(); + Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative(); + Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency(); + Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency(); sleOffer->setIFieldAccount(sfAccount, mTxnAccountID); sleOffer->setIFieldU32(sfSequence, uSequence); @@ -1092,6 +1100,8 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); } } + Log(lsINFO) << "doOfferCreate: final sleOffer=" << sleOffer->getJson(0); + return terResult; } From 195cd9eadec95a4ed881a73d9bb8429474009d1c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 24 Sep 2012 20:07:31 -0700 Subject: [PATCH 19/45] Report IP when do an RPC call. --- src/CallRPC.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CallRPC.cpp b/src/CallRPC.cpp index 38f697a1e7..50896b858c 100644 --- a/src/CallRPC.cpp +++ b/src/CallRPC.cpp @@ -112,7 +112,8 @@ Json::Value callRPC(const std::string& strMethod, const Json::Value& params) "If the file does not exist, create it with owner-readable-only file permissions."); // Connect to localhost - std::cout << "Connecting to port:" << theConfig.RPC_PORT << std::endl; + std::cout << "Connecting to: " << theConfig.RPC_IP << ":" << theConfig.RPC_PORT << std::endl; + boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(theConfig.RPC_IP), theConfig.RPC_PORT); boost::asio::ip::tcp::iostream stream; From 6c17c0270b935cfa65d77e22f52df5d8d6d2e717 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 23:25:27 -0700 Subject: [PATCH 20/45] Remove dead code. Use the protocol file to generate the STI_* constants. --- src/SerializedObject.cpp | 27 ----------------- src/SerializedTypes.cpp | 45 ----------------------------- src/SerializedTypes.h | 62 ++++------------------------------------ 3 files changed, 5 insertions(+), 129 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index af4210f3d1..eaf7ec4006 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -42,9 +42,6 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, c case STI_VL: return std::auto_ptr(new STVariableLength(name)); - case STI_TL: - return std::auto_ptr(new STTaggedList(name)); - case STI_ACCOUNT: return std::auto_ptr(new STAccount(name)); @@ -91,9 +88,6 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID case STI_VL: return STVariableLength::deserialize(sit, name); - case STI_TL: - return STTaggedList::deserialize(sit, name); - case STI_ACCOUNT: return STAccount::deserialize(sit, name); @@ -476,17 +470,6 @@ std::vector STObject::getValueFieldVL(SOE_Field field) const return cf->getValue(); } -std::vector STObject::getValueFieldTL(SOE_Field field) const -{ - const SerializedType* rf = peekAtPField(field); - if (!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id = rf->getSType(); - if (id == STI_NOTPRESENT) return std::vector(); // optional field not present - const STTaggedList *cf = dynamic_cast(rf); - if (!cf) throw std::runtime_error("Wrong field type"); - return cf->getValue(); -} - STAmount STObject::getValueFieldAmount(SOE_Field field) const { const SerializedType* rf = peekAtPField(field); @@ -620,16 +603,6 @@ void STObject::setValueFieldVL(SOE_Field field, const std::vector cf->setValue(v); } -void STObject::setValueFieldTL(SOE_Field field, const std::vector& v) -{ - SerializedType* rf = getPField(field); - if (!rf) throw std::runtime_error("Field not found"); - if (rf->getSType() == STI_NOTPRESENT) rf = makeFieldPresent(field); - STTaggedList* cf = dynamic_cast(rf); - if (!cf) throw std::runtime_error("Wrong field type"); - cf->setValue(v); -} - void STObject::setValueFieldAmount(SOE_Field field, const STAmount &v) { SerializedType* rf = getPField(field); diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 3bd54dc34a..dde47265c0 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -255,51 +255,6 @@ void STAccount::setValueNCA(const NewcoinAddress& nca) setValueH160(nca.getAccountID()); } -std::string STTaggedList::getText() const -{ - std::string ret; - for (std::vector::const_iterator it=value.begin(); it!=value.end(); ++it) - { - ret += boost::lexical_cast(it->first); - ret += ","; - ret += strHex(it->second); - } - return ret; -} - -Json::Value STTaggedList::getJson(int) const -{ - Json::Value ret(Json::arrayValue); - - for (std::vector::const_iterator it=value.begin(); it!=value.end(); ++it) - { - Json::Value elem(Json::arrayValue); - elem.append(it->first); - elem.append(strHex(it->second)); - ret.append(elem); - } - - return ret; -} - -STTaggedList* STTaggedList::construct(SerializerIterator& u, const char *name) -{ - return new STTaggedList(name, u.getTaggedList()); -} - -int STTaggedList::getLength() const -{ - int ret = Serializer::getTaggedListLength(value); - if (ret<0) throw std::overflow_error("bad TL length"); - return ret; -} - -bool STTaggedList::isEquivalent(const SerializedType& t) const -{ - const STTaggedList* v = dynamic_cast(&t); - return v && (value == v->value); -} - STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) { std::vector paths; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 6c9099df50..28a3063677 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -15,24 +15,11 @@ enum SerializedTypeID STI_DONE = -1, STI_NOTPRESENT = 0, - // common types - STI_UINT32 = 1, - STI_UINT64 = 2, - STI_HASH128 = 3, - STI_HASH256 = 4, - STI_TL = 5, - STI_AMOUNT = 6, - STI_VL = 7, - STI_ACCOUNT = 8, - STI_OBJECT = 14, - STI_ARRAY = 15, - - // uncommon types - STI_UINT8 = 16, - STI_UINT16 = 17, - STI_HASH160 = 18, - STI_PATHSET = 19, - STI_VECTOR256 = 20, +#define TYPE(name, field, value) STI_##field = value, +#define FIELD(name, field, value) +#include "SerializeProto.h" +#undef TYPE +#undef FIELD // high level types STI_TRANSACTION = 100001, @@ -730,45 +717,6 @@ namespace boost }; } -class STTaggedList : public SerializedType -{ -protected: - std::vector value; - - STTaggedList* duplicate() const { return new STTaggedList(name, value); } - static STTaggedList* construct(SerializerIterator&, const char* name = NULL); - -public: - - STTaggedList() { ; } - STTaggedList(const char* n) : SerializedType(n) { ; } - STTaggedList(const std::vector& v) : value(v) { ; } - STTaggedList(const char* n, const std::vector& v) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) - { return std::auto_ptr(construct(sit, name)); } - - int getLength() const; - SerializedTypeID getSType() const { return STI_TL; } - std::string getText() const; - void add(Serializer& s) const { if (s.addTaggedList(value) < 0) throw(0); } - - const std::vector& peekValue() const { return value; } - std::vector& peekValue() { return value; } - std::vector getValue() const { return value; } - virtual Json::Value getJson(int) const; - - void setValue(const std::vector& v) { value=v; } - - int getItemCount() const { return value.size(); } - bool isEmpty() const { return value.empty(); } - - void clear() { value.erase(value.begin(), value.end()); } - void addItem(const TaggedListItem& v) { value.push_back(v); } - - operator std::vector() const { return value; } - virtual bool isEquivalent(const SerializedType& t) const; -}; - class STVector256 : public SerializedType { protected: From 04f0b12a13529a7b2251a876cb3e0c371e41e86f Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 15:14:27 -0700 Subject: [PATCH 21/45] UT: Initial tests of creating and connecting to a standalone store. --- test/config.js | 14 ++++++++------ test/standalone-test.js | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/test/config.js b/test/config.js index 6b320f248f..0610373db9 100644 --- a/test/config.js +++ b/test/config.js @@ -9,15 +9,17 @@ exports.newcoind = path.join(process.cwd(), "newcoind"); // Configuration for servers. exports.servers = { + // A local test server. alpha : { + 'trusted' : true, // "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" + '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/standalone-test.js b/test/standalone-test.js index d707baeca3..c50e50154a 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -4,6 +4,7 @@ var fs = require("fs"); var buster = require("buster"); var server = require("./server.js"); +var remote = require("../js/remote.js"); buster.testCase("Check standalone server startup", { "server start and stop": function(done) { @@ -18,4 +19,44 @@ buster.testCase("Check standalone server startup", { } }); +buster.testCase("Check websocket connection", { + 'setUp' : + function(done) { + server.start("alpha", + function(e) { + buster.refute(e); + done(); + }); + }, + + 'tearDown' : + function(done) { + server.stop("alpha", function(e) { + buster.refute(e); + done(); + }); + }, + + "websocket connect and disconnect" : + function(done) { + var alpha = remote.remoteConfig("alpha"); + + alpha.connect(function(stat) { + buster.assert(1 == stat); // OPEN + + alpha.disconnect(function(stat) { + buster.assert(3 == stat); // CLOSED + done(); + }); + }); + }, +}); + +buster.testCase("Check assert", { + "assert" : + function() { + buster.assert(true); + } +}); + // vim:ts=4 From bf71b7b1bf0602117e4fceaf7d7567ae6d197bb0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 15:15:45 -0700 Subject: [PATCH 22/45] js: create a websocket connection. --- js/remote.js | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 js/remote.js diff --git a/js/remote.js b/js/remote.js new file mode 100644 index 0000000000..8903c87472 --- /dev/null +++ b/js/remote.js @@ -0,0 +1,123 @@ +// Remote access to a server. +// - We never send binary data. +// - We use the W3C interface for node and browser compatibility: +// http://www.w3.org/TR/websockets/#the-websocket-interface +// +// YYY Will later provide a network access which use multiple instances of this. +// + +var util = require('util'); + +var WebSocket = require('ws'); + +// YYY This is wrong should not use anything in test directory. +var config = require("../test/config.js"); + +// --> trusted: truthy, if remote is trusted +var Remote = function(trusted, websocket_ip, websocket_port) { + this.trusted = trusted; + this.websocket_ip = websocket_ip; + this.websocket_port = websocket_port; + this.id = 0; +}; + +var remoteConfig = function(server) { + var serverConfig = config.servers[server]; + + return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port); +}; + +// Target state is connectted. +// done(readyState): +// --> readyState: OPEN, CLOSED +Remote.method('connect', function(done, onmessage) { + var url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); + + console.log("remote: connect: %s", url); + + this.ws = new WebSocket(url); + + var ws = this.ws; + + ws.onopen = function() { + console.log("remote: onopen: %s", ws.readyState); + ws.onclose = undefined; + done(ws.readyState); + }; + + // Also covers failure to open. + ws.onclose = function() { + console.log("remote: onclose: %s", ws.readyState); + done(ws.readyState); + }; + + if (onmessage) { + ws.onmessage = onmessage; + } +}); + +// Target stated is disconnected. +Remote.method('disconnect', function(done) { + var ws = this.ws; + + ws.onclose = function() { + console.log("remote: onclose: %s", ws.readyState); + done(ws.readyState); + }; + + ws.close(); +}); + +// Send a command. The comman should lack the id. +// <-> command: what to send, consumed. +Remote.method('request', function(command, done) { + this.id += 1; // Advance id. + + var ws = this.ws; + + command.id = this.id; + + ws.response[command.id] = done; + + ws.send(command); +}); + +// Request the current ledger. +// done(index) +// index: undefined = error +Remote.method('ledger', function(done) { + +}); + + +// Submit a json transaction. +// done(value) +// <-> value: { 'status', status, 'result' : result, ... } +// done may be called up to 3 times. +Remote.method('submit', function(json, done) { +// this.request(..., function() { +// }); +}); + +// ==> entry_spec +Remote.method('ledger_entry', function(entry_spec, done) { + entry_spec.command = 'ledger_entry'; + + this.request(entry_spec, function() { + }); +}); + +// done(value) +// --> value: { 'status', status, 'result' : result, ... } +// done may be called up to 3 times. +Remote.method('account_root', function(account_id, done) { + this.request({ + 'command' : 'ledger_entry', + }, function() { + }); +}); + +exports.Remote = Remote; +exports.remoteConfig = remoteConfig; + +// vim:ts=4 From 93364999505406755bdb3b9e719f2180498a5c5d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 18:30:27 -0700 Subject: [PATCH 23/45] Cosmetic. --- src/NetworkOPs.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index ed6e7f0471..43b7da9f4e 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -134,8 +134,8 @@ public: // Directory functions // - STVector256 getDirNodeInfo(const uint256& uLedger, const uint256& uRootIndex, - uint64& uNodePrevious, uint64& uNodeNext); + STVector256 getDirNodeInfo(const uint256& uLedger, const uint256& uRootIndex, + uint64& uNodePrevious, uint64& uNodeNext); // // Nickname functions @@ -150,7 +150,6 @@ public: Json::Value getOwnerInfo(const uint256& uLedger, const NewcoinAddress& naAccount); Json::Value getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddress& naAccount); - // raw object operations bool findRawLedger(const uint256& ledgerHash, std::vector& rawLedger); bool findRawTransaction(const uint256& transactionHash, std::vector& rawTransaction); From ab4458ccb0c07fc841e38a3233dedacb599df5a0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 18:30:49 -0700 Subject: [PATCH 24/45] WS: add ledger_current command. --- src/WSDoor.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index b4394fb956..bea4e7ed27 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -75,7 +75,10 @@ public: Json::Value invokeCommand(const Json::Value& jvRequest); boost::unordered_set parseAccountIds(const Json::Value& jvArray); - // Commands + // Request-Response Commands + void doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest); + + // Streaming Commands void doAccountInfoSubscribe(Json::Value& jvResult, const Json::Value& jvRequest); void doAccountInfoUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest); void doAccountTransactionSubscribe(Json::Value& jvResult, const Json::Value& jvRequest); @@ -293,6 +296,10 @@ Json::Value WSConnection::invokeCommand(const Json::Value& jvRequest) const char* pCommand; doFuncPtr dfpFunc; } commandsA[] = { + // Request-Response Commands: + { "ledger_current", &WSConnection::doLedgerCurrent }, + + // Streaming commands: { "account_info_subscribe", &WSConnection::doAccountInfoSubscribe }, { "account_info_unsubscribe", &WSConnection::doAccountInfoUnsubscribe }, { "account_transaction_subscribe", &WSConnection::doAccountTransactionSubscribe }, @@ -541,6 +548,11 @@ void WSConnection::doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json } } +void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest) +{ + jvResult["ledger"] = theApp->getOPs().getCurrentLedgerID(); +} + void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) { if (!theApp->getOPs().subTransaction(this)) From dfd55c15637b696531fd38a6b152b747b7609bf2 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 18:31:56 -0700 Subject: [PATCH 25/45] UT: Add timeout to WS connecting. --- js/remote.js | 115 +++++++++++++++++++++++++++++++--------- test/server.js | 3 ++ test/standalone-test.js | 63 +++++++++++++++++----- 3 files changed, 144 insertions(+), 37 deletions(-) diff --git a/js/remote.js b/js/remote.js index 8903c87472..016679718e 100644 --- a/js/remote.js +++ b/js/remote.js @@ -4,65 +4,132 @@ // http://www.w3.org/TR/websockets/#the-websocket-interface // // YYY Will later provide a network access which use multiple instances of this. +// YYY A better model might be to allow requesting a target state: keep connected or not. // var util = require('util'); var WebSocket = require('ws'); -// YYY This is wrong should not use anything in test directory. -var config = require("../test/config.js"); - // --> trusted: truthy, if remote is trusted -var Remote = function(trusted, websocket_ip, websocket_port) { +var Remote = function(trusted, websocket_ip, websocket_port, trace) { this.trusted = trusted; this.websocket_ip = websocket_ip; this.websocket_port = websocket_port; this.id = 0; + this.trace = trace; }; -var remoteConfig = function(server) { +var remoteConfig = function(config, server) { var serverConfig = config.servers[server]; return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port); }; -// Target state is connectted. -// done(readyState): -// --> readyState: OPEN, CLOSED -Remote.method('connect', function(done, onmessage) { - var url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); +Remote.method('connect_helper', function() { + var self = this; - console.log("remote: connect: %s", url); + if (this.trace) + console.log("remote: connect: %s", this.url); - this.ws = new WebSocket(url); + this.ws = new WebSocket(this.url); var ws = this.ws; - ws.onopen = function() { - console.log("remote: onopen: %s", ws.readyState); - ws.onclose = undefined; - done(ws.readyState); + ws.onopen = function() { + if (this.trace) + console.log("remote: onopen: %s", ws.readyState); + + ws.onclose = undefined; + ws.onerror = undefined; + + self.done(ws.readyState); }; - // Also covers failure to open. - ws.onclose = function() { - console.log("remote: onclose: %s", ws.readyState); - done(ws.readyState); + ws.onerror = function() { + if (this.trace) + console.log("remote: onerror: %s", ws.readyState); + + ws.onclose = undefined; + + if (self.expire) { + if (this.trace) + console.log("remote: was expired"); + + self.done(ws.readyState); + } + else + { + // Delay and retry. + setTimeout(function() { + if (this.trace) + console.log("remote: retry"); + + self.connect_helper(); + }, 50); // Retry rate 50ms. + } }; - if (onmessage) { - ws.onmessage = onmessage; + // Covers failure to open. + ws.onclose = function() { + if (this.trace) + console.log("remote: onclose: %s", ws.readyState); + + ws.onerror = undefined; + + self.done(ws.readyState); + }; + + if (this.onmessage) { + ws.onmessage = this.onmessage; } }); +// Target state is connectted. +// done(readyState): +// --> readyState: OPEN, CLOSED +Remote.method('connect', function(done, onmessage, timeout) { + var self = this; + + this.url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); + this.done = done; + + if (onmessage) + this.onmessage = onmessage; + + if (timeout) { + if (this.trace) + console.log("remote: expire: false"); + + this.expire = false; + + setTimeout(function () { + if (this.trace) + console.log("remote: expire: timeout"); + + self.expire = true; + }, timeout); + } + else { + if (this.trace) + console.log("remote: expire: false"); + + this.expire = true; + } + + this.connect_helper(); + +}); + // Target stated is disconnected. Remote.method('disconnect', function(done) { var ws = this.ws; ws.onclose = function() { - console.log("remote: onclose: %s", ws.readyState); - done(ws.readyState); + if (this.trace) + console.log("remote: onclose: %s", ws.readyState); + + done(ws.readyState); }; ws.close(); diff --git a/test/server.js b/test/server.js index 0bd0f582c3..9e20569a58 100644 --- a/test/server.js +++ b/test/server.js @@ -1,4 +1,7 @@ // Manage test servers +// +// YYY Would be nice to be able to hide server output. +// // Provide servers // diff --git a/test/standalone-test.js b/test/standalone-test.js index c50e50154a..b36929eb44 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -5,8 +5,15 @@ var buster = require("buster"); var server = require("./server.js"); var remote = require("../js/remote.js"); +var config = require("./config.js"); -buster.testCase("Check standalone server startup", { +// How long to wait for server to start. +var serverDelay = 1500; + +buster.testRunner.timeout = 5000; + + +buster.testCase("Standalone server startup", { "server start and stop": function(done) { server.start("alpha", function(e) { @@ -19,14 +26,15 @@ buster.testCase("Check standalone server startup", { } }); -buster.testCase("Check websocket connection", { +buster.testCase("WebSocket connection", { 'setUp' : function(done) { server.start("alpha", function(e) { buster.refute(e); done(); - }); + } + ); }, 'tearDown' : @@ -39,24 +47,53 @@ buster.testCase("Check websocket connection", { "websocket connect and disconnect" : function(done) { - var alpha = remote.remoteConfig("alpha"); + var alpha = remote.remoteConfig(config, "alpha"); alpha.connect(function(stat) { - buster.assert(1 == stat); // OPEN + buster.assert(1 == stat); // OPEN alpha.disconnect(function(stat) { - buster.assert(3 == stat); // CLOSED + buster.assert(3 == stat); // CLOSED done(); }); - }); + }, undefined, serverDelay); }, }); -buster.testCase("Check assert", { - "assert" : - function() { - buster.assert(true); - } -}); +// var alpha = remote.remoteConfig("alpha"); +// +// buster.testCase("Websocket commands", { +// 'setUp' : +// function(done) { +// server.start("alpha", +// function(e) { +// buster.refute(e); +// +// alpha.connect(function(stat) { +// buster.assert(1 == stat); // OPEN +// +// done(); +// }); +// }); +// }, +// +// 'tearDown' : +// function(done) { +// alpha.disconnect(function(stat) { +// buster.assert(3 == stat); // CLOSED +// +// server.stop("alpha", function(e) { +// buster.refute(e); +// +// done(); +// }); +// }); +// }, +// +// "assert" : +// function() { +// buster.assert(true); +// } +// }); // vim:ts=4 From 2e5189f276553cd6aaae8c5a35a400e7842ce172 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 19:36:38 -0700 Subject: [PATCH 26/45] JS: Get request-respons and ledger_current working. --- js/remote.js | 56 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/js/remote.js b/js/remote.js index 016679718e..d1fa4430cc 100644 --- a/js/remote.js +++ b/js/remote.js @@ -20,10 +20,10 @@ var Remote = function(trusted, websocket_ip, websocket_port, trace) { this.trace = trace; }; -var remoteConfig = function(config, server) { +var remoteConfig = function(config, server, trace) { var serverConfig = config.servers[server]; - return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port); + return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port, trace); }; Remote.method('connect_helper', function() { @@ -36,6 +36,8 @@ Remote.method('connect_helper', function() { var ws = this.ws; + ws.response = {}; + ws.onopen = function() { if (this.trace) console.log("remote: onopen: %s", ws.readyState); @@ -80,23 +82,36 @@ Remote.method('connect_helper', function() { self.done(ws.readyState); }; - if (this.onmessage) { - ws.onmessage = this.onmessage; - } + // XXX Why doesn't onmessage work? + ws.on('message', function(json, flags) { + var message = JSON.parse(json); + // console.log("message: %s", json); + + if (message.type !== 'response') { + console.log("unexpected message: %s", json); + + } else { + var done = ws.response[message.id]; + + if (done) { + done(message); + + } else { + console.log("unexpected message id: %s", json); + } + } + }); }); // Target state is connectted. // done(readyState): // --> readyState: OPEN, CLOSED -Remote.method('connect', function(done, onmessage, timeout) { +Remote.method('connect', function(done, timeout) { var self = this; this.url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); this.done = done; - if (onmessage) - this.onmessage = onmessage; - if (timeout) { if (this.trace) console.log("remote: expire: false"); @@ -146,14 +161,15 @@ Remote.method('request', function(command, done) { ws.response[command.id] = done; - ws.send(command); + if (this.trace) + console.log("remote: send: %s", JSON.stringify(command)); + + ws.send(JSON.stringify(command)); }); -// Request the current ledger. -// done(index) -// index: undefined = error -Remote.method('ledger', function(done) { - +// Get the current ledger entry (may be live or not). +Remote.method('ledger_current', function(done) { + this.request({ 'command' : 'ledger_current' }, done); }); @@ -166,20 +182,12 @@ Remote.method('submit', function(json, done) { // }); }); -// ==> entry_spec -Remote.method('ledger_entry', function(entry_spec, done) { - entry_spec.command = 'ledger_entry'; - - this.request(entry_spec, function() { - }); -}); - // done(value) // --> value: { 'status', status, 'result' : result, ... } // done may be called up to 3 times. Remote.method('account_root', function(account_id, done) { this.request({ - 'command' : 'ledger_entry', + 'command' : 'ledger_current', }, function() { }); }); From 5a49b696ad1ae6395d04f8300fc37a5fe4bba554 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 19:37:15 -0700 Subject: [PATCH 27/45] UT: Get WS ledger_current test working. --- test/standalone-test.js | 81 ++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/test/standalone-test.js b/test/standalone-test.js index b36929eb44..2a725dffac 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -12,7 +12,6 @@ var serverDelay = 1500; buster.testRunner.timeout = 5000; - buster.testCase("Standalone server startup", { "server start and stop": function(done) { server.start("alpha", @@ -56,44 +55,52 @@ buster.testCase("WebSocket connection", { buster.assert(3 == stat); // CLOSED done(); }); - }, undefined, serverDelay); + }, serverDelay); }, }); -// var alpha = remote.remoteConfig("alpha"); -// -// buster.testCase("Websocket commands", { -// 'setUp' : -// function(done) { -// server.start("alpha", -// function(e) { -// buster.refute(e); -// -// alpha.connect(function(stat) { -// buster.assert(1 == stat); // OPEN -// -// done(); -// }); -// }); -// }, -// -// 'tearDown' : -// function(done) { -// alpha.disconnect(function(stat) { -// buster.assert(3 == stat); // CLOSED -// -// server.stop("alpha", function(e) { -// buster.refute(e); -// -// done(); -// }); -// }); -// }, -// -// "assert" : -// function() { -// buster.assert(true); -// } -// }); +// XXX Figure out a way to stuff this into the test case. +var alpha; + +buster.testCase("Websocket commands", { + 'setUp' : + function(done) { + server.start("alpha", + function(e) { + buster.refute(e); + + alpha = remote.remoteConfig(config, "alpha"); + + alpha.connect(function(stat) { + buster.assert(1 == stat); // OPEN + + done(); + }, serverDelay); + }); + }, + + 'tearDown' : + function(done) { + alpha.disconnect(function(stat) { + buster.assert(3 == stat); // CLOSED + + server.stop("alpha", function(e) { + buster.refute(e); + + done(); + }); + }); + }, + + "ledger_current" : + function(done) { + alpha.ledger_current(function (r) { + console.log(r); + + buster.assert(r.ledger === 2); + done(); + }); + } +}); // vim:ts=4 From 73e4a73f954d9a270db9ab2d870683550bc29407 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 14:07:07 -0700 Subject: [PATCH 28/45] getLedgerID to NetworkOPs. --- src/NetworkOPs.cpp | 5 +++++ src/NetworkOPs.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 0433892263..38a43580db 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -67,6 +67,11 @@ void NetworkOPs::closeTimeOffset(int offset) Log(lsINFO) << "Close time offset now " << mCloseTimeOffset; } +uint32 NetworkOPs::getLedgerID(const uint256& hash) +{ + return mLedgerMaster->getLedgerByHash(hash)->getLedgerSeq(); +} + uint32 NetworkOPs::getCurrentLedgerID() { return mLedgerMaster->getCurrentLedger()->getLedgerSeq(); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 43b7da9f4e..b62a362bec 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -96,6 +96,7 @@ public: uint32 getValidationTimeNC(); void closeTimeOffset(int); boost::posix_time::ptime getNetworkTimePT(); + uint32 getLedgerID(const uint256& hash); uint32 getCurrentLedgerID(); OperatingMode getOperatingMode() { return mMode; } inline bool available() { From 4cec959e78cf1830eebe547130ef37924a025848 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 14:08:10 -0700 Subject: [PATCH 29/45] WS add command ledger_closed and revise ledger_current. --- src/WSDoor.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index bea4e7ed27..a44ee9098e 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -76,7 +76,9 @@ public: boost::unordered_set parseAccountIds(const Json::Value& jvArray); // Request-Response Commands + void doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest); void doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest); + void doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest); // Streaming Commands void doAccountInfoSubscribe(Json::Value& jvResult, const Json::Value& jvRequest); @@ -297,7 +299,9 @@ Json::Value WSConnection::invokeCommand(const Json::Value& jvRequest) doFuncPtr dfpFunc; } commandsA[] = { // Request-Response Commands: - { "ledger_current", &WSConnection::doLedgerCurrent }, + { "ledger_closed", &WSConnection::doLedgerClosed }, + { "ledger_current", &WSConnection::doLedgerCurrent }, + { "ledger_entry", &WSConnection::doLedgerEntry }, // Streaming commands: { "account_info_subscribe", &WSConnection::doAccountInfoSubscribe }, @@ -548,9 +552,55 @@ void WSConnection::doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json } } +void WSConnection::doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest) +{ + uint256 uLedger = theApp->getOPs().getClosedLedger(); + + jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger); + jvResult["ledger"] = uLedger.ToString(); +} + void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest) { - jvResult["ledger"] = theApp->getOPs().getCurrentLedgerID(); + jvResult["ledger_index"] = theApp->getOPs().getCurrentLedgerID(); +} + +void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest) +{ + // Get from request. + uint256 uLedger; + + jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger); + jvResult["ledger"] = uLedger.ToString(); + + if (jvRequest.isMember("index")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("account_root")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("directory")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("generator")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("offer")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("ripple_state")) + { + jvResult["error"] = "notImplemented"; + } + else + { + jvResult["error"] = "unknownOption"; + } } void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) From 8993c8f26838f9773f5d68f9f6ed80870b458fb7 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 14:08:56 -0700 Subject: [PATCH 30/45] UT add testing for ledger_closed and update ledger_current. --- js/remote.js | 10 +++++-- test/standalone-test.js | 66 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/js/remote.js b/js/remote.js index d1fa4430cc..c98129d102 100644 --- a/js/remote.js +++ b/js/remote.js @@ -82,7 +82,7 @@ Remote.method('connect_helper', function() { self.done(ws.readyState); }; - // XXX Why doesn't onmessage work? + // Node's ws module doesn't pass arguments to onmessage. ws.on('message', function(json, flags) { var message = JSON.parse(json); // console.log("message: %s", json); @@ -167,12 +167,16 @@ Remote.method('request', function(command, done) { ws.send(JSON.stringify(command)); }); -// Get the current ledger entry (may be live or not). +Remote.method('ledger_closed', function(done) { + this.request({ 'command' : 'ledger_closed' }, done); +}); + +// Get the current proposed ledger entry. May be closed (and revised) at any time (even before returning). +// Only for use by unit tests. Remote.method('ledger_current', function(done) { this.request({ 'command' : 'ledger_current' }, done); }); - // Submit a json transaction. // done(value) // <-> value: { 'status', status, 'result' : result, ... } diff --git a/test/standalone-test.js b/test/standalone-test.js index 2a725dffac..92289ffcfc 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -92,15 +92,75 @@ buster.testCase("Websocket commands", { }); }, - "ledger_current" : + 'ledger_closed' : + function(done) { + alpha.ledger_closed(function (r) { + console.log(r); + + buster.assert(r.ledger === 1); + done(); + }); + }, + + 'ledger_current' : function(done) { alpha.ledger_current(function (r) { console.log(r); - buster.assert(r.ledger === 2); + buster.assert.equals(r.ledger_index, 2); done(); }); - } + }, + + 'ledger_closed' : + function(done) { + alpha.ledger_closed(function (r) { + console.log("result: %s", JSON.stringify(r)); + + buster.assert.equals(r.ledger_index, 1); + done(); + }); + }, }); +buster.testCase("// Work in progress", { + 'setUp' : + function(done) { + server.start("alpha", + function(e) { + buster.refute(e); + + alpha = remote.remoteConfig(config, "alpha"); + + alpha.connect(function(stat) { + buster.assert(1 == stat); // OPEN + + done(); + }, serverDelay); + }); + }, + + 'tearDown' : + function(done) { + alpha.disconnect(function(stat) { + buster.assert(3 == stat); // CLOSED + + server.stop("alpha", function(e) { + buster.refute(e); + + done(); + }); + }); + }, + + 'ledger_closed' : + function(done) { + alpha.ledger_closed(function (r) { + console.log("result: %s", JSON.stringify(r)); + + buster.assert.equals(r.ledger_index, 1); + done(); + }); + }, +}); // vim:ts=4 From f3f116117a13897a1bb93f8d457884c1a8438ee3 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 15:01:21 -0700 Subject: [PATCH 31/45] Make genesis ledger 1. --- src/Ledger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index b419a493fc..e650f9b94f 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -21,7 +21,7 @@ #include "Log.h" -Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(0), +Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1), mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false), mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap()) From be54bf070c06d3c4786e6a9464b98734ee9d508d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 15:02:17 -0700 Subject: [PATCH 32/45] Make getLedgerByHash(0) return the current ledger. --- src/LedgerMaster.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index 37db69c5c2..76e6327381 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -66,10 +66,15 @@ public: Ledger::pointer getLedgerByHash(const uint256& hash) { + if (!hash) + return mCurrentLedger; + if (mCurrentLedger && (mCurrentLedger->getHash() == hash)) return mCurrentLedger; + if (mFinalizedLedger && (mFinalizedLedger->getHash() == hash)) return mFinalizedLedger; + return mLedgerHistory.getLedgerByHash(hash); } From cae6ea1c3356d91191614062340bafb61093b334 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 15:03:19 -0700 Subject: [PATCH 33/45] Remove useless NetworkOPs::getClosedLedger. --- src/NetworkOPs.cpp | 4 ++- src/NetworkOPs.h | 5 --- src/RPCServer.cpp | 82 ++++++++++++++++++---------------------------- 3 files changed, 35 insertions(+), 56 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 38a43580db..9988a03925 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -69,7 +69,9 @@ void NetworkOPs::closeTimeOffset(int offset) uint32 NetworkOPs::getLedgerID(const uint256& hash) { - return mLedgerMaster->getLedgerByHash(hash)->getLedgerSeq(); + Ledger::ref lrLedger = mLedgerMaster->getLedgerByHash(hash); + + return lrLedger ? lrLedger->getLedgerSeq() : 0; } uint32 NetworkOPs::getCurrentLedgerID() diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index b62a362bec..c22c6b63cd 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -107,11 +107,6 @@ public: uint256 getClosedLedger() { return mLedgerMaster->getClosedLedger()->getHash(); } - // FIXME: This function is basically useless since the hash is constantly changing and the ledger - // is ephemeral and mutable. - uint256 getCurrentLedger() - { return mLedgerMaster->getCurrentLedger()->getHash(); } - // // Transaction operations // diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index cd79010c4a..a2d81512ab 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -422,7 +422,6 @@ Json::Value RPCServer::doAccountDomainSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -438,7 +437,7 @@ Json::Value RPCServer::doAccountDomainSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -476,7 +475,6 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -492,7 +490,7 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -569,12 +567,11 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) ret["accepted"] = jAccepted; - uint256 uCurrent = mNetOps->getCurrentLedger(); - Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + Json::Value jCurrent = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex); if (jCurrent.empty()) { - AccountState::pointer asCurrent = mNetOps->getAccountState(uCurrent, naAccount); + AccountState::pointer asCurrent = mNetOps->getAccountState(uint256(0), naAccount); if (asCurrent) asCurrent->addJson(jCurrent); @@ -598,7 +595,6 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); NewcoinAddress naMessagePubKey; if (!naSeed.setSeedGeneric(params[0u].asString())) @@ -619,7 +615,7 @@ Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) { NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); std::vector vucDomain; @@ -659,7 +655,6 @@ Json::Value RPCServer::doAccountPublishSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -675,7 +670,7 @@ Json::Value RPCServer::doAccountPublishSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -717,7 +712,6 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -733,7 +727,7 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -773,7 +767,6 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value ¶ms) Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -789,7 +782,7 @@ Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) { NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); std::vector vucDomain; @@ -921,8 +914,6 @@ Json::Value RPCServer::doDataStore(const Json::Value& params) // Note: Nicknames are not automatically looked up by commands as they are advisory and can be changed. Json::Value RPCServer::doNicknameInfo(const Json::Value& params) { - uint256 uLedger = mNetOps->getCurrentLedger(); - std::string strNickname = params[0u].asString(); boost::trim(strNickname); @@ -931,7 +922,7 @@ Json::Value RPCServer::doNicknameInfo(const Json::Value& params) return RPCError(rpcNICKNAME_MALFORMED); } - NicknameState::pointer nsSrc = mNetOps->getNicknameState(uLedger, strNickname); + NicknameState::pointer nsSrc = mNetOps->getNicknameState(uint256(0), strNickname); if (!nsSrc) { return RPCError(rpcNICKNAME_MISSING); @@ -951,7 +942,6 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -979,7 +969,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) } STAmount saFee; - NicknameState::pointer nsSrc = mNetOps->getNicknameState(uLedger, strNickname); + NicknameState::pointer nsSrc = mNetOps->getNicknameState(uint256(0), strNickname); if (!nsSrc) { @@ -1002,7 +992,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1068,7 +1058,7 @@ Json::Value RPCServer::doOfferCreate(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1114,7 +1104,7 @@ Json::Value RPCServer::doOfferCancel(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1154,10 +1144,9 @@ Json::Value RPCServer::doOwnerInfo(const Json::Value& params) ret["accepted"] = jAccepted.empty() ? mNetOps->getOwnerInfo(uAccepted, naAccount) : jAccepted; - uint256 uCurrent = mNetOps->getCurrentLedger(); - Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + Json::Value jCurrent = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex); - ret["current"] = jCurrent.empty() ? mNetOps->getOwnerInfo(uCurrent, naAccount) : jCurrent; + ret["current"] = jCurrent.empty() ? mNetOps->getOwnerInfo(uint256(0), naAccount) : jCurrent; return ret; } @@ -1168,7 +1157,6 @@ Json::Value RPCServer::doPasswordFund(const Json::Value ¶ms) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -1188,7 +1176,7 @@ Json::Value RPCServer::doPasswordFund(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1494,8 +1482,7 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) return RPCError(rpcDST_AMT_MALFORMED); } - uint256 uLedger = mNetOps->getCurrentLedger(); - AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); + AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID); STAmount saFee = theConfig.FEE_DEFAULT; NewcoinAddress naVerifyGenerator; @@ -1503,7 +1490,7 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -1556,7 +1543,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; STAmount saLimitAmount; - uint256 uLedger = mNetOps->getCurrentLedger(); bool bLimitAmount = true; bool bQualityIn = params.size() >= 6; bool bQualityOut = params.size() >= 7; @@ -1594,7 +1580,7 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1627,7 +1613,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) { // uint256 uAccepted = mNetOps->getClosedLedger(); - uint256 uCurrent = mNetOps->getCurrentLedger(); std::string strIdent = params[0u].asString(); bool bIndex; @@ -1637,7 +1622,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) Json::Value ret; - ret = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + ret = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex); if (!ret.empty()) return ret; @@ -1649,7 +1634,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) if (bIndex) ret["index"] = iIndex; - AccountState::pointer as = mNetOps->getAccountState(uCurrent, naAccount); + AccountState::pointer as = mNetOps->getAccountState(uint256(0), naAccount); if (as) { Json::Value jsonLines(Json::arrayValue); @@ -1739,8 +1724,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) } else { - uint256 uLedger = mNetOps->getCurrentLedger(); - AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); + AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID); bool bCreate = !asDst; STAmount saFee = bCreate ? theConfig.FEE_ACCOUNT_CREATE : theConfig.FEE_DEFAULT; @@ -1749,7 +1733,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naVerifyGenerator); // Log(lsINFO) << boost::str(boost::format("doSend: sSrcIssuer=%s sDstIssuer=%s saSrcAmountMax=%s saDstAmount=%s") @@ -2081,7 +2065,6 @@ Json::Value RPCServer::accounts(const uint256& uLedger, const NewcoinAddress& na Json::Value RPCServer::doWalletAccounts(const Json::Value& params) { NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -2091,17 +2074,17 @@ Json::Value RPCServer::doWalletAccounts(const Json::Value& params) // Try the seed as a master seed. NewcoinAddress naMasterGenerator = NewcoinAddress::createGeneratorPublic(naSeed); - Json::Value jsonAccounts = accounts(uLedger, naMasterGenerator); + Json::Value jsonAccounts = accounts(uint256(0), naMasterGenerator); if (jsonAccounts.empty()) { // No account via seed as master, try seed a regular. - Json::Value ret = getMasterGenerator(uLedger, naSeed, naMasterGenerator); + Json::Value ret = getMasterGenerator(uint256(0), naSeed, naMasterGenerator); if (!ret.empty()) return ret; - ret["accounts"] = accounts(uLedger, naMasterGenerator); + ret["accounts"] = accounts(uint256(0), naMasterGenerator); return ret; } @@ -2124,7 +2107,6 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) NewcoinAddress naSrcAccountID; STAmount saAmount; std::string sDstCurrency; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naRegularSeed.setSeedGeneric(params[0u].asString())) { @@ -2151,7 +2133,7 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator); if (!obj.empty()) @@ -2177,7 +2159,7 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) ++iIndex; naNewAccountPublic.setAccountPublic(naMasterGenerator, iIndex); - asNew = mNetOps->getAccountState(uLedger, naNewAccountPublic); + asNew = mNetOps->getAccountState(uint256(0), naNewAccountPublic); if (!asNew) bAgain = false; } while (bAgain); @@ -2312,7 +2294,6 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -2326,7 +2307,7 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) { return RPCError(rpcDST_ACT_MALFORMED); } - else if (mNetOps->getAccountState(uLedger, naDstAccountID)) + else if (mNetOps->getAccountState(uint256(0), naDstAccountID)) { return RPCError(rpcACT_EXISTS); } @@ -2339,7 +2320,7 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator); if (!obj.empty()) @@ -2602,7 +2583,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { return RPCError(rpcNO_NETWORK); } - else if ((commandsA[i].iOptions & optCurrent) && mNetOps->getCurrentLedger().isZero()) + // XXX Should verify we have a current ledger. + else if ((commandsA[i].iOptions & optCurrent) && false) { return RPCError(rpcNO_CURRENT); } From 20815377b47b3b140575da3712751d9afad261a7 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 15:07:03 -0700 Subject: [PATCH 34/45] Adjust UTs for genesis 1. --- test/standalone-test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/standalone-test.js b/test/standalone-test.js index 92289ffcfc..ffa593840d 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -107,7 +107,7 @@ buster.testCase("Websocket commands", { alpha.ledger_current(function (r) { console.log(r); - buster.assert.equals(r.ledger_index, 2); + buster.assert.equals(r.ledger_index, 3); done(); }); }, @@ -117,7 +117,7 @@ buster.testCase("Websocket commands", { alpha.ledger_closed(function (r) { console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.ledger_index, 1); + buster.assert.equals(r.ledger_index, 2); done(); }); }, @@ -158,7 +158,7 @@ buster.testCase("// Work in progress", { alpha.ledger_closed(function (r) { console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.ledger_index, 1); + buster.assert.equals(r.ledger_index, 2); done(); }); }, From b491b9925521d8577ec5b8d5d40baf02a2295a4d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 13:08:59 -0700 Subject: [PATCH 35/45] Rework NetworkOPs to return Ledger:pointer. --- src/NetworkOPs.h | 6 ++++++ src/NewcoinAddress.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index c22c6b63cd..cc84f9f89a 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -104,9 +104,15 @@ public: return mMode >= omTRACKING; } + Ledger::pointer getCurrentLedger() { return mLedgerMaster->getCurrentLedger(); } + Ledger::pointer getLedgerByHash(const uint256& hash) { return mLedgerMaster->getLedgerByHash(hash); } + Ledger::pointer getLedgerBySeq(const uint32 seq) { return mLedgerMaster->getLedgerBySeq(seq); } + uint256 getClosedLedger() { return mLedgerMaster->getClosedLedger()->getHash(); } + SLE::pointer getSLE(Ledger::pointer lpLedger, const uint256& uHash) { return lpLedger->getSLE(uHash); } + // // Transaction operations // diff --git a/src/NewcoinAddress.h b/src/NewcoinAddress.h index 369b609d04..707a976c52 100644 --- a/src/NewcoinAddress.h +++ b/src/NewcoinAddress.h @@ -73,6 +73,9 @@ public: bool setAccountID(const std::string& strAccountID); void setAccountID(const uint160& hash160In); + static NewcoinAddress createAccountID(const std::string& strAccountID) + { NewcoinAddress na; na.setAccountID(strAccountID); return na; } + static NewcoinAddress createAccountID(const uint160& uiAccountID); static std::string createHumanAccountID(const uint160& uiAccountID) From ff245609ac4ead2b7b329d7306fed9c9551d548c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 13:09:57 -0700 Subject: [PATCH 36/45] WS: Add support for ledger_entry to return an account_root. --- js/remote.js | 23 ++++++----- src/WSDoor.cpp | 66 ++++++++++++++++++++++++++++--- test/standalone-test.js | 88 +++++++++++++++++++++-------------------- 3 files changed, 119 insertions(+), 58 deletions(-) diff --git a/js/remote.js b/js/remote.js index c98129d102..ffab43eaad 100644 --- a/js/remote.js +++ b/js/remote.js @@ -168,6 +168,8 @@ Remote.method('request', function(command, done) { }); Remote.method('ledger_closed', function(done) { + assert(this.trusted); // If not trusted, need to check proof. + this.request({ 'command' : 'ledger_closed' }, done); }); @@ -177,6 +179,17 @@ Remote.method('ledger_current', function(done) { this.request({ 'command' : 'ledger_current' }, done); }); +// <-> params: +// --> ledger : optional +// --> ledger_index : optional +Remote.method('ledger_entry', function(params, done) { + assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol. + + params.command = 'ledger_entry'; + + this.request(params, done); +}); + // Submit a json transaction. // done(value) // <-> value: { 'status', status, 'result' : result, ... } @@ -186,16 +199,6 @@ Remote.method('submit', function(json, done) { // }); }); -// done(value) -// --> value: { 'status', status, 'result' : result, ... } -// done may be called up to 3 times. -Remote.method('account_root', function(account_id, done) { - this.request({ - 'command' : 'ledger_current', - }, function() { - }); -}); - exports.Remote = Remote; exports.remoteConfig = remoteConfig; diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index a44ee9098e..ae63b02129 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -567,11 +567,46 @@ void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvR void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest) { - // Get from request. - uint256 uLedger; + NetworkOPs& noNetwork = theApp->getOPs(); + uint256 uLedger = jvRequest.isMember("ledger") ? uint256(jvRequest["ledger"].asString()) : 0; + uint32 uLedgerIndex = jvRequest.isMember("ledger_index") && jvRequest["ledger_index"].isNumeric() ? jvRequest["ledger_index"].asUInt() : 0; - jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger); - jvResult["ledger"] = uLedger.ToString(); + Ledger::pointer lpLedger; + + if (!!uLedger) + { + // Ledger directly specified. + lpLedger = noNetwork.getLedgerByHash(uLedger); + + if (!lpLedger) + { + jvResult["error"] = "ledgerNotFound"; + return; + } + + uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index, override if needed. + } + else if (!!uLedgerIndex) + { + lpLedger = noNetwork.getLedgerBySeq(uLedgerIndex); + + if (!lpLedger) + { + jvResult["error"] = "ledgerNotFound"; // ledger_index from future? + return; + } + } + else + { + // Default to current ledger. + lpLedger = noNetwork.getCurrentLedger(); + uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index. + } + + if (!!uLedger) + jvResult["ledger"] = uLedger.ToString(); + + jvResult["ledger_index"] = uLedgerIndex; if (jvRequest.isMember("index")) { @@ -579,7 +614,28 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("account_root")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naAccount = NewcoinAddress::createAccountID(jvRequest["account_root"].asString()); + + if (!naAccount.isValid()) + { + jvResult["error"] = "malformedAddress"; + return; + } + + uint256 accountRootIndex = Ledger::getAccountRootIndex(naAccount.getAccountID()); + + SLE::pointer sleNode = noNetwork.getSLE(lpLedger, accountRootIndex); + + if (!sleNode) + { + // Not found. + // XXX We should also provide proof. + jvResult["error"] = "entryNotFound"; + } + else + { + jvResult["node"] = sleNode->getJson(0); + } } else if (jvRequest.isMember("directory")) { diff --git a/test/standalone-test.js b/test/standalone-test.js index ffa593840d..a3fb947498 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -1,5 +1,3 @@ -// console.log("standalone-test.js>"); - var fs = require("fs"); var buster = require("buster"); @@ -59,9 +57,6 @@ buster.testCase("WebSocket connection", { }, }); -// XXX Figure out a way to stuff this into the test case. -var alpha; - buster.testCase("Websocket commands", { 'setUp' : function(done) { @@ -92,16 +87,6 @@ buster.testCase("Websocket commands", { }); }, - 'ledger_closed' : - function(done) { - alpha.ledger_closed(function (r) { - console.log(r); - - buster.assert(r.ledger === 1); - done(); - }); - }, - 'ledger_current' : function(done) { alpha.ledger_current(function (r) { @@ -112,7 +97,7 @@ buster.testCase("Websocket commands", { }); }, - 'ledger_closed' : + '// ledger_closed' : function(done) { alpha.ledger_closed(function (r) { console.log("result: %s", JSON.stringify(r)); @@ -121,46 +106,63 @@ buster.testCase("Websocket commands", { done(); }); }, -}); -buster.testCase("// Work in progress", { - 'setUp' : + 'account_root success' : function(done) { - server.start("alpha", - function(e) { - buster.refute(e); + alpha.ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); - alpha = remote.remoteConfig(config, "alpha"); + buster.refute('error' in r); - alpha.connect(function(stat) { - buster.assert(1 == stat); // OPEN + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'account_root' : 'iHb9CJAWyB4ij91VRWn96DkukG4bwdtyTh' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + buster.assert('node' in r); done(); - }, serverDelay); - }); - }, - - 'tearDown' : - function(done) { - alpha.disconnect(function(stat) { - buster.assert(3 == stat); // CLOSED - - server.stop("alpha", function(e) { - buster.refute(e); - - done(); - }); + }); }); }, - 'ledger_closed' : + 'account_root malformedAddress' : function(done) { alpha.ledger_closed(function (r) { - console.log("result: %s", JSON.stringify(r)); + // console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.ledger_index, 2); - done(); + buster.refute('error' in r); + + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'account_root' : 'foobar' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + + buster.assert.equals(r.error, 'malformedAddress'); + done(); + }); + }); + }, + + 'account_root entryNotFound' : + function(done) { + alpha.ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); + + buster.refute('error' in r); + + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'account_root' : 'iG1QQv2nh2gi7RCZ1P8YYcBUKCCN633jCn' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + + buster.assert.equals(r.error, 'entryNotFound'); + done(); + }); }); }, }); + // vim:ts=4 From 22c22bd734e0dd04da84a46a34065c8d8be49779 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 13:36:04 -0700 Subject: [PATCH 37/45] WS: Add support ledger_entry to return a ripple_state. --- src/Amount.cpp | 1 + src/WSDoor.cpp | 58 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index f0692f2af7..637d4ef52d 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -12,6 +12,7 @@ uint64 STAmount::uRateOne = STAmount::getRate(STAmount(1), STAmount(1)); +// --> sCurrency: "", "XNS", or three letter ISO code. bool STAmount::currencyFromString(uint160& uDstCurrency, const std::string& sCurrency) { bool bSuccess = true; diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index ae63b02129..7e6960b831 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -608,33 +608,23 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq jvResult["ledger_index"] = uLedgerIndex; + uint256 uNodeIndex; + if (jvRequest.isMember("index")) { jvResult["error"] = "notImplemented"; } else if (jvRequest.isMember("account_root")) { - NewcoinAddress naAccount = NewcoinAddress::createAccountID(jvRequest["account_root"].asString()); + NewcoinAddress naAccount; - if (!naAccount.isValid()) + if (!naAccount.setAccountID(jvRequest["account_root"].asString())) { jvResult["error"] = "malformedAddress"; - return; - } - - uint256 accountRootIndex = Ledger::getAccountRootIndex(naAccount.getAccountID()); - - SLE::pointer sleNode = noNetwork.getSLE(lpLedger, accountRootIndex); - - if (!sleNode) - { - // Not found. - // XXX We should also provide proof. - jvResult["error"] = "entryNotFound"; } else { - jvResult["node"] = sleNode->getJson(0); + uNodeIndex = Ledger::getAccountRootIndex(naAccount.getAccountID()); } } else if (jvRequest.isMember("directory")) @@ -651,12 +641,48 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("ripple_state")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naA; + NewcoinAddress naB; + uint160 uCurrency; + + if (!jvRequest.isMember("accounts") + || !jvRequest.isMember("currency") + || !jvRequest["accounts"].isArray() + || 2 != jvRequest["accounts"].size()) { + jvResult["error"] = "malformedRequest"; + } + else if (!naA.setAccountID(jvRequest["accounts"][0u].asString()) + || !naB.setAccountID(jvRequest["accounts"][1u].asString())) { + jvResult["error"] = "malformedAddress"; + } + else if (!STAmount::currencyFromString(uCurrency, jvRequest["currency"].asString())) { + jvResult["error"] = "malformedCurrency"; + } + else + { + uNodeIndex = Ledger::getRippleStateIndex(naA, naB, uCurrency); + } } else { jvResult["error"] = "unknownOption"; } + + if (!!uNodeIndex) + { + SLE::pointer sleNode = noNetwork.getSLE(lpLedger, uNodeIndex); + + if (!sleNode) + { + // Not found. + // XXX We should also provide proof. + jvResult["error"] = "entryNotFound"; + } + else + { + jvResult["node"] = sleNode->getJson(0); + } + } } void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) From 1ffe841be589562d9739de5216fa08dfc13f21dc Mon Sep 17 00:00:00 2001 From: MJK Date: Thu, 27 Sep 2012 13:49:37 -0700 Subject: [PATCH 38/45] add simple log rotating, tentative Ripple pathfinder work --- newcoind.cfg | 2 +- src/Log.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/Log.h | 7 +++++++ src/RPCServer.cpp | 21 +++++++++++++++++++++ src/RPCServer.h | 2 ++ src/main.cpp | 1 + websocketpp | 2 +- 7 files changed, 79 insertions(+), 2 deletions(-) diff --git a/newcoind.cfg b/newcoind.cfg index ac87d7aa8d..689b276923 100644 --- a/newcoind.cfg +++ b/newcoind.cfg @@ -119,7 +119,7 @@ 1 [debug_logfile] -debug.log +log/debug.log [sntp_servers] time.windows.com diff --git a/src/Log.cpp b/src/Log.cpp index bdd56959b2..948552cbf9 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -10,6 +10,8 @@ boost::recursive_mutex Log::sLock; LogSeverity Log::sMinSeverity = lsINFO; std::ofstream* Log::outStream = NULL; +boost::filesystem::path *Log::pathToLog = NULL; +uint32 Log::logRotateCounter = 0; Log::~Log() { @@ -31,6 +33,48 @@ Log::~Log() (*outStream) << logMsg << std::endl; } + +std::string Log::rotateLog(void) +{ + boost::recursive_mutex::scoped_lock sl(sLock); + boost::filesystem::path abs_path; + std::string abs_path_str; + + uint32 failsafe = 0; + + std::string abs_new_path_str; + do { + std::string s; + std::stringstream out; + + failsafe++; + if (failsafe == std::numeric_limits::max()) { + return "unable to create new log file; too many log files!"; + } + abs_path = boost::filesystem::absolute(""); + abs_path /= *pathToLog; + abs_path_str = abs_path.parent_path().string(); + out << logRotateCounter; + s = out.str(); + + + abs_new_path_str = abs_path_str + "/" + s + + "_" + pathToLog->filename().string(); + + logRotateCounter++; + + } while (boost::filesystem::exists(boost::filesystem::path(abs_new_path_str))); + + outStream->close(); + boost::filesystem::rename(abs_path, boost::filesystem::path(abs_new_path_str)); + + + + setLogFile(*pathToLog); + + return abs_new_path_str; + +} + void Log::setMinSeverity(LogSeverity s) { boost::recursive_mutex::scoped_lock sl(sLock); @@ -52,4 +96,6 @@ void Log::setLogFile(boost::filesystem::path path) outStream = newStream; if (outStream) Log(lsINFO) << "Starting up"; + + pathToLog = new boost::filesystem::path(path); } diff --git a/src/Log.h b/src/Log.h index 7153012226..fd3db13fd3 100644 --- a/src/Log.h +++ b/src/Log.h @@ -9,6 +9,9 @@ // Ensure that we don't get value.h without writer.h #include "../json/json.h" +#include "types.h" +#include + enum LogSeverity { lsTRACE = 0, @@ -33,6 +36,9 @@ protected: mutable std::ostringstream oss; LogSeverity mSeverity; + static boost::filesystem::path *pathToLog; + static uint32 logRotateCounter; + public: Log(LogSeverity s) : mSeverity(s) { ; } @@ -51,6 +57,7 @@ public: static void setMinSeverity(LogSeverity); static void setLogFile(boost::filesystem::path); + static std::string rotateLog(void); }; #endif diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index cd79010c4a..ad845ac8f9 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -14,6 +14,11 @@ #include "Log.h" #include "RippleLines.h" +#include "Pathfinder.h" +#include "Conversion.h" + +extern uint160 humanTo160(const std::string& buf); + #include #include @@ -1795,6 +1800,16 @@ Json::Value RPCServer::doSend(const Json::Value& params) STPathSet spsPaths; + uint160 srcCurrencyID; + bool ret_b; + ret_b = false; + STAmount::currencyFromString(srcCurrencyID, sSrcCurrency); + + Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount); + + ret_b = pf.findPaths(5, 1, spsPaths); + // TODO: Nope; the above can't be right + trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, naSrcAccountID, @@ -2518,6 +2533,11 @@ Json::Value RPCServer::doLogin(const Json::Value& params) } } +Json::Value RPCServer::doLogRotate(const Json::Value& params) +{ + return Log::rotateLog(); +} + Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params) { Log(lsTRACE) << "RPC:" << command; @@ -2543,6 +2563,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, { "data_store", &RPCServer::doDataStore, 2, 2, true }, { "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork }, + { "logrotate", &RPCServer::doLogRotate, 0, 0, true, optCurrent }, { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent }, { "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent }, { "offer_create", &RPCServer::doOfferCreate, 9, 10, false, optCurrent }, diff --git a/src/RPCServer.h b/src/RPCServer.h index 33f9699b03..8d56ed55aa 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -141,6 +141,7 @@ private: Json::Value doDataFetch(const Json::Value& params); Json::Value doDataStore(const Json::Value& params); Json::Value doLedger(const Json::Value& params); + Json::Value doLogRotate(const Json::Value& params); Json::Value doNicknameInfo(const Json::Value& params); Json::Value doNicknameSet(const Json::Value& params); Json::Value doOfferCreate(const Json::Value& params); @@ -184,6 +185,7 @@ private: Json::Value doLogin(const Json::Value& params); + public: static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps) { diff --git a/src/main.cpp b/src/main.cpp index b9154261d1..4a69f9f2da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,6 +51,7 @@ void printHelp(const po::options_description& desc) cout << " data_fetch " << endl; cout << " data_store " << endl; cout << " ledger [|current|lastclosed] [full]" << endl; + cout << " logrotate " << endl; cout << " nickname_info " << endl; cout << " nickname_set [] []" << endl; cout << " offer_create [passive]" << endl; diff --git a/websocketpp b/websocketpp index f78b9df4ad..dd9899c34b 160000 --- a/websocketpp +++ b/websocketpp @@ -1 +1 @@ -Subproject commit f78b9df4adbc354f5fdf8c2c8b9e76549f977cb8 +Subproject commit dd9899c34bb1f86caf486735b136a5460b4760db From 84dd986b6e903bfb51272a2074f7ce9ef125f4f1 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 14:40:56 -0700 Subject: [PATCH 39/45] WS: Add ledger_entry option ledger. --- src/WSDoor.cpp | 20 ++++++++++++++++---- test/standalone-test.js | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index 7e6960b831..5eca83fb2d 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -609,10 +609,13 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq jvResult["ledger_index"] = uLedgerIndex; uint256 uNodeIndex; + bool bNodeBinary = false; if (jvRequest.isMember("index")) { - jvResult["error"] = "notImplemented"; + // XXX Needs to provide proof. + uNodeIndex.SetHex(jvRequest["index"].asString()); + bNodeBinary = true; } else if (jvRequest.isMember("account_root")) { @@ -675,12 +678,21 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq if (!sleNode) { // Not found. - // XXX We should also provide proof. - jvResult["error"] = "entryNotFound"; + // XXX Should also provide proof. + jvResult["error"] = "entryNotFound"; + } + else if (bNodeBinary) + { + // XXX Should also provide proof. + Serializer s; + + sleNode->add(s); + + jvResult["node_binary"] = strHex(s.peekData()); } else { - jvResult["node"] = sleNode->getJson(0); + jvResult["node"] = sleNode->getJson(0); } } } diff --git a/test/standalone-test.js b/test/standalone-test.js index a3fb947498..6a18592a42 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -163,6 +163,26 @@ buster.testCase("Websocket commands", { }); }); }, + + 'ledger_entry index' : + function(done) { + alpha.ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); + + buster.refute('error' in r); + + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'index' : "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8", + } , function (r) { + console.log("node: %s", JSON.stringify(r)); + + buster.assert('node_binary' in r); + done(); + }); + }); + }, + }); // vim:ts=4 From a584a9c2843ed332782135b3723027dda5b9365d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 15:16:38 -0700 Subject: [PATCH 40/45] WS: Add ledger_entry option offer. --- src/WSDoor.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index 5eca83fb2d..8f3a94b100 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -640,7 +640,28 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("offer")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naAccountID; + + if (!jvRequest.isObject()) + { + uNodeIndex.SetHex(jvRequest["offer"].asString()); + } + else if (!jvRequest["offer"].isMember("account") + || !jvRequest["offer"].isMember("seq") + || !jvRequest["offer"]["seq"].isIntegral()) + { + jvResult["error"] = "malformedRequest"; + } + else if (!naAccountID.setAccountID(jvRequest["offer"]["account"].asString())) + { + jvResult["error"] = "malformedAddress"; + } + else + { + uint32 uSequence = jvRequest["offer"]["seq"].asUInt(); + + uNodeIndex = Ledger::getOfferIndex(naAccountID.getAccountID(), uSequence); + } } else if (jvRequest.isMember("ripple_state")) { From da7155d8ca3f513e9283560b3b23f6aaa933aa16 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 15:42:30 -0700 Subject: [PATCH 41/45] WS: Add ledger_entry option generator. Also have ledger entry return index. --- src/WSDoor.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index 8f3a94b100..e5c68ed82e 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -636,7 +636,29 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("generator")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naGeneratorID; + + if (!jvRequest.isObject()) + { + uNodeIndex.SetHex(jvRequest["generator"].asString()); + } + else if (!jvRequest["generator"].isMember("regular_seed")) + { + jvResult["error"] = "malformedRequest"; + } + else if (!naGeneratorID.setSeedGeneric(jvRequest["generator"]["regular_seed"].asString())) + { + jvResult["error"] = "malformedAddress"; + } + else + { + NewcoinAddress na0Public; // To find the generator's index. + NewcoinAddress naGenerator = NewcoinAddress::createGeneratorPublic(naGeneratorID); + + na0Public.setAccountPublic(naGenerator, 0); + + uNodeIndex = Ledger::getGeneratorIndex(na0Public.getAccountID()); + } } else if (jvRequest.isMember("offer")) { @@ -710,10 +732,12 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq sleNode->add(s); jvResult["node_binary"] = strHex(s.peekData()); + jvResult["index"] = uNodeIndex.ToString(); } else { jvResult["node"] = sleNode->getJson(0); + jvResult["index"] = uNodeIndex.ToString(); } } } From bf36fc84bd17e405285fb1da9f914b8550bfcbb7 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 16:06:12 -0700 Subject: [PATCH 42/45] WS: Add ledger entry option directory. --- src/WSDoor.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index e5c68ed82e..1092e8c037 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -632,7 +632,50 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("directory")) { - jvResult["error"] = "notImplemented"; + + if (!jvRequest.isObject()) + { + uNodeIndex.SetHex(jvRequest["directory"].asString()); + } + else if (jvRequest["directory"].isMember("sub_index") + && !jvRequest["directory"]["sub_index"].isIntegral()) + { + jvResult["error"] = "malformedRequest"; + } + else + { + uint64 uSubIndex = jvRequest["directory"].isMember("sub_index") + ? jvRequest["directory"]["sub_index"].asUInt() + : 0; + + if (jvRequest["directory"].isMember("dir_root")) + { + uint256 uDirRoot; + + uDirRoot.SetHex(jvRequest["dir_root"].asString()); + + uNodeIndex = Ledger::getDirNodeIndex(uDirRoot, uSubIndex); + } + else if (jvRequest["directory"].isMember("owner")) + { + NewcoinAddress naOwnerID; + + if (!naOwnerID.setAccountID(jvRequest["directory"]["owner"].asString())) + { + jvResult["error"] = "malformedAddress"; + } + else + { + uint256 uDirRoot = Ledger::getOwnerDirIndex(naOwnerID.getAccountID()); + + uNodeIndex = Ledger::getDirNodeIndex(uDirRoot, uSubIndex); + } + } + else + { + jvResult["error"] = "malformedRequest"; + } + } } else if (jvRequest.isMember("generator")) { From 5b9439689043107110dee6ea4939db16e29e115d Mon Sep 17 00:00:00 2001 From: MJK Date: Thu, 27 Sep 2012 17:01:27 -0700 Subject: [PATCH 43/45] Move around to256 to uint256.h, get rid of Conversion.cpp,h --- src/Conversion.cpp | 50 ----------- src/Conversion.h | 11 --- src/Ledger.cpp | 1 - src/LedgerMaster.cpp | 1 - src/Peer.cpp | 1 - src/RPCServer.cpp | 10 +-- src/UniqueNodeList.cpp | 1 - src/uint256.h | 187 +++++++++++++++++++++-------------------- 8 files changed, 100 insertions(+), 162 deletions(-) delete mode 100644 src/Conversion.cpp delete mode 100644 src/Conversion.h diff --git a/src/Conversion.cpp b/src/Conversion.cpp deleted file mode 100644 index 7f9de9029b..0000000000 --- a/src/Conversion.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "Conversion.h" -#include "base58.h" -using namespace std; - -#if 0 - -uint160 protobufTo160(const std::string& buf) -{ - uint160 ret; - // TODO: - return(ret); -} - -uint256 protobufTo256(const std::string& hash) -{ - uint256 ret; - // TODO: - return(ret); -} - -uint160 humanTo160(const std::string& buf) -{ - vector retVec; - DecodeBase58(buf,retVec); - uint160 ret; - memcpy(ret.begin(), &retVec[0], ret.GetSerializeSize()); - - - return(ret); -} - -bool humanToPK(const std::string& buf,std::vector& retVec) -{ - return(DecodeBase58(buf,retVec)); -} - -bool u160ToHuman(uint160& buf, std::string& retStr) -{ - retStr=EncodeBase58(buf.begin(),buf.end()); - return(true); -} - -#endif - -base_uint256 uint160::to256() const -{ - uint256 m; - memcpy(m.begin(), begin(), size()); - return m; -} diff --git a/src/Conversion.h b/src/Conversion.h deleted file mode 100644 index c2ceb5339a..0000000000 --- a/src/Conversion.h +++ /dev/null @@ -1,11 +0,0 @@ -#include "uint256.h" -#include - -extern uint160 protobufTo160(const std::string& buf); -extern uint256 protobufTo256(const std::string& hash); -extern uint160 humanTo160(const std::string& buf); -extern bool humanToPK(const std::string& buf,std::vector& retVec); - - -extern bool u160ToHuman(uint160& buf, std::string& retStr); - diff --git a/src/Ledger.cpp b/src/Ledger.cpp index e650f9b94f..8d7dec92bf 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -13,7 +13,6 @@ #include "../obj/src/newcoin.pb.h" #include "PackedMessage.h" #include "Config.h" -#include "Conversion.h" #include "BitcoinUtil.h" #include "Wallet.h" #include "LedgerTiming.h" diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index abdbf12e99..e0adb16ade 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -5,7 +5,6 @@ #include "Application.h" #include "NewcoinAddress.h" -#include "Conversion.h" #include "Log.h" uint32 LedgerMaster::getCurrentLedgerIndex() diff --git a/src/Peer.cpp b/src/Peer.cpp index ea27e06c81..641a33571c 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -12,7 +12,6 @@ #include "Peer.h" #include "Config.h" #include "Application.h" -#include "Conversion.h" #include "SerializedTransaction.h" #include "utils.h" #include "Log.h" diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 7f44f1fe58..202f0e5e3d 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -6,7 +6,6 @@ #include "Application.h" #include "RPC.h" #include "Wallet.h" -#include "Conversion.h" #include "NewcoinAddress.h" #include "AccountState.h" #include "NicknameState.h" @@ -15,9 +14,6 @@ #include "RippleLines.h" #include "Pathfinder.h" -#include "Conversion.h" - -extern uint160 humanTo160(const std::string& buf); #include @@ -1783,7 +1779,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) // Destination exists, ordinary send. STPathSet spsPaths; - + /* uint160 srcCurrencyID; bool ret_b; ret_b = false; @@ -1793,7 +1789,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) ret_b = pf.findPaths(5, 1, spsPaths); // TODO: Nope; the above can't be right - + */ trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, naSrcAccountID, @@ -2544,7 +2540,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, { "data_store", &RPCServer::doDataStore, 2, 2, true }, { "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork }, - { "logrotate", &RPCServer::doLogRotate, 0, 0, true, optCurrent }, + { "logrotate", &RPCServer::doLogRotate, 0, 0, false, optCurrent }, { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent }, { "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent }, { "offer_create", &RPCServer::doOfferCreate, 9, 10, false, optCurrent }, diff --git a/src/UniqueNodeList.cpp b/src/UniqueNodeList.cpp index b5b1d2c804..96ca1b7d7d 100644 --- a/src/UniqueNodeList.cpp +++ b/src/UniqueNodeList.cpp @@ -2,7 +2,6 @@ // XXX Want a limit of 2000 validators. #include "Application.h" -#include "Conversion.h" #include "HttpsClient.h" #include "Log.h" #include "ParseSection.h" diff --git a/src/uint256.h b/src/uint256.h index bb11b101b4..3e2ab10e62 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -386,96 +386,6 @@ public: }; -////////////////////////////////////////////////////////////////////////////// -// -// uint160 -// - -class uint160 : public base_uint160 -{ -public: - typedef base_uint160 basetype; - - uint160() - { - zero(); - } - - uint160(const basetype& b) - { - *this = b; - } - - uint160& operator=(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - - return *this; - } - - uint160(uint64 b) - { - *this = b; - } - - uint160& operator=(uint64 uHost) - { - zero(); - - // Put in least significant bits. - ((uint64_t *) end())[-1] = htobe64(uHost); - - return *this; - } - - explicit uint160(const std::string& str) - { - SetHex(str); - } - - explicit uint160(const std::vector& vch) - { - if (vch.size() == sizeof(pn)) - memcpy(pn, &vch[0], sizeof(pn)); - else - zero(); - } - - base_uint256 to256() const; -}; - -inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; } -inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; } - -inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } -inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } -inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } - -inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } - -inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } -inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } - -extern std::size_t hash_value(const uint160&); - -inline const std::string strHex(const uint160& ui) -{ - return strHex(ui.begin(), ui.size()); -} - ////////////////////////////////////////////////////////////////////////////// // // uint256 @@ -694,5 +604,102 @@ inline int Testuint256AdHoc(std::vector vArg) return (0); } +////////////////////////////////////////////////////////////////////////////// +// +// uint160 +// + +class uint160 : public base_uint160 +{ +public: + typedef base_uint160 basetype; + + uint160() + { + zero(); + } + + uint160(const basetype& b) + { + *this = b; + } + + uint160& operator=(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + + return *this; + } + + uint160(uint64 b) + { + *this = b; + } + + uint160& operator=(uint64 uHost) + { + zero(); + + // Put in least significant bits. + ((uint64_t *) end())[-1] = htobe64(uHost); + + return *this; + } + + explicit uint160(const std::string& str) + { + SetHex(str); + } + + explicit uint160(const std::vector& vch) + { + if (vch.size() == sizeof(pn)) + memcpy(pn, &vch[0], sizeof(pn)); + else + zero(); + } + + base_uint256 to256() const + { + uint256 m; + memcpy(m.begin(), begin(), size()); + return m; + } + +}; + +inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; } +inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; } + +inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } +inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } +inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } + +inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } + +inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } +inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } + +extern std::size_t hash_value(const uint160&); + +inline const std::string strHex(const uint160& ui) +{ + return strHex(ui.begin(), ui.size()); +} + + #endif // vim:ts=4 From e2fb75046fee67e741f3b15b9c3b2f81f26324b6 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 28 Sep 2012 12:29:44 -0700 Subject: [PATCH 44/45] RPC: Fix parsing of ripple options limit and average. --- src/RPCServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 202f0e5e3d..4028d8496c 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1451,7 +1451,7 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) bLimit = params.size() != iArg ? params[iArg].asString() == "limit" : false; bAverage = params.size() != iArg ? params[iArg].asString() == "average" : false; - if (!bPartial && !bFull) + if (!bLimit && !bAverage) { return RPCError(rpcINVALID_PARAMS); } From 9f2b38a441ec2d5c94b0cca3593bacfa541cde4d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 28 Sep 2012 12:30:29 -0700 Subject: [PATCH 45/45] TransactionEngine: do not allow bad transfer rate to be set. --- src/TransactionAction.cpp | 10 ++++++++-- src/TransactionErr.cpp | 2 ++ src/TransactionErr.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index 16d2e3f1ed..f37ef5a31c 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -166,18 +166,24 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { uint32 uRate = txn.getITFieldU32(sfTransferRate); - if (!uRate) + if (!uRate || uRate == QUALITY_ONE) { Log(lsINFO) << "doAccountSet: unset transfer rate"; mTxnAccount->makeIFieldAbsent(sfTransferRate); } - else + else if (uRate > QUALITY_ONE) { Log(lsINFO) << "doAccountSet: set transfer rate"; mTxnAccount->setIFieldU32(sfTransferRate, uRate); } + else + { + Log(lsINFO) << "doAccountSet: bad transfer rate"; + + return temBAD_TRANSFER_RATE; + } } // diff --git a/src/TransactionErr.cpp b/src/TransactionErr.cpp index 878d7cd1cd..85ea95594b 100644 --- a/src/TransactionErr.cpp +++ b/src/TransactionErr.cpp @@ -31,6 +31,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) { temBAD_PATH, "temBAD_PATH", "Malformed." }, { temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed." }, { temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: bad publish." }, + { temBAD_TRANSFER_RATE, "temBAD_TRANSFER_RATE", "Malformed: transfer rate must be >= 1.0" }, { temBAD_SET_ID, "temBAD_SET_ID", "Malformed." }, { temCREATEXNS, "temCREATEXNS", "Can not specify non XNS for Create." }, { temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." }, @@ -89,3 +90,4 @@ std::string transHuman(TER terCode) return transResultInfo(terCode, strToken, strHuman) ? strHuman : "-"; } +// vim:ts=4 diff --git a/src/TransactionErr.h b/src/TransactionErr.h index 4f0d5a7994..7ce5cd6109 100644 --- a/src/TransactionErr.h +++ b/src/TransactionErr.h @@ -33,6 +33,7 @@ enum TER // aka TransactionEngineResult temBAD_PATH, temBAD_PATH_LOOP, temBAD_PUBLISH, + temBAD_TRANSFER_RATE, temBAD_SET_ID, temCREATEXNS, temDST_IS_SRC,