From bd0dc68a22be89d9f51d2a2ab0cfea88069268e7 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 21 Oct 2012 21:45:04 -0700 Subject: [PATCH 01/32] JS: More fixes and tests for Amount.negate(). --- js/amount.js | 4 ++-- test/amount-test.js | 48 ++++++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/js/amount.js b/js/amount.js index d791e8c98..b0ac9c0ed 100644 --- a/js/amount.js +++ b/js/amount.js @@ -193,7 +193,7 @@ Amount.prototype.copyTo = function(d, negate) { if ('object' === typeof this.value) { if (this.is_native && negate) - this.value.negate.copyTo(d.value); + this.value.negate().copyTo(d.value); else this.value.copyTo(d.value); } @@ -204,7 +204,7 @@ Amount.prototype.copyTo = function(d, negate) { d.offset = this.offset; d.is_native = this.is_native; - d.is_negative = this.is_negative ? undefined : !this.is_negative; + d.is_negative = this.is_native ? undefined : !this.is_negative; this.currency.copyTo(d.currency); this.issuer.copyTo(d.issuer); diff --git a/test/amount-test.js b/test/amount-test.js index 9b10dad5a..97654d2a7 100644 --- a/test/amount-test.js +++ b/test/amount-test.js @@ -1,55 +1,71 @@ var buster = require("buster"); var amount = require("../js/amount.js"); +var Amount = require("../js/amount.js").Amount; +var UInt160 = require("../js/amount.js").UInt160; buster.testCase("Amount", { "UInt160" : { "Parse 0" : function () { - buster.assert.equals(0, amount.UInt160.from_json("0").value); + buster.assert.equals(0, UInt160.from_json("0").value); }, "Parse 0 export" : function () { - buster.assert.equals(amount.consts.hex_xns, amount.UInt160.from_json("0").to_json()); + buster.assert.equals(amount.consts.hex_xns, UInt160.from_json("0").to_json()); }, }, - "Amount" : { + "Amount parsing" : { "Parse native 0" : function () { - buster.assert.equals("0/XNS", amount.Amount.from_json("0").to_text_full()); + buster.assert.equals("0/XNS", Amount.from_json("0").to_text_full()); }, "Parse native 0.0" : function () { - buster.assert.equals("0/XNS", amount.Amount.from_json("0.0").to_text_full()); + buster.assert.equals("0/XNS", Amount.from_json("0.0").to_text_full()); }, "Parse native -0" : function () { - buster.assert.equals("0/XNS", amount.Amount.from_json("-0").to_text_full()); + buster.assert.equals("0/XNS", Amount.from_json("-0").to_text_full()); }, "Parse native -0.0" : function () { - buster.assert.equals("0/XNS", amount.Amount.from_json("-0.0").to_text_full()); + buster.assert.equals("0/XNS", Amount.from_json("-0.0").to_text_full()); }, "Parse native 1000" : function () { - buster.assert.equals("1000/XNS", amount.Amount.from_json("1000").to_text_full()); + buster.assert.equals("1000/XNS", Amount.from_json("1000").to_text_full()); }, "Parse native 12.3" : function () { - buster.assert.equals("12300000/XNS", amount.Amount.from_json("12.3").to_text_full()); + buster.assert.equals("12300000/XNS", Amount.from_json("12.3").to_text_full()); }, "Parse native -12.3" : function () { - buster.assert.equals("-12300000/XNS", amount.Amount.from_json("-12.3").to_text_full()); + buster.assert.equals("-12300000/XNS", Amount.from_json("-12.3").to_text_full()); }, "Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { - buster.assert.equals("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); + buster.assert.equals("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); }, "Parse 12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { - buster.assert.equals("12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); + buster.assert.equals("12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("12300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); }, "Parse 12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { - buster.assert.equals("12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); + buster.assert.equals("12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("12.3/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); }, "Parse 1.2300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { - buster.assert.equals("1.23/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("1.2300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); + buster.assert.equals("1.23/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("1.2300/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); }, "Parse -0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { - buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("-0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); + buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("-0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); }, "Parse -0.0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" : function () { - buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", amount.Amount.from_json("-0.0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); + buster.assert.equals("0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("-0.0/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").to_text_full()); + }, + }, + "Amount operations" : { + "Negate native 123" : function () { + buster.assert.equals("-123/XNS", Amount.from_json("123").negate().to_text_full()); + }, + "Negate native -123" : function () { + buster.assert.equals("123/XNS", Amount.from_json("-123").negate().to_text_full()); + }, + "Negate non-native 123" : function () { + buster.assert.equals("-123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").negate().to_text_full()); + }, + "Negate non-native -123" : function () { + buster.assert.equals("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("-123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").negate().to_text_full()); }, } }); From 5bc0838d2af389b448d02677c532221214a46411 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 22 Oct 2012 09:22:32 -0700 Subject: [PATCH 02/32] Make the standard output loglevel low even if the debug file loglevel is high. --- src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Application.cpp b/src/Application.cpp index 0d777f518..d7bc41520 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -70,8 +70,9 @@ void Application::run() { assert(mTxnDB == NULL); if (!theConfig.DEBUG_LOGFILE.empty()) - { + { // Let DEBUG messages go to the file but only WARNING or higher to regular output Log::setLogFile(theConfig.DEBUG_LOGFILE); + Log::setMinSeverity(lsWARNING); LogPartition::setSeverity(lsDEBUG); } From e2e7eca1f116faae66d53344336fdfa433cd7eea Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 22 Oct 2012 10:30:42 -0700 Subject: [PATCH 03/32] Fix a small bug in the ledger tiebreak algorithm based on nodes using. --- src/NetworkOPs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index bdf97d4d9..a2e800bc4 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -496,7 +496,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis ValidationCount& ourVC = ledgers[closedLedger]; - if ((theConfig.LEDGER_CREATOR) && (mMode >= omTRACKING)) + if (mMode >= omTRACKING) { ++ourVC.nodesUsing; uint160 ourAddress = theApp->getWallet().getNodePublic().getNodeID(); From 8705d0258dc2f185ba305cd094521a13439a18a5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 22 Oct 2012 10:31:07 -0700 Subject: [PATCH 04/32] Add a "full history" mode that causes the node to try to keep full history going back to the genesis ledger. Not fully implemented yet. --- src/Application.cpp | 10 +++++++++- src/Config.cpp | 6 ++++++ src/Config.h | 3 +++ src/Ledger.cpp | 11 +++++++++++ src/Ledger.h | 1 + src/LedgerMaster.cpp | 4 ++++ src/LedgerMaster.h | 6 ++++++ 7 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Application.cpp b/src/Application.cpp index d7bc41520..489b33a7d 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -113,6 +113,13 @@ void Application::run() else startNewLedger(); + if (theConfig.FULL_HISTORY && (theConfig.START_UP != Config::LOAD)) + { + Ledger::pointer ledger = Ledger::getLastFullLedger(); + if (ledger) + mMasterLedger.setLastFullLedger(ledger); + } + // // Begin validation and ip maintenance. // - Wallet maintains local information: including identity and network connection persistence information. @@ -215,7 +222,7 @@ void Application::loadOldLedger() { try { - Ledger::pointer lastLedger = Ledger::getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;"); + Ledger::pointer lastLedger = Ledger::getLastFullLedger(); if (!lastLedger) { @@ -244,6 +251,7 @@ void Application::loadOldLedger() cLog(lsFATAL) << "Ledger is not sane."; exit(-1); } + mMasterLedger.setLastFullLedger(lastLedger); Ledger::pointer openLedger = boost::make_shared(false, boost::ref(*lastLedger)); mMasterLedger.switchLedgers(lastLedger, openLedger); diff --git a/src/Config.cpp b/src/Config.cpp index e4fb3f79a..12eac4885 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -14,6 +14,7 @@ #define SECTION_FEE_NICKNAME_CREATE "fee_nickname_create" #define SECTION_FEE_OFFER "fee_offer" #define SECTION_FEE_OPERATION "fee_operation" +#define SECTION_FULL_HISTORY "full_history" #define SECTION_IPS "ips" #define SECTION_NETWORK_QUORUM "network_quorum" #define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water" @@ -150,6 +151,8 @@ void Config::setup(const std::string& strConf) FEE_DEFAULT = DEFAULT_FEE_DEFAULT; FEE_CONTRACT_OPERATION = DEFAULT_FEE_OPERATION; + FULL_HISTORY = false; + ACCOUNT_PROBE_MAX = 10; VALIDATORS_SITE = DEFAULT_VALIDATORS_SITE; @@ -266,6 +269,9 @@ void Config::load() if (sectionSingleB(secConfig, SECTION_FEE_OPERATION, strTemp)) FEE_CONTRACT_OPERATION = boost::lexical_cast(strTemp); + if (sectionSingleB(secConfig, SECTION_FULL_HISTORY, strTemp)) + FULL_HISTORY = boost::lexical_cast(strTemp); + if (sectionSingleB(secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp)) ACCOUNT_PROBE_MAX = boost::lexical_cast(strTemp); diff --git a/src/Config.h b/src/Config.h index c7270e1d7..8c0c5c2f0 100644 --- a/src/Config.h +++ b/src/Config.h @@ -102,6 +102,9 @@ public: uint64 FEE_OFFER; // Rate per day. int FEE_CONTRACT_OPERATION; // fee for each contract operation + // Node storage configuration + bool FULL_HISTORY; + // Client behavior int ACCOUNT_PROBE_MAX; // How far to scan for accounts. diff --git a/src/Ledger.cpp b/src/Ledger.cpp index dd67647b5..4460e2747 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -429,6 +429,12 @@ void Ledger::saveAcceptedLedger() } theApp->getOPs().pubLedger(shared_from_this()); + + if(theConfig.FULL_HISTORY) + { + // WRITEME: check for seamless ledger history + } + } Ledger::pointer Ledger::getSQL(const std::string& sql) @@ -498,6 +504,11 @@ Ledger::pointer Ledger::loadByHash(const uint256& ledgerHash) return getSQL(sql); } +Ledger::pointer Ledger::getLastFullLedger() +{ + return getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;"); +} + void Ledger::addJson(Json::Value& ret, int options) { ret["ledger"] = getJson(options); diff --git a/src/Ledger.h b/src/Ledger.h index 2b03b88ea..7c746843a 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -100,6 +100,7 @@ public: Ledger(Ledger& target, bool isMutable); // snapshot static Ledger::pointer getSQL(const std::string& sqlStatement); + static Ledger::pointer getLastFullLedger(); void updateHash(); void setClosed() { mClosed = true; } diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index dd0f6ecca..5553c91b5 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -32,6 +32,8 @@ void LedgerMaster::pushLedger(Ledger::ref newLedger) mFinalizedLedger = mCurrentLedger; mCurrentLedger = newLedger; mEngine.setLedger(newLedger); + if (mLastFullLedger && (newLedger->getParentHash() == mLastFullLedger->getHash())) + mLastFullLedger = newLedger; } void LedgerMaster::pushLedger(Ledger::ref newLCL, Ledger::ref newOL) @@ -44,6 +46,8 @@ void LedgerMaster::pushLedger(Ledger::ref newLCL, Ledger::ref newOL) assert(newLCL->isClosed()); assert(newLCL->isImmutable()); mLedgerHistory.addAcceptedLedger(newLCL); + if (mLastFullLedger && (newLCL->getParentHash() == mLastFullLedger->getHash())) + mLastFullLedger = newLCL; Log(lsINFO) << "StashAccepted: " << newLCL->getHash(); } diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index 2f198b884..36f9339db 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -20,6 +20,7 @@ class LedgerMaster Ledger::pointer mCurrentLedger; // The ledger we are currently processiong Ledger::pointer mFinalizedLedger; // The ledger that most recently closed + Ledger::pointer mLastFullLedger; // We have history to this point LedgerHistory mLedgerHistory; @@ -49,6 +50,11 @@ public: void pushLedger(Ledger::ref newLCL, Ledger::ref newOL); void storeLedger(Ledger::ref); + void setLastFullLedger(Ledger::ref ledger) + { + mLastFullLedger = ledger; + } + void switchLedgers(Ledger::ref lastClosed, Ledger::ref newCurrent); Ledger::pointer closeLedger(); From 766bc8377f1e27e018554d3a96607e2f85935e4d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 22 Oct 2012 11:49:17 -0700 Subject: [PATCH 05/32] Lots of small cleanups. --- src/CanonicalTXSet.cpp | 2 +- src/CanonicalTXSet.h | 2 +- src/LedgerConsensus.cpp | 2 +- src/LedgerConsensus.h | 2 +- src/LedgerEntrySet.h | 4 ++-- src/NetworkOPs.cpp | 2 +- src/NetworkOPs.h | 2 +- src/RippleCalc.cpp | 22 +++++++++++----------- src/RippleCalc.h | 29 +++++++++++++++-------------- src/RippleLines.cpp | 6 +++--- src/RippleLines.h | 6 +++--- src/SHAMap.h | 2 +- src/SHAMapNodes.cpp | 4 ++-- src/SerializedTransaction.h | 3 ++- src/Transaction.cpp | 6 +++--- src/Transaction.h | 2 +- src/TransactionMaster.cpp | 2 +- src/TransactionMaster.h | 2 +- 18 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/CanonicalTXSet.cpp b/src/CanonicalTXSet.cpp index e3af1e487..8b536d354 100644 --- a/src/CanonicalTXSet.cpp +++ b/src/CanonicalTXSet.cpp @@ -37,7 +37,7 @@ bool CanonicalTXKey::operator>=(const CanonicalTXKey& key)const return mTXid >= key.mTXid; } -void CanonicalTXSet::push_back(const SerializedTransaction::pointer& txn) +void CanonicalTXSet::push_back(SerializedTransaction::ref txn) { uint256 effectiveAccount = mSetHash; effectiveAccount ^= txn->getSourceAccount().getAccountID().to256(); diff --git a/src/CanonicalTXSet.h b/src/CanonicalTXSet.h index 3315625a3..c75fb6b1b 100644 --- a/src/CanonicalTXSet.h +++ b/src/CanonicalTXSet.h @@ -38,7 +38,7 @@ protected: public: CanonicalTXSet(const uint256& lclHash) : mSetHash(lclHash) { ; } - void push_back(const SerializedTransaction::pointer& txn); + void push_back(SerializedTransaction::ref txn); iterator erase(const iterator& it); iterator begin() { return mMap.begin(); } diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 2bd8e5744..afaf29cfe 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -993,7 +993,7 @@ void LedgerConsensus::playbackProposals() } } -void LedgerConsensus::applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, +void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTransaction::ref txn, Ledger::ref ledger, CanonicalTXSet& failedTransactions, bool openLedger) { TransactionEngineParams parms = openLedger ? tapOPEN_LEDGER : tapNONE; diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 23582e071..2387307f6 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -134,7 +134,7 @@ protected: void sendHaveTxSet(const uint256& set, bool direct); void applyTransactions(SHAMap::ref transactionSet, Ledger::ref targetLedger, Ledger::ref checkLedger, CanonicalTXSet& failedTransactions, bool openLgr); - void applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, + void applyTransaction(TransactionEngine& engine, SerializedTransaction::ref txn, Ledger::ref targetLedger, CanonicalTXSet& failedTransactions, bool openLgr); uint32 roundCloseTime(uint32 closeTime); diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 2558f1288..aaafd523b 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -65,8 +65,8 @@ public: void init(Ledger::ref ledger, const uint256& transactionID, uint32 ledgerID); void clear(); - Ledger::pointer& getLedger() { return mLedger; } - const Ledger::pointer& getLedgerRef() const { return mLedger; } + Ledger::pointer& getLedger() { return mLedger; } + Ledger::ref getLedgerRef() const { return mLedger; } // basic entry functions SLE::pointer getEntry(const uint256& index, LedgerEntryAction&); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index a2e800bc4..09239e69f 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -638,7 +638,7 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringCo theApp->getConnectionPool().relayMessage(NULL, packet); } -int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger) +int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::ref closingLedger) { cLog(lsINFO) << "Consensus time for ledger " << closingLedger->getLedgerSeq(); cLog(lsINFO) << " LCL is " << closingLedger->getParentHash(); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index cd2e8bede..2c5475c93 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -180,7 +180,7 @@ public: void checkState(const boost::system::error_code& result); void switchLastClosedLedger(Ledger::pointer newLedger, bool duringConsensus); // Used for the "jump" case bool checkLastClosedLedger(const std::vector&, uint256& networkClosed); - int beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger); + int beginConsensus(const uint256& networkClosed, Ledger::ref closingLedger); void endConsensus(bool correctLCL); void setStandAlone() { setMode(omFULL); } void setStateTimer(); diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp index d87758a4a..5241ad824 100644 --- a/src/RippleCalc.cpp +++ b/src/RippleCalc.cpp @@ -27,7 +27,7 @@ std::size_t hash_value(const aciSource& asValue) // <-- uOfferIndex : 0=end of list. TER RippleCalc::calcNodeAdvance( const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, + PathState::ref pspCur, const bool bMultiQuality, const bool bReverse) { @@ -267,7 +267,7 @@ TER RippleCalc::calcNodeAdvance( // Continue process till request is satisified while we the rate does not increase past the initial rate. TER RippleCalc::calcNodeDeliverRev( const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, + PathState::ref pspCur, const bool bMultiQuality, const uint160& uOutAccountID, // --> Output owner's account. const STAmount& saOutReq, // --> Funds wanted. @@ -459,7 +459,7 @@ TER RippleCalc::calcNodeDeliverRev( // Goal: Make progress consuming the offer. TER RippleCalc::calcNodeDeliverFwd( const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, + PathState::ref pspCur, const bool bMultiQuality, const uint160& uInAccountID, // --> Input owner's account. const STAmount& saInFunds, // --> Funds available for delivery and fees. @@ -610,7 +610,7 @@ TER RippleCalc::calcNodeDeliverFwd( // Called to drive from the last offer node in a chain. TER RippleCalc::calcNodeOfferRev( const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, + PathState::ref pspCur, const bool bMultiQuality) { TER terResult; @@ -650,7 +650,7 @@ TER RippleCalc::calcNodeOfferRev( // - Deliver is set without transfer fees. TER RippleCalc::calcNodeOfferFwd( const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, + PathState::ref pspCur, const bool bMultiQuality ) { @@ -789,7 +789,7 @@ void RippleCalc::calcNodeRipple( // Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur... // <-- tesSUCCESS or tepPATH_DRY -TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality) { TER terResult = tesSUCCESS; const unsigned int uLast = pspCur->vpnNodes.size() - 1; @@ -1100,7 +1100,7 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p // - Output to next node is computed as input minus quality or transfer fee. TER RippleCalc::calcNodeAccountFwd( const unsigned int uIndex, // 0 <= uIndex <= uLast - const PathState::pointer& pspCur, + PathState::ref pspCur, const bool bMultiQuality) { TER terResult = tesSUCCESS; @@ -1362,7 +1362,7 @@ TER RippleCalc::calcNodeAccountFwd( } // Return true, iff lhs has less priority than rhs. -bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs) +bool PathState::lessPriority(PathState::ref lhs, PathState::ref rhs) { if (lhs->uQuality != rhs->uQuality) return lhs->uQuality > rhs->uQuality; // Bigger is worse. @@ -1713,7 +1713,7 @@ Json::Value PathState::getJson() const return jvPathState; } -TER RippleCalc::calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +TER RippleCalc::calcNodeFwd(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality) { const PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); @@ -1743,7 +1743,7 @@ TER RippleCalc::calcNodeFwd(const unsigned int uIndex, const PathState::pointer& // --> [all]saWanted.mCurrency // --> [all]saAccount // <-> [0]saWanted.mAmount : --> limit, <-- actual -TER RippleCalc::calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +TER RippleCalc::calcNodeRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality) { PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); @@ -1785,7 +1785,7 @@ TER RippleCalc::calcNodeRev(const unsigned int uIndex, const PathState::pointer& // Calculate the next increment of a path. // The increment is what can satisfy a portion or all of the requested output at the best quality. // <-- pspCur->uQuality -void RippleCalc::pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent) +void RippleCalc::pathNext(PathState::ref pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent) { // The next state is what is available in preference order. // This is calculated when referenced accounts changed. diff --git a/src/RippleCalc.h b/src/RippleCalc.h index 14d07f4aa..b212c162e 100644 --- a/src/RippleCalc.h +++ b/src/RippleCalc.h @@ -65,13 +65,14 @@ extern std::size_t hash_value(const aciSource& asValue); class PathState { protected: - const Ledger::pointer& mLedger; + Ledger::ref mLedger; TER pushNode(const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); TER pushImply(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); public: - typedef boost::shared_ptr pointer; + typedef boost::shared_ptr pointer; + typedef const boost::shared_ptr& ref; TER terStatus; std::vector vpnNodes; @@ -123,7 +124,7 @@ public: return boost::make_shared(iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax); } - static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs); + static bool lessPriority(PathState::ref lhs, PathState::ref rhs); }; class RippleCalc @@ -139,18 +140,18 @@ public: boost::unordered_set musUnfundedFound; // Offers that were found unfunded. PathState::pointer pathCreate(const STPath& spPath); - void pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent); - TER calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - TER calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - TER calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - TER calcNodeOfferRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - TER calcNodeOfferFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - TER calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - TER calcNodeAccountFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - TER calcNodeAdvance(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality, const bool bReverse); + void pathNext(PathState::ref pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent); + TER calcNode(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeFwd(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeOfferRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeOfferFwd(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeAccountFwd(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeAdvance(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality, const bool bReverse); TER calcNodeDeliverRev( const unsigned int uIndex, - const PathState::pointer& pspCur, + PathState::ref pspCur, const bool bMultiQuality, const uint160& uOutAccountID, const STAmount& saOutReq, @@ -158,7 +159,7 @@ public: TER calcNodeDeliverFwd( const unsigned int uIndex, - const PathState::pointer& pspCur, + PathState::ref pspCur, const bool bMultiQuality, const uint160& uInAccountID, const STAmount& saInFunds, diff --git a/src/RippleLines.cpp b/src/RippleLines.cpp index a9808780b..fece4f429 100644 --- a/src/RippleLines.cpp +++ b/src/RippleLines.cpp @@ -7,9 +7,9 @@ SETUP_LOG(); -RippleLines::RippleLines(const uint160& accountID, Ledger::pointer ledger) +RippleLines::RippleLines(const uint160& accountID, Ledger::ref ledger) { - fillLines(accountID,ledger); + fillLines(accountID, ledger); } void RippleLines::printRippleLines() @@ -25,7 +25,7 @@ RippleLines::RippleLines(const uint160& accountID ) fillLines(accountID,theApp->getMasterLedger().getCurrentLedger()); } -void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger) +void RippleLines::fillLines(const uint160& accountID, Ledger::ref ledger) { uint256 rootIndex = Ledger::getOwnerDirIndex(accountID); uint256 currentIndex = rootIndex; diff --git a/src/RippleLines.h b/src/RippleLines.h index 00373838d..5ddd47e04 100644 --- a/src/RippleLines.h +++ b/src/RippleLines.h @@ -9,12 +9,12 @@ It provides a vector so you to easily iterate through them class RippleLines { std::vector mLines; - void fillLines(const uint160& accountID, Ledger::pointer ledger); + void fillLines(const uint160& accountID, Ledger::ref ledger); public: - RippleLines(const uint160& accountID, Ledger::pointer ledger); + RippleLines(const uint160& accountID, Ledger::ref ledger); RippleLines(const uint160& accountID ); // looks in the current ledger - std::vector& getLines(){ return(mLines); } + std::vector& getLines() { return(mLines); } void printRippleLines(); }; diff --git a/src/SHAMap.h b/src/SHAMap.h index 7426ab780..2621ba58e 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -208,7 +208,7 @@ public: bool hasItem() const { return !!mItem; } SHAMapItem::ref peekItem() { return mItem; } SHAMapItem::pointer getItem() const; - bool setItem(const SHAMapItem::pointer& i, TNType type); + bool setItem(SHAMapItem::ref i, TNType type); const uint256& getTag() const { return mItem->getTag(); } const std::vector& peekData() { return mItem->peekData(); } std::vector getData() const { return mItem->getData(); } diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index b301e9db8..9db9f4e2c 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -185,7 +185,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq) : SHAMapN memcpy(mHashes, node.mHashes, sizeof(mHashes)); } -SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, const SHAMapItem::pointer& item, TNType type, uint32 seq) : +SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::ref item, TNType type, uint32 seq) : SHAMapNode(node), mItem(item), mSeq(seq), mType(type), mFullBelow(true) { assert(item->peekData().size() >= 12); @@ -465,7 +465,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, SHANodeFormat format) assert(false); } -bool SHAMapTreeNode::setItem(const SHAMapItem::pointer& i, TNType type) +bool SHAMapTreeNode::setItem(SHAMapItem::ref i, TNType type) { uint256 hash = getNodeHash(); mType = type; diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index e049a455d..a5dc83101 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -20,7 +20,8 @@ class SerializedTransaction : public STObject { public: - typedef boost::shared_ptr pointer; + typedef boost::shared_ptr pointer; + typedef const boost::shared_ptr& ref; protected: TransactionType mType; diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 8eea1dd76..1f0f43ff1 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -13,7 +13,7 @@ #include "SerializedTransaction.h" #include "Log.h" -Transaction::Transaction(const SerializedTransaction::pointer& sit, bool bValidate) +Transaction::Transaction(SerializedTransaction::ref sit, bool bValidate) : mInLedger(0), mStatus(INVALID), mResult(temUNCERTAIN), mTransaction(sit) { try @@ -709,8 +709,8 @@ bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedg for(it = inMap.begin(); it != inMap.end(); ++it) { const uint256& id = it->first; - const SHAMapItem::pointer& first = it->second.first; - const SHAMapItem::pointer& second = it->second.second; + SHAMapItem::ref first = it->second.first; + SHAMapItem::ref second = it->second.second; Transaction::pointer firstTrans, secondTrans; if (!!first) diff --git a/src/Transaction.h b/src/Transaction.h index c78a617bb..f9101cf49 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -129,7 +129,7 @@ private: const std::vector& vucSignature); public: - Transaction(const SerializedTransaction::pointer& st, bool bValidate); + Transaction(SerializedTransaction::ref st, bool bValidate); static Transaction::pointer sharedTransaction(const std::vector&vucTransaction, bool bValidate); static Transaction::pointer transactionFromSQL(Database* db, bool bValidate); diff --git a/src/TransactionMaster.cpp b/src/TransactionMaster.cpp index b59f54d22..eabf17622 100644 --- a/src/TransactionMaster.cpp +++ b/src/TransactionMaster.cpp @@ -31,7 +31,7 @@ Transaction::pointer TransactionMaster::fetch(const uint256& txnID, bool checkDi return txn; } -SerializedTransaction::pointer TransactionMaster::fetch(const SHAMapItem::pointer& item, bool checkDisk, uint32 uCommitLedger) +SerializedTransaction::pointer TransactionMaster::fetch(SHAMapItem::ref item, bool checkDisk, uint32 uCommitLedger) { SerializedTransaction::pointer txn; Transaction::pointer iTx = theApp->getMasterTransaction().fetch(item->getTag(), false); diff --git a/src/TransactionMaster.h b/src/TransactionMaster.h index c5e5f9a75..19fd8b64d 100644 --- a/src/TransactionMaster.h +++ b/src/TransactionMaster.h @@ -16,7 +16,7 @@ public: TransactionMaster(); Transaction::pointer fetch(const uint256&, bool checkDisk); - SerializedTransaction::pointer fetch(const SHAMapItem::pointer& item, bool checkDisk, uint32 uCommitLedger); + SerializedTransaction::pointer fetch(SHAMapItem::ref item, bool checkDisk, uint32 uCommitLedger); // return value: true = we had the transaction already bool canonicalize(Transaction::pointer& txn, bool maybeNew); From 9326074324ba92ce047fcdcc80c72df4047e7013 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 22 Oct 2012 12:26:51 -0700 Subject: [PATCH 06/32] Second phase of removing old-style ledger data queries -- always give new style replies. --- src/Peer.cpp | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index e44608049..f115db278 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -1053,25 +1053,22 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet) ledger->addRaw(nData); reply.add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength()); - if (packet.nodeids().size() != 0) - { // new-style root request - cLog(lsINFO) << "Ledger root w/map roots request"; - SHAMap::pointer map = ledger->peekAccountStateMap(); - if (map && map->getHash().isNonZero()) - { // return account state root node if possible - Serializer rootNode(768); - if (map->getRootNode(rootNode, snfWIRE)) + cLog(lsINFO) << "Ledger root w/map roots request"; + SHAMap::pointer map = ledger->peekAccountStateMap(); + if (map && map->getHash().isNonZero()) + { // return account state root node if possible + Serializer rootNode(768); + if (map->getRootNode(rootNode, snfWIRE)) + { + reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength()); + if (ledger->getTransHash().isNonZero()) { - reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength()); - if (ledger->getTransHash().isNonZero()) + map = ledger->peekTransactionMap(); + if (map && map->getHash().isNonZero()) { - map = ledger->peekTransactionMap(); - if (map && map->getHash().isNonZero()) - { - rootNode.resize(0); - if (map->getRootNode(rootNode, snfWIRE)) - reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength()); - } + rootNode.resize(0); + if (map->getRootNode(rootNode, snfWIRE)) + reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength()); } } } From c08db57b2b822497894121ad3136a7ae5354fc1b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 22 Oct 2012 12:27:30 -0700 Subject: [PATCH 07/32] Ledger reply error support. --- src/ripple.proto | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ripple.proto b/src/ripple.proto index a6ed14e55..64cd1b71f 100644 --- a/src/ripple.proto +++ b/src/ripple.proto @@ -245,15 +245,20 @@ message TMGetLedger { optional uint32 requestCookie = 6; } +enum TMReplyError { + reNO_LEDGER = 1; // We don't have the ledger you are asking about + reNO_NODE = 2; // We don't have any of the nodes you are asking for +} + message TMLedgerData { required bytes ledgerHash = 1; required uint32 ledgerSeq = 2; required TMLedgerInfoType type = 3; repeated TMLedgerNode nodes = 4; optional uint32 requestCookie = 5; + optional TMReplyError error = 6; } - message TMPing { enum pingType { PING = 0; // we want a reply From 2f2f09b4fc4c6653cfe823635b61ff5f0616fa75 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 22 Oct 2012 14:01:06 -0700 Subject: [PATCH 08/32] Reduce debug. --- src/NetworkOPs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 09239e69f..6cf1e4be4 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -864,7 +864,7 @@ std::vector bool NetworkOPs::recvValidation(const SerializedValidation::pointer& val) { - cLog(lsINFO) << "recvValidation " << val->getLedgerHash(); + cLog(lsDEBUG) << "recvValidation " << val->getLedgerHash(); return theApp->getValidations().addValidation(val); } From 39303e3998b771a6d464357ac5e2afae8bac5212 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 22 Oct 2012 14:01:17 -0700 Subject: [PATCH 09/32] Some extra LedgerAcquire helper functions. --- src/LedgerAcquire.cpp | 23 +++++++++++++++++++++++ src/LedgerAcquire.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index f5579a9c3..7f638c7af 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -326,6 +326,29 @@ void PeerSet::sendRequest(const ripple::TMGetLedger& tmGL) } } +int PeerSet::takePeerSetFrom(const PeerSet& s) +{ + int ret = 0; + mPeers.clear(); + mPeers.reserve(s.mPeers.size()); + BOOST_FOREACH(const boost::weak_ptr& p, s.mPeers) + if (p.lock()) + { + mPeers.push_back(p); + ++ret; + } + return ret; +} + +int PeerSet::getPeerCount() const +{ + int ret = 0; + BOOST_FOREACH(const boost::weak_ptr& p, mPeers) + if (p.lock()) + ++ret; + return ret; +} + bool LedgerAcquire::takeBase(const std::string& data) { // Return value: true=normal, false=bad data #ifdef LA_DEBUG diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index 196a325c1..354ad1593 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -45,6 +45,9 @@ public: void badPeer(Peer::ref); void resetTimer(); + int takePeerSetFrom(const PeerSet& s); + int getPeerCount() const; + protected: virtual void newPeer(Peer::ref) = 0; virtual void onTimer(void) = 0; From 485f1aab13012789d0690707e4f812a6f2c0d708 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 22 Oct 2012 16:11:35 -0700 Subject: [PATCH 10/32] JS: Add arraySet() and stringToArray() to utils.js --- js/utils.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/js/utils.js b/js/utils.js index 37f78736b..288445993 100644 --- a/js/utils.js +++ b/js/utils.js @@ -44,6 +44,16 @@ var trace = function(comment, func) { }; }; +var arraySet = function (count, value) { + var a = new Array(count); + var i; + + for (i = 0; i != count; i += 1) + a[i] = value; + + return a; +}; + var hexToString = function (h) { var a = []; var i = 0; @@ -68,9 +78,21 @@ var stringToHex = function (s) { }).join(""); }; +var stringToArray = function (s) { + var a = new Array(s.length); + var i; + + for (i = 0; i != a.length; i += 1) + a[i] = s.charCodeAt(i); + + return a; +}; + exports.mapOr = mapOr; exports.trace = trace; +exports.arraySet = arraySet; exports.hexToString = hexToString; +exports.stringToArray = stringToArray; exports.stringToHex = stringToHex; // vim:sw=2:sts=2:ts=8 From c5dce0e270532301cb50755df7c07be55bc4cb50 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 22 Oct 2012 16:15:58 -0700 Subject: [PATCH 11/32] JS: Add support for parsing and encoding base58. --- js/amount.js | 164 +++++++++++++++++++++++++++++++++++++------- test/amount-test.js | 17 ++++- test/send-test.js | 14 ++-- 3 files changed, 161 insertions(+), 34 deletions(-) diff --git a/js/amount.js b/js/amount.js index b0ac9c0ed..ab1524ab9 100644 --- a/js/amount.js +++ b/js/amount.js @@ -1,6 +1,8 @@ // Represent Ripple amounts and currencies. // - Numbers in hex are big-endian. +var sjcl = require('./sjcl/core.js'); +var bn = require('./sjcl/core.js').bn; var utils = require('./utils.js'); var jsbn = require('./jsbn.js'); @@ -8,11 +10,122 @@ var jsbn = require('./jsbn.js'); var config = require('../test/config.js'); var BigInteger = jsbn.BigInteger; +var nbi = jsbn.nbi; + +var alphabets = { + 'ripple' : "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", + 'bitcoin' : "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" +}; + +// --> input: big-endian array of bytes. +// <-- string at least as long as input. +var encode_base = function (input, alphabet) { + var alphabet = alphabets[alphabet || 'ripple']; + var bi_base = new BigInteger(String(alphabet.length)); + var bi_q = nbi(); + var bi_r = nbi(); + var bi_value = new BigInteger(input); + var buffer = []; + + while (bi_value.compareTo(BigInteger.ZERO) > 0) + { + bi_value.divRemTo(bi_base, bi_q, bi_r); + bi_q.copyTo(bi_value); + + buffer.push(alphabet[bi_r.intValue()]); + } + + var i; + + for (i = 0; i != input.length && !input[i]; i += 1) { + buffer.push(alphabet[0]); + } + + return buffer.reverse().join(""); +}; + +// --> input: String +// <-- array of bytes or undefined. +var decode_base = function (input, alphabet) { + var alphabet = alphabets[alphabet || 'ripple']; + var bi_base = new BigInteger(String(alphabet.length)); + var bi_value = nbi(); + var i; + + while (i != input.length && input[i] === alphabet[0]) + i += 1; + + for (i = 0; i != input.length; i += 1) { + var v = alphabet.indexOf(input[i]); + + if (v < 0) + return undefined; + + var r = nbi(); + + r.fromInt(v); + + bi_value = bi_value.multiply(bi_base).add(r); + } + + // toByteArray: + // - Returns leading zeros! + // - Returns signed bytes! + var bytes = bi_value.toByteArray().map(function (b) { return b ? b < 0 ? 256+b : b : 0}); + var extra = 0; + + while (extra != bytes.length && !bytes[extra]) + extra += 1; + + if (extra) + bytes = bytes.slice(extra); + + var zeros = 0; + + while (zeros !== input.length && input[zeros] === alphabet[0]) + zeros += 1; + + return [].concat(utils.arraySet(zeros, 0), bytes); +}; + +var sha256 = function (bytes) { + return sjcl.codec.bytes.fromBits(sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes))); +}; + +var sha256hash = function (bytes) { + return sha256(sha256(bytes)); +}; + +// --> input: Array +// <-- String +var encode_base_check = function (version, input, alphabet) { + var buffer = [].concat(version, input); + var check = sha256(sha256(buffer)).slice(0, 4); + + return encode_base([].concat(buffer, check), alphabet); +} + +// --> input : String +// <-- NaN || BigInteger +var decode_base_check = function (version, input, alphabet) { + var buffer = decode_base(input, alphabet); + + if (!buffer || buffer[0] !== version || buffer.length < 5) + return NaN; + + var computed = sha256hash(buffer.slice(0, -4)).slice(0, 4); + var checksum = buffer.slice(-4); + var i; + + for (i = 0; i != 4; i += 1) + if (computed[i] !== checksum[i]) + return NaN; + + return new BigInteger(buffer.slice(1, -4)); +} var UInt160 = function () { - // Internal form: - // 0, 1, 'iXXXXX', 20 byte string, or NaN. - // XXX Should standardize on 'i' format or 20 format. + // Internal form: NaN or BigInteger this.value = NaN; }; @@ -54,14 +167,15 @@ UInt160.prototype.parse_json = function (j) { case exports.consts.address_xns: case exports.consts.uint160_xns: case exports.consts.hex_xns: - this.value = 0; + this.value = nbi(); break; case "1": case exports.consts.address_one: case exports.consts.uint160_one: case exports.consts.hex_one: - this.value = 1; + this.value = new BigInteger([1]); + break; default: @@ -69,15 +183,14 @@ UInt160.prototype.parse_json = function (j) { this.value = NaN; } else if (20 === j.length) { - this.value = j; + this.value = new BigInteger(utils.stringToArray(j), 256); } else if (40 === j.length) { - this.value = utils.hexToString(j); + // XXX Check char set! + this.value = new BigInteger(j, 16); } else if (j[0] === "r") { - // XXX Do more checking convert to string. - - this.value = j; + this.value = decode_base_check(0, j); } else { this.value = NaN; @@ -90,25 +203,26 @@ UInt160.prototype.parse_json = function (j) { // Convert from internal form. // XXX Json form should allow 0 and 1, C++ doesn't currently allow it. UInt160.prototype.to_json = function () { - if ("0" === this.value) { - return exports.consts.hex_xns; - } - else if ("1" === this.value) - { - return exports.consts.hex_one; - } - else if ('string' === typeof this.value && 20 === this.value.length) { - return utils.stringToHex(this.value); - } - else - { - return this.value; - } + if (isNaN(this.value)) + return NaN; + + var bytes = this.value.toByteArray().map(function (b) { return b ? b < 0 ? 256+b : b : 0}); + var target = 20; + + // XXX Make sure only trim off leading zeros. + var array = bytes.length < target + ? bytes.length + ? [].concat(utils.arraySet(target - bytes.length, 0), bytes) + : utils.arraySet(target, 0) + : bytes.slice(target - bytes.length); + var output = encode_base_check(0, array); + + return output; }; var Currency = function () { // Internal form: 0 = XNS. 3 letter-code. - // XXX Internal should be 0 or hex. + // XXX Internal should be 0 or hex with three letter annotation when valid. // Json form: // '', 'XNS', '0': 0 diff --git a/test/amount-test.js b/test/amount-test.js index 97654d2a7..a6cae93f9 100644 --- a/test/amount-test.js +++ b/test/amount-test.js @@ -1,5 +1,9 @@ var buster = require("buster"); +var jsbn = require('../js/jsbn.js'); +var BigInteger = jsbn.BigInteger; +var nbi = jsbn.nbi; + var amount = require("../js/amount.js"); var Amount = require("../js/amount.js").Amount; var UInt160 = require("../js/amount.js").UInt160; @@ -7,10 +11,19 @@ var UInt160 = require("../js/amount.js").UInt160; buster.testCase("Amount", { "UInt160" : { "Parse 0" : function () { - buster.assert.equals(0, UInt160.from_json("0").value); + buster.assert.equals(nbi(), UInt160.from_json("0").value); }, "Parse 0 export" : function () { - buster.assert.equals(amount.consts.hex_xns, UInt160.from_json("0").to_json()); + buster.assert.equals(amount.consts.address_xns, UInt160.from_json("0").to_json()); + }, + "Parse 1" : function () { + buster.assert.equals(new BigInteger([1]), UInt160.from_json("1").value); + }, + "Parse rrrrrrrrrrrrrrrrrrrrrhoLvTp export" : function () { + buster.assert.equals(amount.consts.address_xns, UInt160.from_json("rrrrrrrrrrrrrrrrrrrrrhoLvTp").to_json()); + }, + "Parse rrrrrrrrrrrrrrrrrrrrBZbvji export" : function () { + buster.assert.equals(amount.consts.address_one, UInt160.from_json("rrrrrrrrrrrrrrrrrrrrBZbvji").to_json()); }, }, "Amount parsing" : { diff --git a/test/send-test.js b/test/send-test.js index 9d66ad030..dcc35d56e 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -10,7 +10,7 @@ var testutils = require("./testutils.js"); // How long to wait for server to start. var serverDelay = 1500; -buster.testRunner.timeout = 2000; +buster.testRunner.timeout = 3000; buster.testCase("Sending", { 'setUp' : testutils.test_setup, @@ -23,7 +23,7 @@ buster.testCase("Sending", { var got_proposed; this.remote.transaction() - .payment('root', 'alice', Amount.from_json("10000")) + .payment('root', 'alice', "10000") .on('success', function (r) { // Transaction sent. @@ -88,10 +88,10 @@ buster.testCase("Sending", { .submit(); }, - "credit_limit" : + "// credit_limit" : function (done) { var self = this; - //this.remote.set_trace(); + this.remote.set_trace(); async.waterfall([ function (callback) { @@ -101,11 +101,10 @@ buster.testCase("Sending", { }, function (callback) { this.what = "Check a non-existant credit limit."; + self.remote.request_ripple_balance("alice", "mtgox", "USD", 'CURRENT') .on('ripple_state', function (m) { - buster.assert(false); - - callback(); + callback(true); }) .on('error', function(m) { // console.log("error: %s", JSON.stringify(m)); @@ -118,6 +117,7 @@ buster.testCase("Sending", { }, function (callback) { this.what = "Create a credit limit."; + testutils.credit_limit(self.remote, "alice", "800/USD/mtgox", callback); }, function (callback) { From f4d48f56d8e5e432fc56a06d56451dd5fbc164ea Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 22 Oct 2012 16:56:00 -0700 Subject: [PATCH 12/32] JS: Fix UInt160 comparison. --- js/amount.js | 2 +- test/amount-test.js | 10 +++++++++- test/send-test.js | 6 +++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/js/amount.js b/js/amount.js index ab1524ab9..a01eb1689 100644 --- a/js/amount.js +++ b/js/amount.js @@ -152,7 +152,7 @@ UInt160.prototype.copyTo = function(d) { }; UInt160.prototype.equals = function(d) { - return this.value === d.value; + return isNaN(this.value) || isNaN(d.value) ? false : this.value.equals(d.value); }; // value = NaN on error. diff --git a/test/amount-test.js b/test/amount-test.js index a6cae93f9..a8dce60fa 100644 --- a/test/amount-test.js +++ b/test/amount-test.js @@ -6,7 +6,9 @@ var nbi = jsbn.nbi; var amount = require("../js/amount.js"); var Amount = require("../js/amount.js").Amount; -var UInt160 = require("../js/amount.js").UInt160; +var UInt160 = require("../js/amount.js").UInt160; + +var config = require('./config.js'); buster.testCase("Amount", { "UInt160" : { @@ -25,8 +27,14 @@ buster.testCase("Amount", { "Parse rrrrrrrrrrrrrrrrrrrrBZbvji export" : function () { buster.assert.equals(amount.consts.address_one, UInt160.from_json("rrrrrrrrrrrrrrrrrrrrBZbvji").to_json()); }, + "Parse mtgox export" : function () { + buster.assert.equals(config.accounts["mtgox"].account, UInt160.from_json("mtgox").to_json()); + }, }, "Amount parsing" : { + "Parse 800/USD/mtgox" : function () { + buster.assert.equals("800/USD/"+config.accounts["mtgox"].account, Amount.from_json("800/USD/mtgox").to_text_full()); + }, "Parse native 0" : function () { buster.assert.equals("0/XNS", Amount.from_json("0").to_text_full()); }, diff --git a/test/send-test.js b/test/send-test.js index dcc35d56e..01803a176 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -10,7 +10,7 @@ var testutils = require("./testutils.js"); // How long to wait for server to start. var serverDelay = 1500; -buster.testRunner.timeout = 3000; +buster.testRunner.timeout = 5000; buster.testCase("Sending", { 'setUp' : testutils.test_setup, @@ -88,10 +88,10 @@ buster.testCase("Sending", { .submit(); }, - "// credit_limit" : + "credit_limit" : function (done) { var self = this; - this.remote.set_trace(); + // this.remote.set_trace(); async.waterfall([ function (callback) { From 7bfe50999637a7f0f2d771ac8f7242d8b00fd57a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 22 Oct 2012 21:29:38 -0700 Subject: [PATCH 13/32] JS: Fix Amount.copyTo(). --- js/amount.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/amount.js b/js/amount.js index a01eb1689..ad58e44cb 100644 --- a/js/amount.js +++ b/js/amount.js @@ -318,7 +318,11 @@ Amount.prototype.copyTo = function(d, negate) { d.offset = this.offset; d.is_native = this.is_native; - d.is_negative = this.is_native ? undefined : !this.is_negative; + d.is_negative = this.is_native + ? undefined // Native sign in BigInteger. + : negate + ? !this.is_negative // Negating. + : this.is_negative; // Just copying. this.currency.copyTo(d.currency); this.issuer.copyTo(d.issuer); From 7811850a520db059cc8d584920356ee2f0fe5f88 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 22 Oct 2012 21:30:04 -0700 Subject: [PATCH 14/32] JS: Fix Remote.request_ripple_balnce(). --- js/remote.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/js/remote.js b/js/remote.js index 554411fc6..9fa97054a 100644 --- a/js/remote.js +++ b/js/remote.js @@ -744,16 +744,16 @@ Remote.prototype.request_ripple_balance = function (account, issuer, currency, c var lowLimit = Amount.from_json(node.LowLimit); var highLimit = Amount.from_json(node.HighLimit); - // The amount account holds of issuer (after negation if needed). + // The amount the low account holds of issuer. var balance = Amount.from_json(node.Balance); // accountHigh implies: for account: balance is negated, highLimit is the limit set by account. var accountHigh = UInt160.from_json(account).equals(highLimit.issuer); - // The limit set by issuer. - var issuerLimit = (accountHigh ? lowLimit : highLimit).parse_issuer(issuer); // The limit set by account. var accountLimit = (accountHigh ? highLimit : lowLimit).parse_issuer(account); - var issuerBalance = (accountHigh ? balance.negate() : balance).parse_issuer(issuer); - var accountBalance = issuerBalance.clone().negate().parse_issuer(account); + // The limit set by issuer. + var issuerLimit = (accountHigh ? lowLimit : highLimit).parse_issuer(issuer); + var accountBalance = (accountHigh ? balance.negate() : balance).parse_issuer(account); + var issuerBalance = (accountHigh ? balance : balance.negate()).parse_issuer(issuer); request.emit('ripple_state', { 'issuer_balance' : issuerBalance, // Balance with dst as issuer. From 9ea2fa8c698eb33b3b137a95c4d780b975a1eef9 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 22 Oct 2012 21:30:29 -0700 Subject: [PATCH 15/32] UT: Add another Amount test. --- test/amount-test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/amount-test.js b/test/amount-test.js index a8dce60fa..10f0fac8d 100644 --- a/test/amount-test.js +++ b/test/amount-test.js @@ -88,6 +88,9 @@ buster.testCase("Amount", { "Negate non-native -123" : function () { buster.assert.equals("123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("-123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").negate().to_text_full()); }, + "Clone non-native -123" : function () { + buster.assert.equals("-123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", Amount.from_json("-123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh").clone().to_text_full()); + }, } }); From ef1066cbfa2e7b12c2d0cf54226f7a55b8b3ba85 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 22 Oct 2012 21:31:02 -0700 Subject: [PATCH 16/32] UT: Add a verbose setup short cut. --- test/testutils.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/testutils.js b/test/testutils.js index 605f8e27d..2884aaaa3 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -6,7 +6,7 @@ var Server = require("./server.js").Server; var config = require("./config.js"); -var test_setup = function (done, host) { +var test_setup = function (done, host, verbose) { var self = this; var host = host || config.server_default; @@ -14,11 +14,15 @@ var test_setup = function (done, host) { var data = this.store[host] = this.store[host] || {}; - data.server = Server.from_config(host).on('started', function () { + data.server = Server.from_config(host, verbose).on('started', function () { self.remote = data.remote = Remote.from_config(host).once('ledger_closed', done).connect(); }).start(); }; +var test_setup_verbose = function (done, host) { + test_setup.call(this, done, host, 'VERBOSE'); +} + var test_teardown = function (done, host) { var host = host || config.server_default; @@ -58,7 +62,7 @@ var credit_limit = function (remote, src, amount, callback) { remote.transaction() .ripple_line_set(src, amount) .on('proposed', function (m) { - // console.log("proposed: %s", JSON.stringify(m)); + console.log("proposed: %s", JSON.stringify(m)); // buster.assert.equals(m.result, 'tesSUCCESS'); @@ -72,9 +76,10 @@ var credit_limit = function (remote, src, amount, callback) { .submit(); }; -exports.create_accounts = create_accounts; -exports.credit_limit = credit_limit; -exports.test_setup = test_setup; -exports.test_teardown = test_teardown; +exports.create_accounts = create_accounts; +exports.credit_limit = credit_limit; +exports.test_setup = test_setup; +exports.test_setup_verbose = test_setup_verbose; +exports.test_teardown = test_teardown; // vim:sw=2:sts=2:ts=8 From 0105009d2150d41a76a20c15aff5c4147f6e4287 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 22 Oct 2012 21:33:38 -0700 Subject: [PATCH 17/32] UT: Add more ripple testing. --- test/send-test.js | 296 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 281 insertions(+), 15 deletions(-) diff --git a/test/send-test.js b/test/send-test.js index 01803a176..cd474f752 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -13,7 +13,7 @@ var serverDelay = 1500; buster.testRunner.timeout = 5000; buster.testCase("Sending", { - 'setUp' : testutils.test_setup, + 'setUp' : testutils.test_setup_verbose, 'tearDown' : testutils.test_teardown, "send XNS to non-existant account without create." : @@ -91,16 +91,15 @@ buster.testCase("Sending", { "credit_limit" : function (done) { var self = this; - // this.remote.set_trace(); async.waterfall([ function (callback) { - this.what = "Create account."; + self.what = "Create accounts."; testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback); }, function (callback) { - this.what = "Check a non-existant credit limit."; + self.what = "Check a non-existant credit limit."; self.remote.request_ripple_balance("alice", "mtgox", "USD", 'CURRENT') .on('ripple_state', function (m) { @@ -116,7 +115,7 @@ buster.testCase("Sending", { .request(); }, function (callback) { - this.what = "Create a credit limit."; + self.what = "Create a credit limit."; testutils.credit_limit(self.remote, "alice", "800/USD/mtgox", callback); }, @@ -138,7 +137,7 @@ buster.testCase("Sending", { .request(); }, function (callback) { - this.what = "Modify a credit limit."; + self.what = "Modify a credit limit."; testutils.credit_limit(self.remote, "alice", "700/USD/mtgox", callback); }, @@ -155,12 +154,12 @@ buster.testCase("Sending", { .request(); }, function (callback) { - this.what = "Zero a credit limit."; + self.what = "Zero a credit limit."; testutils.credit_limit(self.remote, "alice", "0/USD/mtgox", callback); }, function (callback) { - this.what = "Make sure still exists."; + self.what = "Make sure still exists."; self.remote.request_ripple_balance("alice", "mtgox", "USD", 'CURRENT') .on('ripple_state', function (m) { @@ -173,17 +172,284 @@ buster.testCase("Sending", { }) .request(); }, - // Check in both owner books. - // Set limit on other side. // Set negative limit. - //function (callback) { - // testutils.credit_limit(self.remote, "alice", "-1/USD/mtgox", callback); - //}, + function (callback) { + self.remote.transaction() + .ripple_line_set("alice", "-1/USD/mtgox") + .on('proposed', function (m) { + buster.assert.equals('temBAD_AMOUNT', m.result); + + // After a malformed transaction, need to recover correct sequence. + self.remote.set_account_seq("alice", self.remote.account_seq("alice")-1); + callback('temBAD_AMOUNT' !== m.result); + }) + .submit(); + }, + // TODO Check in both owner books. + function (callback) { + self.what = "Set another limit."; + + testutils.credit_limit(self.remote, "alice", "600/USD/bob", callback); + }, + function (callback) { + self.what = "Set limit on other side."; + + testutils.credit_limit(self.remote, "bob", "500/USD/alice", callback); + }, + function (callback) { + self.what = "Check ripple_line's state from alice's pov."; + + self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') + .on('ripple_state', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + + buster.assert(m.account_balance.equals("0/USD/alice")); + buster.assert(m.account_limit.equals("600/USD/alice")); + buster.assert(m.issuer_balance.equals("0/USD/bob")); + buster.assert(m.issuer_limit.equals("500/USD/bob")); + + callback(); + }) + .request(); + }, + function (callback) { + self.what = "Check ripple_line's state from bob's pov."; + + self.remote.request_ripple_balance("bob", "alice", "USD", 'CURRENT') + .on('ripple_state', function (m) { + buster.assert(m.account_balance.equals("0/USD/bob")); + buster.assert(m.account_limit.equals("500/USD/bob")); + buster.assert(m.issuer_balance.equals("0/USD/alice")); + buster.assert(m.issuer_limit.equals("600/USD/alice")); + + callback(); + }) + .request(); + }, ], function (error) { - buster.refute(error, this.what); + buster.refute(error, self.what); done(); }); - } + }, +}); + +buster.testCase("Broken Sending", { + 'setUp' : testutils.test_setup_verbose, + 'tearDown' : testutils.test_teardown, + + "// direct ripple" : + function (done) { + var self = this; + + self.remote.set_trace(); + + async.waterfall([ + function (callback) { + self.what = "Create accounts."; + + testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob"], callback); + }, + function (callback) { + self.what = "Set alice's limit."; + + testutils.credit_limit(self.remote, "alice", "600/USD/bob", callback); + }, + function (callback) { + self.what = "Set bob's limit."; + + testutils.credit_limit(self.remote, "bob", "700/USD/alice", callback); + }, + function (callback) { + self.what = "Set alice send bob partial with alice as issuer."; + + self.remote.transaction() + .payment('alice', 'bob', "24/USD/alice") + .on('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + callback(m.result != 'tesSUCCESS'); + }) + .once('final', function (m) { + buster.assert(m.result != 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balance."; + + self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') + .once('ripple_state', function (m) { + console.log("BALANCE: %s", JSON.stringify(m)); + console.log("account_balance: %s", m.account_balance.to_text_full()); + console.log("account_limit: %s", m.account_limit.to_text_full()); + console.log("issuer_balance: %s", m.issuer_balance.to_text_full()); + console.log("issuer_limit: %s", m.issuer_limit.to_text_full()); + + buster.assert(m.account_balance.equals("-24/USD/alice")); + buster.assert(m.issuer_balance.equals("24/USD/bob")); + + callback(); + }) + .request(); + }, + function (callback) { + self.what = "Set alice send bob more with bob as issuer."; + + self.remote.transaction() + .payment('alice', 'bob', "33/USD/bob") + .once('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + callback(m.result != 'tesSUCCESS'); + }) + .once('final', function (m) { + buster.assert(m.result != 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balance from bob's pov."; + + self.remote.request_ripple_balance("bob", "alice", "USD", 'CURRENT') + .once('ripple_state', function (m) { + buster.assert(m.account_balance.equals("57/USD/bob")); + buster.assert(m.issuer_balance.equals("-57/USD/alice")); + + callback(); + }) + .request(); + }, + function (callback) { + self.what = "Bob send back more than sent."; + + self.remote.transaction() + .payment('bob', 'alice', "90/USD/bob") + .once('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + callback(m.result != 'tesSUCCESS'); + }) + .once('final', function (m) { + buster.assert(m.result != 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balance from alice's pov."; + + self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') + .once('ripple_state', function (m) { + buster.assert(m.account_balance.equals("33/USD/alice")); + + callback(); + }) + .request(); + }, + function (callback) { + self.what = "Alice send to limit."; + + self.remote.transaction() + .payment('alice', 'bob', "733/USD/bob") + .once('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + callback(m.result != 'tesSUCCESS'); + }) + .once('final', function (m) { + buster.assert(m.result != 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balance from alice's pov."; + + self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') + .once('ripple_state', function (m) { + buster.assert(m.account_balance.equals("-700/USD/alice")); + + callback(); + }) + .request(); + }, + function (callback) { + self.what = "Bob send to limit."; + + self.remote.transaction() + .payment('bob', 'alice', "1300/USD/bob") + .once('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + callback(m.result != 'tesSUCCESS'); + }) + .once('final', function (m) { + buster.assert(m.result != 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balance from alice's pov."; + + self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') + .once('ripple_state', function (m) { + buster.assert(m.account_balance.equals("600/USD/alice")); + + callback(); + }) + .request(); + }, +// function (callback) { +// // If this gets applied out of order, it could stop the big payment. +// self.what = "Bob send past limit."; +// +// self.remote.transaction() +// .payment('bob', 'alice', "1/USD/bob") +// .once('proposed', function (m) { +// // console.log("proposed: %s", JSON.stringify(m)); +// callback(m.result != 'tepPATH_PARTIAL'); +// }) +// .submit(); +// }, + function (callback) { + self.what = "Verify balance from alice's pov."; + + self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') + .once('ripple_state', function (m) { + buster.assert(m.account_balance.equals("600/USD/alice")); + + callback(); + }) + .request(); + }, + function (callback) { + // Make sure all is good after canonical ordering. + self.what = "Close the ledger and check balance."; + + self.remote + .once('ledger_closed', function (ledger_closed, ledger_closed_index) { + // console.log("LEDGER_CLOSED: A: %d: %s", ledger_closed_index, ledger_closed); + callback(); + }) + .ledger_accept(); + }, + function (callback) { + self.what = "Verify balance from alice's pov."; + + self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') + .once('ripple_state', function (m) { + console.log("account_balance: %s", m.account_balance.to_text_full()); + console.log("account_limit: %s", m.account_limit.to_text_full()); + console.log("issuer_balance: %s", m.issuer_balance.to_text_full()); + console.log("issuer_limit: %s", m.issuer_limit.to_text_full()); + + buster.assert(m.account_balance.equals("600/USD/alice")); + + callback(); + }) + .request(); + }, + ], function (error) { + buster.refute(error, self.what); + done(); + }); + }, + + // Ripple without credit path. + // Ripple with one-way credit path. }); // vim:sw=2:sts=2:ts=8 From 72f434c670cc5de079c786510c0aa4d9519152db Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 22 Oct 2012 21:40:26 -0700 Subject: [PATCH 18/32] UT: Quiet tests. --- test/send-test.js | 2 +- test/testutils.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/send-test.js b/test/send-test.js index cd474f752..f60208036 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -13,7 +13,7 @@ var serverDelay = 1500; buster.testRunner.timeout = 5000; buster.testCase("Sending", { - 'setUp' : testutils.test_setup_verbose, + 'setUp' : testutils.test_setup, 'tearDown' : testutils.test_teardown, "send XNS to non-existant account without create." : diff --git a/test/testutils.js b/test/testutils.js index 2884aaaa3..8d9c337af 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -62,9 +62,7 @@ var credit_limit = function (remote, src, amount, callback) { remote.transaction() .ripple_line_set(src, amount) .on('proposed', function (m) { - console.log("proposed: %s", JSON.stringify(m)); - - // buster.assert.equals(m.result, 'tesSUCCESS'); + // console.log("proposed: %s", JSON.stringify(m)); callback(m.result != 'tesSUCCESS'); }) From 1a20295e163e606c949a95a2839decce47e2a330 Mon Sep 17 00:00:00 2001 From: Stefan Thomas Date: Tue, 23 Oct 2012 17:52:18 +0200 Subject: [PATCH 19/32] Remove tx invalid assertion - exception should be enough. Jed's words, not mine. ;) --- src/SerializedTransaction.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index dbe3ffbf2..a7c26357a 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -25,7 +25,6 @@ SerializedTransaction::SerializedTransaction(const STObject& object) : STObject( throw std::runtime_error("invalid transaction type"); if (!setType(mFormat->elements)) { - assert(false); throw std::runtime_error("transaction not valid"); } } From 67c87a9d13dbbe3eb95e205d91d4cf74937416e0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 23 Oct 2012 11:05:17 -0700 Subject: [PATCH 20/32] Add a few test vectors. --- src/DeterministicKeys.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/DeterministicKeys.cpp b/src/DeterministicKeys.cpp index 2c5241a58..ce2a9cd7f 100644 --- a/src/DeterministicKeys.cpp +++ b/src/DeterministicKeys.cpp @@ -9,7 +9,10 @@ // Functions to add CKey support for deterministic EC keys +#include + #include "Serializer.h" +#include "Log.h" // <-- seed uint128 CKey::PassPhraseToKey(const std::string& passPhrase) @@ -304,4 +307,34 @@ EC_KEY* CKey::GeneratePrivateDeterministicKey(const NewcoinAddress& pubGen, cons return pkey; } +BOOST_AUTO_TEST_SUITE(DeterministicKeys_test) + +BOOST_AUTO_TEST_CASE(DeterminsticKeys_test1) +{ + Log(lsDEBUG) << "Beginning deterministic key test"; + + uint128 seed1, seed2; + seed1.SetHex("71ED064155FFADFA38782C5E0158CB26"); + seed2.SetHex("CF0C3BE4485961858C4198515AE5B965"); + CKey root1(seed1), root2(seed2); + + uint256 priv1, priv2; + root1.GetPrivateKeyU(priv1); + root2.GetPrivateKeyU(priv2); + + if (priv1.GetHex() != "7CFBA64F771E93E817E15039215430B53F7401C34931D111EAB3510B22DBB0D8") + BOOST_FAIL("Incorrect private key for generator"); + if (priv2.GetHex() != "98BC2EACB26EB021D1A6293C044D88BA2F0B6729A2772DEEBF2E21A263C1740B") + BOOST_FAIL("Incorrect private key for generator"); + + NewcoinAddress nSeed; + nSeed.setSeed(seed1); + if (nSeed.humanSeed() != "shHM53KPZ87Gwdqarm1bAmPeXg8Tn") + BOOST_FAIL("Incorrect human seed"); + if (nSeed.humanSeed1751() != "MAD BODY ACE MINT OKAY HUB WHAT DATA SACK FLAT DANA MATH") + BOOST_FAIL("Incorrect 1751 seed"); +} + +BOOST_AUTO_TEST_SUITE_END(); + // vim:ts=4 From 756e628f93313a379b20a879630fa7590ec60ace Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 23 Oct 2012 11:22:37 -0700 Subject: [PATCH 21/32] Add an STObject::operator== that is sensible. --- src/SerializedObject.cpp | 37 ++++++++++++++++++++++++++++++++++++- src/SerializedObject.h | 3 +++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index d6bce836c..e69fd32d6 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -792,6 +792,42 @@ Json::Value STObject::getJson(int options) const return ret; } +bool STObject::operator==(const STObject& obj) const +{ // This is not particularly efficient, and only compares data elements with binary representations + int matches = 0; + BOOST_FOREACH(const SerializedType& t, mData) + if ((t.getSType() != STI_NOTPRESENT) && t.getFName().isBinary()) + { // each present field must have a matching field + bool match = false; + BOOST_FOREACH(const SerializedType& t2, obj.mData) + if (t.getFName() == t2.getFName()) + { + if (t2 != t) + return false; + match = true; + ++matches; + break; + } + if (!match) + { + Log(lsTRACE) << "STObject::operator==: no match for " << t.getFName().getName(); + return false; + } + } + + int fields = 0; + BOOST_FOREACH(const SerializedType& t2, obj.mData) + if ((t2.getSType() != STI_NOTPRESENT) && t2.getFName().isBinary()) + ++fields; + + if (fields != matches) + { + Log(lsTRACE) << "STObject::operator==: " << fields << " fields, " << matches << " matches"; + return false; + } + return true; +} + Json::Value STVector256::getJson(int options) const { Json::Value ret(Json::arrayValue); @@ -1246,7 +1282,6 @@ BOOST_AUTO_TEST_CASE( FieldManipulation_test ) if (object1.getFieldVL(sfTestVL) != j) BOOST_FAIL("STObject error"); if (object3.getFieldVL(sfTestVL) != j) BOOST_FAIL("STObject error"); } - } BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 0c9425917..e1f7b0021 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -148,6 +148,9 @@ public: { return makeDefaultObject(STI_NOTPRESENT, name); } static std::auto_ptr makeDefaultObject(SField::ref name) { return makeDefaultObject(name.fieldType, name); } + + bool operator==(const STObject& o) const; + bool operator!=(const STObject& o) const { return ! (*this == o); } }; class STArray : public SerializedType From bb4cc37e5845a816cd56b01fb9930b55ce2e0673 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 23 Oct 2012 11:22:56 -0700 Subject: [PATCH 22/32] Remove chatty debug. --- src/Amount.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 8abd8bbfc..2280d7032 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -166,8 +166,6 @@ STAmount::STAmount(SField::ref n, const Json::Value& v) } else throw std::runtime_error("invalid amount type"); - - cLog(lsTRACE) << "Parsed: " << this->getJson(0); } std::string STAmount::createHumanCurrency(const uint160& uCurrency) From 61de7a974613555508b14bc21ce45e63d4e94737 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 23 Oct 2012 11:23:09 -0700 Subject: [PATCH 23/32] Clean up this unit test. --- src/SerializedTransaction.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index a7c26357a..53f35ba09 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -202,8 +202,8 @@ BOOST_AUTO_TEST_CASE( STrans_test ) NewcoinAddress seed; seed.setSeedRandom(); NewcoinAddress generator = NewcoinAddress::createGeneratorPublic(seed); - NewcoinAddress publicAcct = NewcoinAddress::createAccountPublic(generator, 1); - NewcoinAddress privateAcct = NewcoinAddress::createAccountPrivate(generator, seed, 1); + NewcoinAddress publicAcct = NewcoinAddress::createAccountPublic(generator, 1); + NewcoinAddress privateAcct = NewcoinAddress::createAccountPrivate(generator, seed, 1); SerializedTransaction j(ttCLAIM); j.setSourceAccount(publicAcct); @@ -223,10 +223,15 @@ BOOST_AUTO_TEST_CASE( STrans_test ) Log(lsFATAL) << copy.getJson(0); BOOST_FAIL("Transaction fails serialize/deserialize test"); } - Log(lsINFO) << "ORIG: " << j.getJson(0); std::auto_ptr new_obj = STObject::parseJson(j.getJson(0), sfGeneric); if (new_obj.get() == NULL) BOOST_FAIL("Unable to build object from json"); - Log(lsINFO) << "BUILT " << new_obj->getJson(0); + + if (STObject(j) != *new_obj) + { + Log(lsINFO) << "ORIG: " << j.getJson(0); + Log(lsINFO) << "BUILT " << new_obj->getJson(0); + BOOST_FAIL("Built a different transaction"); + } } BOOST_AUTO_TEST_SUITE_END(); From 6da5d508a77de9dc1c4f92475313a460043685f0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 23 Oct 2012 11:49:16 -0700 Subject: [PATCH 24/32] Improve the warning messages when STObject::setType fails. --- src/SerializedObject.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index e69fd32d6..0742dcbfe 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -164,7 +164,8 @@ bool STObject::setType(const std::vector &type) { if (elem->flags != SOE_OPTIONAL) { - cLog(lsWARNING) << "setType !valid missing " << elem->e_field.fieldName; + cLog(lsWARNING) << "setType( " << getFName().getName() << ") invalid missing " + << elem->e_field.fieldName; valid = false; } newData.push_back(makeNonPresentObject(elem->e_field)); @@ -178,7 +179,8 @@ bool STObject::setType(const std::vector &type) { if (!t.getFName().isDiscardable()) { - cLog(lsWARNING) << "setType !valid leftover: " << t.getFName().getName(); + cLog(lsWARNING) << "setType( " << getFName().getName() << ") invalid leftover " + << t.getFName().getName(); valid = false; } } From 3650e6122c62dbbcc55e6c74cbf2fe369d9dd5c0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 23 Oct 2012 11:56:05 -0700 Subject: [PATCH 25/32] JS: Optimize base58 decoding. --- js/amount.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/amount.js b/js/amount.js index ad58e44cb..d2da47a05 100644 --- a/js/amount.js +++ b/js/amount.js @@ -52,10 +52,10 @@ var decode_base = function (input, alphabet) { var bi_value = nbi(); var i; - while (i != input.length && input[i] === alphabet[0]) - i += 1; + for (i = 0; i != input.length && input[i] === alphabet[0]; i += 1) + ; - for (i = 0; i != input.length; i += 1) { + for (; i != input.length; i += 1) { var v = alphabet.indexOf(input[i]); if (v < 0) From 6e2637356caa32c31049c71bbbed2f03d144a5fa Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 23 Oct 2012 12:05:30 -0700 Subject: [PATCH 26/32] UT: Enable some ripple unit tests. --- test/send-test.js | 101 +++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/test/send-test.js b/test/send-test.js index f60208036..3d53e7d06 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -12,7 +12,7 @@ var serverDelay = 1500; buster.testRunner.timeout = 5000; -buster.testCase("Sending", { +buster.testCase("// Sending", { 'setUp' : testutils.test_setup, 'tearDown' : testutils.test_teardown, @@ -233,11 +233,12 @@ buster.testCase("Sending", { }, }); -buster.testCase("Broken Sending", { - 'setUp' : testutils.test_setup_verbose, +// XXX In the future add ledger_accept after partial retry is implemented in the server. +buster.testCase("Sending future", { + 'setUp' : testutils.test_setup, 'tearDown' : testutils.test_teardown, - "// direct ripple" : + "direct ripple" : function (done) { var self = this; @@ -384,6 +385,29 @@ buster.testCase("Broken Sending", { function (callback) { self.what = "Verify balance from alice's pov."; + self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') + .once('ripple_state', function (m) { + buster.assert(m.account_balance.equals("600/USD/alice")); + + callback(); + }) + .request(); + }, + function (callback) { + // If this gets applied out of order, it could stop the big payment. + self.what = "Bob send past limit."; + + self.remote.transaction() + .payment('bob', 'alice', "1/USD/bob") + .once('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + callback(m.result != 'tepPATH_PARTIAL'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balance from alice's pov."; + self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') .once('ripple_state', function (m) { buster.assert(m.account_balance.equals("600/USD/alice")); @@ -393,55 +417,32 @@ buster.testCase("Broken Sending", { .request(); }, // function (callback) { -// // If this gets applied out of order, it could stop the big payment. -// self.what = "Bob send past limit."; +// // Make sure all is good after canonical ordering. +// self.what = "Close the ledger and check balance."; // -// self.remote.transaction() -// .payment('bob', 'alice', "1/USD/bob") -// .once('proposed', function (m) { -// // console.log("proposed: %s", JSON.stringify(m)); -// callback(m.result != 'tepPATH_PARTIAL'); +// self.remote +// .once('ledger_closed', function (ledger_closed, ledger_closed_index) { +// // console.log("LEDGER_CLOSED: A: %d: %s", ledger_closed_index, ledger_closed); +// callback(); // }) -// .submit(); +// .ledger_accept(); +// }, +// function (callback) { +// self.what = "Verify balance from alice's pov."; +// +// self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') +// .once('ripple_state', function (m) { +// console.log("account_balance: %s", m.account_balance.to_text_full()); +// console.log("account_limit: %s", m.account_limit.to_text_full()); +// console.log("issuer_balance: %s", m.issuer_balance.to_text_full()); +// console.log("issuer_limit: %s", m.issuer_limit.to_text_full()); +// +// buster.assert(m.account_balance.equals("600/USD/alice")); +// +// callback(); +// }) +// .request(); // }, - function (callback) { - self.what = "Verify balance from alice's pov."; - - self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') - .once('ripple_state', function (m) { - buster.assert(m.account_balance.equals("600/USD/alice")); - - callback(); - }) - .request(); - }, - function (callback) { - // Make sure all is good after canonical ordering. - self.what = "Close the ledger and check balance."; - - self.remote - .once('ledger_closed', function (ledger_closed, ledger_closed_index) { - // console.log("LEDGER_CLOSED: A: %d: %s", ledger_closed_index, ledger_closed); - callback(); - }) - .ledger_accept(); - }, - function (callback) { - self.what = "Verify balance from alice's pov."; - - self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT') - .once('ripple_state', function (m) { - console.log("account_balance: %s", m.account_balance.to_text_full()); - console.log("account_limit: %s", m.account_limit.to_text_full()); - console.log("issuer_balance: %s", m.issuer_balance.to_text_full()); - console.log("issuer_limit: %s", m.issuer_limit.to_text_full()); - - buster.assert(m.account_balance.equals("600/USD/alice")); - - callback(); - }) - .request(); - }, ], function (error) { buster.refute(error, self.what); done(); From b7a40435b8ccf081a99f27dbbc5f5e275eeada54 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 23 Oct 2012 12:48:09 -0700 Subject: [PATCH 27/32] Document future direction of Transaction. --- src/Transaction.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Transaction.h b/src/Transaction.h index f9101cf49..9e0f3f667 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -1,6 +1,11 @@ #ifndef __TRANSACTION__ #define __TRANSACTION__ +// +// Notes: this code contains legacy constructored sharedXYZ and setXYZ. The intent is for these functions to go away. Transactions +// should now be constructed in JSON with. Use STObject::parseJson to obtain a binary version. +// + #include #include From cb2fb10b6535d5d36d4e61ecc31f1d9430ebd517 Mon Sep 17 00:00:00 2001 From: Stefan Thomas Date: Tue, 23 Oct 2012 22:39:30 +0200 Subject: [PATCH 28/32] UT: Added verbosity and no_server options to setUp routine. --- test/offer-test.js | 2 +- test/remote-test.js | 2 +- test/send-test.js | 4 +-- test/testutils.js | 86 ++++++++++++++++++++++++++++++++++----------- 4 files changed, 69 insertions(+), 25 deletions(-) diff --git a/test/offer-test.js b/test/offer-test.js index 590d3f262..9407a7917 100644 --- a/test/offer-test.js +++ b/test/offer-test.js @@ -11,7 +11,7 @@ var testutils = require("./testutils.js"); buster.testRunner.timeout = 5000; buster.testCase("Offer tests", { - 'setUp' : testutils.test_setup, + 'setUp' : testutils.build_setup(), 'tearDown' : testutils.test_teardown, "offer create then cancel in one ledger" : diff --git a/test/remote-test.js b/test/remote-test.js index a22230af0..94d896f49 100644 --- a/test/remote-test.js +++ b/test/remote-test.js @@ -14,7 +14,7 @@ var serverDelay = 1500; // XXX Not implemented. buster.testRunner.timeout = 5000; buster.testCase("Remote functions", { - 'setUp' : testutils.test_setup, + 'setUp' : testutils.build_setup(), 'tearDown' : testutils.test_teardown, 'request_ledger_current' : diff --git a/test/send-test.js b/test/send-test.js index 3d53e7d06..f98e08e46 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -13,7 +13,7 @@ var serverDelay = 1500; buster.testRunner.timeout = 5000; buster.testCase("// Sending", { - 'setUp' : testutils.test_setup, + 'setUp' : testutils.build_setup(), 'tearDown' : testutils.test_teardown, "send XNS to non-existant account without create." : @@ -235,7 +235,7 @@ buster.testCase("// Sending", { // XXX In the future add ledger_accept after partial retry is implemented in the server. buster.testCase("Sending future", { - 'setUp' : testutils.test_setup, + 'setUp' : testutils.build_setup(), 'tearDown' : testutils.test_teardown, "direct ripple" : diff --git a/test/testutils.js b/test/testutils.js index 8d9c337af..bb04d40fc 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -6,33 +6,78 @@ var Server = require("./server.js").Server; var config = require("./config.js"); -var test_setup = function (done, host, verbose) { - var self = this; - var host = host || config.server_default; +/** + * Helper called by test cases to generate a setUp routine. + * + * By default you would call this without options, but it is useful to + * be able to plug options in during development for quick and easy + * debugging. + * + * @example + * buster.testCase("Foobar", { + * setUp: testutils.build_setup({verbose: true}), + * // ... + * }); + * + * @param host {String} Identifier for the host configuration to be used. + * @param opts {Object} These options allow quick-and-dirty test-specific + * customizations of your test environment. + * @param opts.verbose {Bool} Enable all debug output (then cover your ears + * and run) + * @param opts.verbose_ws {Bool} Enable tracing in the Remote class. Prints + * websocket traffic. + * @param opts.verbose_server {Bool} Set the -v option when running rippled. + * @param opts.no_server {Bool} Don't auto-run rippled. + */ +var build_setup = function (opts) { + opts = this.opts = opts || {}; - this.store = this.store || {}; + // Normalize options + if (opts.verbose) { + opts.verbose_ws = true; + opts.verbose_server = true; + }; - var data = this.store[host] = this.store[host] || {}; + return function (done) { + var self = this; - data.server = Server.from_config(host, verbose).on('started', function () { - self.remote = data.remote = Remote.from_config(host).once('ledger_closed', done).connect(); - }).start(); + var host = host || config.server_default; + + this.store = this.store || {}; + + var data = this.store[host] = this.store[host] || {}; + + async.series([ + function runServerStep(callback) { + if (opts.no_server) return callback(); + + data.server = Server.from_config(host, !!opts.verbose_server).on('started', callback).start(); + }, + function connectWebsocketStep(callback) { + self.remote = data.remote = Remote.from_config(host, !!opts.verbose_ws).once('ledger_closed', callback).connect(); + } + ], done); + }; }; -var test_setup_verbose = function (done, host) { - test_setup.call(this, done, host, 'VERBOSE'); -} +var test_teardown = function (done, host) { + host = host || config.server_default; -var test_teardown = function (done, host) { - var host = host || config.server_default; + var data = this.store[host]; + var opts = this.opts; - var data = this.store[host]; + async.series([ + function disconnectWebsocketStep(callback) { + data.remote + .on('disconnected', callback) + .connect(false); + }, + function stopServerStep(callback) { + if (opts.no_server) return callback(); - data.remote - .on('disconnected', function () { - data.server.on('stopped', done).stop(); - }) - .connect(false); + data.server.on('stopped', callback).stop(); + } + ], done); }; var create_accounts = function (remote, src, amount, accounts, callback) { @@ -76,8 +121,7 @@ var credit_limit = function (remote, src, amount, callback) { exports.create_accounts = create_accounts; exports.credit_limit = credit_limit; -exports.test_setup = test_setup; -exports.test_setup_verbose = test_setup_verbose; +exports.build_setup = build_setup; exports.test_teardown = test_teardown; // vim:sw=2:sts=2:ts=8 From 5684a8e23356c6ab953c6e206e7a7459cf2957b3 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 23 Oct 2012 17:03:38 -0700 Subject: [PATCH 29/32] LedgerAcquireSet code to acquire a set of ledgers to restore a chain. --- src/LedgerAcquire.cpp | 137 ++++++++++++++++++++++++++++++++++++------ src/LedgerAcquire.h | 26 ++++++++ 2 files changed, 146 insertions(+), 17 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 7f638c7af..0ebb7c470 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -10,6 +10,8 @@ #include "SHAMapSync.h" #include "HashPrefixes.h" +SETUP_LOG(); + // #define LA_DEBUG #define LEDGER_ACQUIRE_TIMEOUT 750 #define TRUST_NETWORK @@ -72,7 +74,7 @@ void PeerSet::invokeOnTimer() if (!mProgress) { ++mTimeouts; - Log(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash; + cLog(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash; } else mProgress = false; @@ -92,7 +94,7 @@ LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false) { #ifdef LA_DEBUG - Log(lsTRACE) << "Acquiring ledger " << mHash; + cLog(lsTRACE) << "Acquiring ledger " << mHash; #endif } @@ -156,7 +158,7 @@ void LedgerAcquire::done() return; mSignaled = true; #ifdef LA_DEBUG - Log(lsTRACE) << "Done acquiring ledger " << mHash; + cLog(lsTRACE) << "Done acquiring ledger " << mHash; #endif std::vector< boost::function > triggers; @@ -185,12 +187,12 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer) if (mAborted || mComplete || mFailed) return; #ifdef LA_DEBUG - if (peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP(); - else Log(lsTRACE) << "Trigger acquiring ledger " << mHash; + if (peer) cLog(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP(); + else cLog(lsTRACE) << "Trigger acquiring ledger " << mHash; if (mComplete || mFailed) - Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed; + cLog(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed; else - Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState; + cLog(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState; #endif if (!mHaveBase) { @@ -204,7 +206,7 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer) if (mHaveBase && !mHaveTransactions) { #ifdef LA_DEBUG - Log(lsTRACE) << "need tx"; + cLog(lsTRACE) << "need tx"; #endif assert(mLedger); if (mLedger->peekTransactionMap()->getHash().isZero()) @@ -248,7 +250,7 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer) if (mHaveBase && !mHaveState) { #ifdef LA_DEBUG - Log(lsTRACE) << "need as"; + cLog(lsTRACE) << "need as"; #endif assert(mLedger); if (mLedger->peekAccountStateMap()->getHash().isZero()) @@ -352,15 +354,15 @@ int PeerSet::getPeerCount() const bool LedgerAcquire::takeBase(const std::string& data) { // Return value: true=normal, false=bad data #ifdef LA_DEBUG - Log(lsTRACE) << "got base acquiring ledger " << mHash; + cLog(lsTRACE) << "got base acquiring ledger " << mHash; #endif boost::recursive_mutex::scoped_lock sl(mLock); if (mHaveBase) return true; mLedger = boost::make_shared(data); if (mLedger->getHash() != mHash) { - Log(lsWARNING) << "Acquire hash mismatch"; - Log(lsWARNING) << mLedger->getHash() << "!=" << mHash; + cLog(lsWARNING) << "Acquire hash mismatch"; + cLog(lsWARNING) << mLedger->getHash() << "!=" << mHash; mLedger = Ledger::pointer(); #ifdef TRUST_NETWORK assert(false); @@ -419,7 +421,7 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, const std::list< std::vector >& data) { #ifdef LA_DEBUG - Log(lsTRACE) << "got ASdata acquiring ledger " << mHash; + cLog(lsTRACE) << "got ASdata acquiring ledger " << mHash; #endif if (!mHaveBase) return false; std::list::const_iterator nodeIDit = nodeIDs.begin(); @@ -502,7 +504,7 @@ void LedgerAcquireMaster::dropLedger(const uint256& hash) bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref peer) { #ifdef LA_DEBUG - Log(lsTRACE) << "got data for acquiring ledger "; + cLog(lsTRACE) << "got data for acquiring ledger "; #endif uint256 hash; if (packet.ledgerhash().size() != 32) @@ -512,7 +514,7 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref } memcpy(hash.begin(), packet.ledgerhash().data(), 32); #ifdef LA_DEBUG - Log(lsTRACE) << hash; + cLog(lsTRACE) << hash; #endif LedgerAcquire::pointer ledger = find(hash); @@ -532,7 +534,7 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref } if (!ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata()))) { - Log(lsWARNING) << "Included ASbase invalid"; + cLog(lsWARNING) << "Included ASbase invalid"; } if (packet.nodes().size() == 2) { @@ -540,7 +542,9 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref return true; } if (!ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata()))) - Log(lsWARNING) << "Invcluded TXbase invalid"; + { + cLog(lsWARNING) << "Invcluded TXbase invalid"; + } ledger->trigger(peer, false); return true; } @@ -571,4 +575,103 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref return false; } + +LedgerAcquireSet::LedgerAcquireSet(Ledger::ref targetLedger, Ledger::ref currentLedger) : + mTargetLedger(targetLedger), mCheckComplete(true) +{ + updateCurrentLedger(currentLedger); +} + +void LedgerAcquireSet::updateCurrentLedger(Ledger::pointer currentLedger) +{ // We have 'currentLedger', what do we need to acquire next + + while (1) + { + + if ((currentLedger->getHash() == mTargetLedger->getHash()) || + (currentLedger->getParentHash() == mTargetLedger->getHash())) + { // We have completed acquiring the set + done(); + return; + } + + while (mTargetLedger->getLedgerSeq() >= currentLedger->getLedgerSeq()) + { // We need to back up our target + mTargetLedger = theApp->getMasterLedger().getLedgerByHash(mTargetLedger->getParentHash()); + if (!mTargetLedger) + { + cLog(lsWARNING) << "LedgerAcquireSet encountered a non-present target ledger"; + done(); + return; + } + } + + Ledger::pointer nextLedger = + theApp->getMasterLedger().getLedgerByHash(currentLedger->getParentHash()); + + if (nextLedger && mCheckComplete && !nextLedger->walkLedger()) + { + cLog(lsINFO) << "Acquire set has encountered a ledger that is missing nodes"; + nextLedger = Ledger::pointer(); + } + + if (!nextLedger) + { // the next ledger we need is missing or missing nodes + LedgerAcquire::pointer nextAcquire = + theApp->getMasterLedgerAcquire().findCreate(currentLedger->getParentHash()); + if (mCurrentLedger) + nextAcquire->takePeerSetFrom(*mCurrentLedger); + mCurrentLedger = nextAcquire; + if (!mCurrentLedger->getPeerCount()) + addPeers(); + mCurrentLedger->addOnComplete(boost::bind( + &LedgerAcquireSet::onComplete, boost::weak_ptr(shared_from_this()), _1)); + return; + } + currentLedger = nextLedger; + } +} + +void LedgerAcquireSet::onComplete(boost::weak_ptr set, LedgerAcquire::pointer acquired) +{ + LedgerAcquireSet::pointer lSet = set.lock(); + if (!lSet) + return; + + if (acquired->isComplete()) + lSet->updateCurrentLedger(acquired->getLedger()); + else + { + cLog(lsWARNING) << "Bailing on LedgerAcquireSet due to failure to acquire a ledger"; + lSet->done(); + } +} + +void LedgerAcquireSet::done() +{ + theApp->getMasterLedgerAcquire().killSet(*this); +} + +void LedgerAcquireSet::addPeers() +{ + std::vector peerList = theApp->getConnectionPool().getPeerVector(); + const uint256& hash = mCurrentLedger->getHash(); + + bool found = false; + BOOST_FOREACH(Peer::ref peer, peerList) + { + if (peer->hasLedger(hash)) + { + found = true; + mCurrentLedger->peerHas(peer); + } + } + + if (!found) + { + BOOST_FOREACH(Peer::ref peer, peerList) + mCurrentLedger->peerHas(peer); + } +} + // vim:ts=4 diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index 354ad1593..a07dbccd8 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -100,11 +100,32 @@ public: bool tryLocal(); }; +class LedgerAcquireSet : public boost::enable_shared_from_this +{ // a sequence of ledgers we are retreiving +public: + typedef boost::shared_ptr pointer; + +protected: + Ledger::pointer mTargetLedger; // ledger we have and want to get back to + LedgerAcquire::pointer mCurrentLedger; // ledger we are acquiring + bool mCheckComplete; // should we check to make sure we have all nodes + + void updateCurrentLedger(Ledger::pointer currentLedger); + void done(); + void addPeers(); + + static void onComplete(boost::weak_ptr, LedgerAcquire::pointer); + +public: + LedgerAcquireSet(Ledger::ref targetLedger, Ledger::ref currentLedger); +}; + class LedgerAcquireMaster { protected: boost::mutex mLock; std::map mLedgers; + LedgerAcquireSet::pointer mAcquireSet; public: LedgerAcquireMaster() { ; } @@ -114,6 +135,11 @@ public: bool hasLedger(const uint256& ledgerHash); void dropLedger(const uint256& ledgerHash); bool gotLedgerData(ripple::TMLedgerData& packet, Peer::ref); + + void killSet(const LedgerAcquireSet&) + { mAcquireSet = LedgerAcquireSet::pointer(); } + void makeSet(Ledger::ref target, Ledger::ref current) + { mAcquireSet = boost::make_shared(boost::ref(target), boost::ref(current)); } }; #endif From bbec036837edbb2670d0478dbea5d6a085bc73dc Mon Sep 17 00:00:00 2001 From: Stefan Thomas Date: Wed, 24 Oct 2012 09:35:31 +0200 Subject: [PATCH 30/32] UT: Fixed host configurations and having multiple instances of test suite. --- test/offer-test.js | 2 +- test/remote-test.js | 2 +- test/send-test.js | 4 ++-- test/testutils.js | 55 ++++++++++++++++++++++++++------------------- 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/test/offer-test.js b/test/offer-test.js index 9407a7917..0efe31651 100644 --- a/test/offer-test.js +++ b/test/offer-test.js @@ -12,7 +12,7 @@ buster.testRunner.timeout = 5000; buster.testCase("Offer tests", { 'setUp' : testutils.build_setup(), - 'tearDown' : testutils.test_teardown, + 'tearDown' : testutils.build_teardown(), "offer create then cancel in one ledger" : function (done) { diff --git a/test/remote-test.js b/test/remote-test.js index 94d896f49..eec201357 100644 --- a/test/remote-test.js +++ b/test/remote-test.js @@ -15,7 +15,7 @@ buster.testRunner.timeout = 5000; buster.testCase("Remote functions", { 'setUp' : testutils.build_setup(), - 'tearDown' : testutils.test_teardown, + 'tearDown' : testutils.build_teardown(), 'request_ledger_current' : function (done) { diff --git a/test/send-test.js b/test/send-test.js index f98e08e46..ea1ae9491 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -14,7 +14,7 @@ buster.testRunner.timeout = 5000; buster.testCase("// Sending", { 'setUp' : testutils.build_setup(), - 'tearDown' : testutils.test_teardown, + 'tearDown' : testutils.build_teardown(), "send XNS to non-existant account without create." : function (done) { @@ -236,7 +236,7 @@ buster.testCase("// Sending", { // XXX In the future add ledger_accept after partial retry is implemented in the server. buster.testCase("Sending future", { 'setUp' : testutils.build_setup(), - 'tearDown' : testutils.test_teardown, + 'tearDown' : testutils.build_teardown(), "direct ripple" : function (done) { diff --git a/test/testutils.js b/test/testutils.js index bb04d40fc..26d04551d 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -19,7 +19,6 @@ var config = require("./config.js"); * // ... * }); * - * @param host {String} Identifier for the host configuration to be used. * @param opts {Object} These options allow quick-and-dirty test-specific * customizations of your test environment. * @param opts.verbose {Bool} Enable all debug output (then cover your ears @@ -28,9 +27,10 @@ var config = require("./config.js"); * websocket traffic. * @param opts.verbose_server {Bool} Set the -v option when running rippled. * @param opts.no_server {Bool} Don't auto-run rippled. + * @param host {String} Identifier for the host configuration to be used. */ -var build_setup = function (opts) { - opts = this.opts = opts || {}; +var build_setup = function (opts, host) { + opts = opts || {}; // Normalize options if (opts.verbose) { @@ -41,12 +41,14 @@ var build_setup = function (opts) { return function (done) { var self = this; - var host = host || config.server_default; + host = host || config.server_default; this.store = this.store || {}; var data = this.store[host] = this.store[host] || {}; + data.opts = opts; + async.series([ function runServerStep(callback) { if (opts.no_server) return callback(); @@ -60,24 +62,31 @@ var build_setup = function (opts) { }; }; -var test_teardown = function (done, host) { - host = host || config.server_default; +/** + * Generate tearDown routine. + * + * @param host {String} Identifier for the host configuration to be used. + */ +var build_teardown = function (host) { + return function (done) { + host = host || config.server_default; - var data = this.store[host]; - var opts = this.opts; + var data = this.store[host]; + var opts = data.opts; - async.series([ - function disconnectWebsocketStep(callback) { - data.remote - .on('disconnected', callback) - .connect(false); - }, - function stopServerStep(callback) { - if (opts.no_server) return callback(); + async.series([ + function disconnectWebsocketStep(callback) { + data.remote + .on('disconnected', callback) + .connect(false); + }, + function stopServerStep(callback) { + if (opts.no_server) return callback(); - data.server.on('stopped', callback).stop(); - } - ], done); + data.server.on('stopped', callback).stop(); + } + ], done); + }; }; var create_accounts = function (remote, src, amount, accounts, callback) { @@ -119,9 +128,9 @@ var credit_limit = function (remote, src, amount, callback) { .submit(); }; -exports.create_accounts = create_accounts; -exports.credit_limit = credit_limit; -exports.build_setup = build_setup; -exports.test_teardown = test_teardown; +exports.create_accounts = create_accounts; +exports.credit_limit = credit_limit; +exports.build_setup = build_setup; +exports.build_teardown = build_teardown; // vim:sw=2:sts=2:ts=8 From 0ac4185ff95f9a211d846ac553a3dcfdd1384008 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 24 Oct 2012 07:26:05 -0700 Subject: [PATCH 31/32] Update to support accepting ledgers acquired during the history fill. --- src/Ledger.cpp | 5 ++++- src/Ledger.h | 2 +- src/LedgerAcquire.cpp | 13 +++++++++++-- src/LedgerAcquire.h | 3 ++- src/LedgerHistory.cpp | 4 ++-- src/LedgerHistory.h | 2 +- src/LedgerMaster.cpp | 4 +++- 7 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 4460e2747..c93b90532 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -337,7 +337,7 @@ uint256 Ledger::getHash() return mHash; } -void Ledger::saveAcceptedLedger() +void Ledger::saveAcceptedLedger(bool fromConsensus) { // can be called in a different thread static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers where LedgerSeq = %d;"); static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;"); @@ -428,6 +428,9 @@ void Ledger::saveAcceptedLedger() mAccountHash.GetHex() % mTransHash.GetHex())); } + if (!fromConsensus) + return; + theApp->getOPs().pubLedger(shared_from_this()); if(theConfig.FULL_HISTORY) diff --git a/src/Ledger.h b/src/Ledger.h index 7c746843a..ca6b9ed2b 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -157,7 +157,7 @@ public: SLE::pointer getAccountRoot(const NewcoinAddress& naAccountID); // database functions - void saveAcceptedLedger(); + void saveAcceptedLedger(bool fromConsensus); static Ledger::pointer loadByIndex(uint32 ledgerIndex); static Ledger::pointer loadByHash(const uint256& ledgerHash); diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 0ebb7c470..9cc09b2ee 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -91,7 +91,7 @@ void PeerSet::TimerEntry(boost::weak_ptr wptr, const boost::system::err } LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT), - mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false) + mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false), mAccept(false) { #ifdef LA_DEBUG cLog(lsTRACE) << "Acquiring ledger " << mHash; @@ -169,7 +169,11 @@ void LedgerAcquire::done() mLock.unlock(); if (mLedger) + { + if (mAccept) + mLedger->setAccepted(); theApp->getMasterLedger().storeLedger(mLedger); + } for (unsigned int i = 0; i < triggers.size(); ++i) triggers[i](shared_from_this()); @@ -619,6 +623,7 @@ void LedgerAcquireSet::updateCurrentLedger(Ledger::pointer currentLedger) { // the next ledger we need is missing or missing nodes LedgerAcquire::pointer nextAcquire = theApp->getMasterLedgerAcquire().findCreate(currentLedger->getParentHash()); + nextAcquire->setAccept(); if (mCurrentLedger) nextAcquire->takePeerSetFrom(*mCurrentLedger); mCurrentLedger = nextAcquire; @@ -639,7 +644,11 @@ void LedgerAcquireSet::onComplete(boost::weak_ptr set, LedgerA return; if (acquired->isComplete()) - lSet->updateCurrentLedger(acquired->getLedger()); + { + Ledger::pointer ledger = acquired->getLedger(); + ledger->setAccepted(); + lSet->updateCurrentLedger(ledger); + } else { cLog(lsWARNING) << "Bailing on LedgerAcquireSet due to failure to acquire a ledger"; diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index a07dbccd8..cbd0459dc 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -68,7 +68,7 @@ public: protected: Ledger::pointer mLedger; - bool mHaveBase, mHaveState, mHaveTransactions, mAborted, mSignaled; + bool mHaveBase, mHaveState, mHaveTransactions, mAborted, mSignaled, mAccept; std::vector< boost::function > mOnComplete; @@ -88,6 +88,7 @@ public: bool isTransComplete() const { return mHaveTransactions; } Ledger::pointer getLedger() { return mLedger; } void abort() { mAborted = true; } + void setAccept() { mAccept = true; } void addOnComplete(boost::function); diff --git a/src/LedgerHistory.cpp b/src/LedgerHistory.cpp index 75519538a..233ab3078 100644 --- a/src/LedgerHistory.cpp +++ b/src/LedgerHistory.cpp @@ -26,7 +26,7 @@ void LedgerHistory::addLedger(Ledger::pointer ledger) mLedgersByHash.canonicalize(ledger->getHash(), ledger, true); } -void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger) +void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger, bool fromConsensus) { assert(ledger && ledger->isAccepted()); uint256 h(ledger->getHash()); @@ -37,7 +37,7 @@ void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger) assert(ledger->isImmutable()); mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger)); - boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, ledger)); + boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, ledger, fromConsensus)); thread.detach(); } diff --git a/src/LedgerHistory.h b/src/LedgerHistory.h index e593c739b..ed58f4fc9 100644 --- a/src/LedgerHistory.h +++ b/src/LedgerHistory.h @@ -13,7 +13,7 @@ public: LedgerHistory(); void addLedger(Ledger::pointer ledger); - void addAcceptedLedger(Ledger::pointer ledger); + void addAcceptedLedger(Ledger::pointer ledger, bool fromConsensus); Ledger::pointer getLedgerBySeq(uint32 index); Ledger::pointer getLedgerByHash(const uint256& hash); diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index 5553c91b5..773e98dbe 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -45,7 +45,7 @@ void LedgerMaster::pushLedger(Ledger::ref newLCL, Ledger::ref newOL) { assert(newLCL->isClosed()); assert(newLCL->isImmutable()); - mLedgerHistory.addAcceptedLedger(newLCL); + mLedgerHistory.addAcceptedLedger(newLCL, false); if (mLastFullLedger && (newLCL->getParentHash() == mLastFullLedger->getHash())) mLastFullLedger = newLCL; Log(lsINFO) << "StashAccepted: " << newLCL->getHash(); @@ -72,6 +72,8 @@ void LedgerMaster::switchLedgers(Ledger::ref lastClosed, Ledger::ref current) void LedgerMaster::storeLedger(Ledger::ref ledger) { mLedgerHistory.addLedger(ledger); + if (ledger->isAccepted()) + mLedgerHistory.addAcceptedLedger(ledger, false); } From d1d231193da3cc86ec6faa6d62f65906b58ebd6f Mon Sep 17 00:00:00 2001 From: Stefan Thomas Date: Wed, 24 Oct 2012 17:08:23 +0200 Subject: [PATCH 32/32] Handle exceptions caused by invalid transactions. --- src/WSDoor.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index da00ea400..f9106112f 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -946,7 +946,18 @@ void WSConnection::doSubmit(Json::Value& jvResult, const Json::Value& jvRequest) sopTrans->setFieldVL(sfSigningPubKey, naAccountPublic.getAccountPublic()); - SerializedTransaction::pointer stpTrans = boost::make_shared(*sopTrans); + SerializedTransaction::pointer stpTrans; + + try + { + stpTrans = boost::make_shared(*sopTrans); + } + catch (std::exception& e) + { + jvResult["error"] = "invalidTransaction"; + jvResult["error_exception"] = e.what(); + return; + } stpTrans->sign(naAccountPrivate);