diff --git a/src/cpp/ripple/Amount.cpp b/src/cpp/ripple/Amount.cpp index 40639d164e..52ff6f8d3c 100644 --- a/src/cpp/ripple/Amount.cpp +++ b/src/cpp/ripple/Amount.cpp @@ -383,7 +383,7 @@ bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurr // Stamps not must have an issuer. if (mIsNative && !mIssuer.isZero()) { - Log(lsINFO) << "Issuer specified for stamps: " << sIssuer; + Log(lsINFO) << "Issuer specified for XRP: " << sIssuer; return false; } diff --git a/src/cpp/ripple/FieldNames.cpp b/src/cpp/ripple/FieldNames.cpp index 2789f33aba..d51adf8ad0 100644 --- a/src/cpp/ripple/FieldNames.cpp +++ b/src/cpp/ripple/FieldNames.cpp @@ -30,27 +30,6 @@ static int initFields() { sfTxnSignature.notSigningField(); sfTxnSignatures.notSigningField(); sfSignature.notSigningField(); - - sfHighQualityIn.setMeta(SFM_CHANGE); sfHighQualityOut.setMeta(SFM_CHANGE); - sfLowQualityIn.setMeta(SFM_CHANGE); sfLowQualityOut.setMeta(SFM_CHANGE); - - sfLowLimit.setMeta(SFM_ALWAYS); sfHighLimit.setMeta(SFM_ALWAYS); - sfTakerPays.setMeta(SFM_ALWAYS); sfTakerGets.setMeta(SFM_ALWAYS); - sfQualityIn.setMeta(SFM_ALWAYS); sfQualityOut.setMeta(SFM_ALWAYS); - - sfBalance.setMeta(SFM_ALWAYS); - - sfPublicKey.setMeta(SFM_CHANGE); sfMessageKey.setMeta(SFM_CHANGE); - sfSigningPubKey.setMeta(SFM_CHANGE); sfAuthorizedKey.setMeta(SFM_CHANGE); - sfSigningAccounts.setMeta(SFM_CHANGE); - - sfWalletLocator.setMeta(SFM_ALWAYS); - sfWalletSize.setMeta(SFM_ALWAYS); - sfNickname.setMeta(SFM_CHANGE); - sfAmount.setMeta(SFM_ALWAYS); - sfDomain.setMeta(SFM_CHANGE); - sfOwner.setMeta(SFM_ALWAYS); - return 0; } static const int f = initFields(); @@ -60,6 +39,7 @@ SField::SField(SerializedTypeID tid, int fv) : fieldCode(FIELD_CODE(tid, fv)), f { // call with the map mutex fieldName = lexical_cast_i(tid) + "/" + lexical_cast_i(fv); codeToField[fieldCode] = this; + assert((fv != 1) || ((tid != STI_ARRAY) && (tid!=STI_OBJECT))); } SField::ref SField::getField(int code) diff --git a/src/cpp/ripple/FieldNames.h b/src/cpp/ripple/FieldNames.h index 3a0ae9a3a1..8b1d5636a5 100644 --- a/src/cpp/ripple/FieldNames.h +++ b/src/cpp/ripple/FieldNames.h @@ -33,14 +33,6 @@ enum SOE_Flags SOE_OPTIONAL = 1, // optional }; -enum SF_Meta -{ - SFM_NEVER = 0, - SFM_CHANGE = 1, - SFM_DELETE = 2, - SFM_ALWAYS = 3 -}; - class SField { public: @@ -59,19 +51,17 @@ public: const SerializedTypeID fieldType; // STI_* const int fieldValue; // Code number for protocol std::string fieldName; - SF_Meta fieldMeta; bool signingField; SField(int fc, SerializedTypeID tid, int fv, const char* fn) : - fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn), fieldMeta(SFM_NEVER), signingField(true) + fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn), signingField(true) { boost::mutex::scoped_lock sl(mapMutex); codeToField[fieldCode] = this; } SField(SerializedTypeID tid, int fv, const char *fn) : - fieldCode(FIELD_CODE(tid, fv)), fieldType(tid), fieldValue(fv), fieldName(fn), - fieldMeta(SFM_NEVER), signingField(true) + fieldCode(FIELD_CODE(tid, fv)), fieldType(tid), fieldValue(fv), fieldName(fn), signingField(true) { boost::mutex::scoped_lock sl(mapMutex); codeToField[fieldCode] = this; @@ -95,10 +85,6 @@ public: bool isBinary() const { return fieldValue < 256; } bool isDiscardable() const { return fieldValue > 256; } - SF_Meta getMeta() const { return fieldMeta; } - bool shouldMetaDel() const { return (fieldMeta == SFM_DELETE) || (fieldMeta == SFM_ALWAYS); } - bool shouldMetaMod() const { return (fieldMeta == SFM_CHANGE) || (fieldMeta == SFM_ALWAYS); } - void setMeta(SF_Meta m) { fieldMeta = m; } bool isSigningField() const { return signingField; } void notSigningField() { signingField = false; } diff --git a/src/cpp/ripple/JobQueue.h b/src/cpp/ripple/JobQueue.h index 26a72dca23..bdd23bc690 100644 --- a/src/cpp/ripple/JobQueue.h +++ b/src/cpp/ripple/JobQueue.h @@ -17,13 +17,15 @@ enum JobType { // must be in priority order, low to high jtINVALID, - jtVALIDATION_ut, - jtTRANSACTION, - jtPROPOSAL_ut, - jtVALIDATION_t, - jtTRANSACTION_l, - jtPROPOSAL_t, - jtADMIN, + jtVALIDATION_ut, // A validation from an untrusted source + jtCLIENTOP_ut, // A client operation from a non-local/untrusted source + jtTRANSACTION, // A transaction received from the network + jtPROPOSAL_ut, // A proposal from an untrusted source + jtCLIENTOP_t, // A client operation from a trusted source + jtVALIDATION_t, // A validation from a trusted source + jtTRANSACTION_l, // A local transaction + jtPROPOSAL_t, // A proposal from a trusted source + jtADMIN, // An administrative operation jtDEATH, // job of death, used internally }; diff --git a/src/cpp/ripple/Ledger.cpp b/src/cpp/ripple/Ledger.cpp index d19cf9e029..03e0a48d1b 100644 --- a/src/cpp/ripple/Ledger.cpp +++ b/src/cpp/ripple/Ledger.cpp @@ -927,11 +927,6 @@ uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uT bool bInNative = uTakerPaysCurrency.isZero(); bool bOutNative = uTakerGetsCurrency.isZero(); - assert(!bInNative || !bOutNative); // Stamps to stamps not allowed. - assert(bInNative == uTakerPaysIssuerID.isZero()); // Make sure issuer is specified as needed. - assert(bOutNative == uTakerGetsIssuerID.isZero()); // Make sure issuer is specified as needed. - assert(uTakerPaysCurrency != uTakerGetsCurrency || uTakerPaysIssuerID != uTakerGetsIssuerID); // Currencies or accounts must differ. - Serializer s(82); s.add16(spaceBookDir); // 2 @@ -942,13 +937,18 @@ uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uT uint256 uBaseIndex = getQualityIndex(s.getSHA512Half()); // Return with quality 0. - Log(lsINFO) << str(boost::format("getBookBase(%s,%s,%s,%s) = %s") + cLog(lsDEBUG) << boost::str(boost::format("getBookBase(%s,%s,%s,%s) = %s") % STAmount::createHumanCurrency(uTakerPaysCurrency) % RippleAddress::createHumanAccountID(uTakerPaysIssuerID) % STAmount::createHumanCurrency(uTakerGetsCurrency) % RippleAddress::createHumanAccountID(uTakerGetsIssuerID) % uBaseIndex.ToString()); + assert(!bInNative || !bOutNative); // XRP to XRP not allowed. + assert(bInNative == uTakerPaysIssuerID.isZero()); // Make sure issuer is specified as needed. + assert(bOutNative == uTakerGetsIssuerID.isZero()); // Make sure issuer is specified as needed. + assert(uTakerPaysCurrency != uTakerGetsCurrency || uTakerPaysIssuerID != uTakerGetsIssuerID); // Currencies or accounts must differ. + return uBaseIndex; } diff --git a/src/cpp/ripple/LedgerConsensus.cpp b/src/cpp/ripple/LedgerConsensus.cpp index e5a877b3bf..8daade3bdf 100644 --- a/src/cpp/ripple/LedgerConsensus.cpp +++ b/src/cpp/ripple/LedgerConsensus.cpp @@ -267,7 +267,7 @@ bool LCTransaction::updateVote(int percentTime, bool proposing) LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previousLedger, uint32 closeTime) : mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger), - mValPublic(theConfig.VALIDATION_PUB), mValPrivate(theConfig.VALIDATION_PRIV), + mValPublic(theConfig.VALIDATION_PUB), mValPrivate(theConfig.VALIDATION_PRIV), mConsensusFail(false), mCurrentMSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false), mConsensusStartTime(boost::posix_time::microsec_clock::universal_time()) { @@ -305,6 +305,36 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previou } } +void LedgerConsensus::checkOurValidation() +{ // This only covers some cases - Fix for the case where we can't ever acquire the consensus ledger + if (!mHaveCorrectLCL || !mValPublic.isValid() || !mValPrivate.isValid()) + return; + + SerializedValidation::pointer lastVal = theApp->getOPs().getLastValidation(); + if (lastVal) + { + if (lastVal->getFieldU32(sfLedgerSequence) == mPreviousLedger->getLedgerSeq()) + return; + if (lastVal->getLedgerHash() == mPrevLedgerHash) + return; + } + + uint256 signingHash; + SerializedValidation::pointer v = boost::make_shared + (mPreviousLedger->getHash(), theApp->getOPs().getValidationTimeNC(), mValPublic, false); + v->setTrusted(); + v->sign(signingHash, mValPrivate); + theApp->isNew(signingHash); + theApp->getValidations().addValidation(v); + std::vector validation = v->getSigned(); + ripple::TMValidation val; + val.set_validation(&validation[0], validation.size()); + theApp->getConnectionPool().relayMessage(NULL, + boost::make_shared(val, ripple::mtVALIDATION)); + theApp->getOPs().setLastValidation(v); + cLog(lsWARNING) << "Sending partial validation"; +} + void LedgerConsensus::checkLCL() { uint256 netLgr = mPrevLedgerHash; @@ -575,12 +605,13 @@ void LedgerConsensus::statePreClose() void LedgerConsensus::closeLedger() { - mState = lcsESTABLISH; - mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); - mCloseTime = theApp->getOPs().getCloseTimeNC(); - theApp->getOPs().setLastCloseTime(mCloseTime); - statusChange(ripple::neCLOSING_LEDGER, *mPreviousLedger); - takeInitialPosition(*theApp->getMasterLedger().closeLedger(true)); + checkOurValidation(); + mState = lcsESTABLISH; + mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); + mCloseTime = theApp->getOPs().getCloseTimeNC(); + theApp->getOPs().setLastCloseTime(mCloseTime); + statusChange(ripple::neCLOSING_LEDGER, *mPreviousLedger); + takeInitialPosition(*theApp->getMasterLedger().closeLedger(true)); } void LedgerConsensus::stateEstablish() @@ -769,7 +800,7 @@ bool LedgerConsensus::haveConsensus(bool forReal) cLog(lsDEBUG) << "Checking for TX consensus: agree=" << agree << ", disagree=" << disagree; return ContinuousLedgerTiming::haveConsensus(mPreviousProposers, agree + disagree, agree, currentValidations, - mPreviousMSeconds, mCurrentMSeconds, forReal); + mPreviousMSeconds, mCurrentMSeconds, forReal, mConsensusFail); } SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool doAcquire) @@ -1193,15 +1224,17 @@ void LedgerConsensus::accept(SHAMap::ref set) } statusChange(ripple::neACCEPTED_LEDGER, *newLCL); - if (mValidating) + if (mValidating && !mConsensusFail) { uint256 signingHash; SerializedValidation::pointer v = boost::make_shared - (newLCLHash, theApp->getOPs().getValidationTimeNC(), mValPublic, mValPrivate, - mProposing, boost::ref(signingHash)); + (newLCLHash, theApp->getOPs().getValidationTimeNC(), mValPublic, mProposing); + v->setFieldU32(sfLedgerSequence, newLCL->getLedgerSeq()); + v->sign(signingHash, mValPrivate); v->setTrusted(); theApp->isNew(signingHash); // suppress it if we receive it theApp->getValidations().addValidation(v); + theApp->getOPs().setLastValidation(v); std::vector validation = v->getSigned(); ripple::TMValidation val; val.set_validation(&validation[0], validation.size()); @@ -1238,7 +1271,7 @@ void LedgerConsensus::accept(SHAMap::ref set) cLog(lsINFO) << "Applying transactions from current ledger"; applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), newOL, newLCL, failedTransactions, true); - theApp->getMasterLedger().pushLedger(newLCL, newOL, true); + theApp->getMasterLedger().pushLedger(newLCL, newOL, !mConsensusFail); mNewLedgerHash = newLCL->getHash(); mState = lcsACCEPTED; sl.unlock(); diff --git a/src/cpp/ripple/LedgerConsensus.h b/src/cpp/ripple/LedgerConsensus.h index 064d5800c9..3b66fa9f42 100644 --- a/src/cpp/ripple/LedgerConsensus.h +++ b/src/cpp/ripple/LedgerConsensus.h @@ -91,7 +91,7 @@ protected: LedgerAcquire::pointer mAcquiringLedger; LedgerProposal::pointer mOurPosition; RippleAddress mValPublic, mValPrivate; - bool mProposing, mValidating, mHaveCorrectLCL; + bool mProposing, mValidating, mHaveCorrectLCL, mConsensusFail; int mCurrentMSeconds, mClosePercent, mCloseResolution; bool mHaveCloseTimeConsensus; @@ -148,6 +148,7 @@ protected: void playbackProposals(); int getThreshold(); void closeLedger(); + void checkOurValidation(); void beginAccept(bool synchronous); void endConsensus(); diff --git a/src/cpp/ripple/LedgerEntrySet.cpp b/src/cpp/ripple/LedgerEntrySet.cpp index e7d361c671..1aeffb14b0 100644 --- a/src/cpp/ripple/LedgerEntrySet.cpp +++ b/src/cpp/ripple/LedgerEntrySet.cpp @@ -394,22 +394,21 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result) continue; SLE::pointer origNode = mLedger->getSLE(it.first); - - if (origNode && (origNode->getType() == ltDIR_NODE)) // No metadata for dir nodes - continue; - SLE::pointer curNode = it.second.mEntry; - mSet.setAffectedNode(it.first, *type); + uint16 nodeType = curNode ? curNode->getFieldU16(sfLedgerEntryType) : origNode->getFieldU16(sfLedgerEntryType); + + mSet.setAffectedNode(it.first, *type, nodeType); if (type == &sfDeletedNode) { assert(origNode); + assert(curNode); threadOwners(origNode, mLedger, newMod); STObject finals(sfFinalFields); BOOST_FOREACH(const SerializedType& obj, *curNode) - { // search the deleted node for values saved on delete - if (obj.getFName().shouldMetaDel() && !obj.isDefault()) + { // save non-default values + if (!obj.isDefault() && (obj.getFName() != sfLedgerEntryType)) finals.addObject(obj); } if (!finals.empty()) @@ -421,7 +420,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result) STObject mods(sfPreviousFields); BOOST_FOREACH(const SerializedType& obj, *origNode) { // search the original node for values saved on modify - if (obj.getFName().shouldMetaMod() && !obj.isDefault() && !curNode->hasMatchingEntry(obj)) + if (!obj.isDefault() && (obj.getFName() != sfLedgerEntryType) && !curNode->hasMatchingEntry(obj)) mods.addObject(obj); } if (!mods.empty()) @@ -432,6 +431,15 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result) { assert(!origNode); threadOwners(curNode, mLedger, newMod); + + STObject news(sfNewFields); + BOOST_FOREACH(const SerializedType& obj, *curNode) + { // save non-default values + if (!obj.isDefault() && (obj.getFName() != sfLedgerEntryType)) + news.addObject(obj); + } + if (!news.empty()) + mSet.getAffectedNode(it.first, *type).addObject(news); } if ((type == &sfCreatedNode) || (type == &sfModifiedNode)) diff --git a/src/cpp/ripple/LedgerTiming.cpp b/src/cpp/ripple/LedgerTiming.cpp index 6119123a4f..dd92c953cf 100644 --- a/src/cpp/ripple/LedgerTiming.cpp +++ b/src/cpp/ripple/LedgerTiming.cpp @@ -63,7 +63,8 @@ bool ContinuousLedgerTiming::haveConsensus( int currentFinished, // proposers who have validated a ledger after this one int previousAgreeTime, // how long it took to agree on the last ledger int currentAgreeTime, // how long we've been trying to agree - bool forReal) // deciding whether to stop consensus process + bool forReal, // deciding whether to stop consensus process + bool& failed) // we can't reach a consensus { cLog(lsTRACE) << boost::str(boost::format("CLC::haveConsensus: prop=%d/%d agree=%d validated=%d time=%d/%d%s") % currentProposers % previousProposers % currentAgree % currentFinished % currentAgreeTime % previousAgreeTime % @@ -85,13 +86,15 @@ bool ContinuousLedgerTiming::haveConsensus( if (((currentAgree * 100 + 100) / (currentProposers + 1)) > 80) { tLog(forReal, lsINFO) << "normal consensus"; + failed = false; return true; } - // If 50% of the nodes on your UNL have moved on, you should declare consensus - if (((currentFinished * 100) / (currentProposers + 1)) > 50) + // If 80% of the nodes on your UNL have moved on, you should declare consensus + if (((currentFinished * 100) / (currentProposers + 1)) > 80) { - tLog(forReal, lsWARNING) << "We see no consensus, but 50% of nodes have moved on"; + tLog(forReal, lsWARNING) << "We see no consensus, but 80% of nodes have moved on"; + failed = true; return true; } diff --git a/src/cpp/ripple/LedgerTiming.h b/src/cpp/ripple/LedgerTiming.h index 6cf535c40c..821eb60730 100644 --- a/src/cpp/ripple/LedgerTiming.h +++ b/src/cpp/ripple/LedgerTiming.h @@ -66,7 +66,7 @@ public: int previousProposers, int currentProposers, int currentAgree, int currentClosed, int previousAgreeTime, int currentAgreeTime, - bool forReal); + bool forReal, bool& failed); static int getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq); }; diff --git a/src/cpp/ripple/NetworkOPs.cpp b/src/cpp/ripple/NetworkOPs.cpp index b3006f7a5c..4cc878beaf 100644 --- a/src/cpp/ripple/NetworkOPs.cpp +++ b/src/cpp/ripple/NetworkOPs.cpp @@ -1168,11 +1168,10 @@ std::map NetworkOPs::getAffectedAccounts(const SerializedTra const STAccount* sa = dynamic_cast(&it); if (sa) { - bool found = false; RippleAddress na = sa->getValueNCA(); accounts[na]=true; }else - { + { if( it.getFName() == sfLimitAmount ) { const STAmount* amount = dynamic_cast(&it); diff --git a/src/cpp/ripple/NetworkOPs.h b/src/cpp/ripple/NetworkOPs.h index 6d06250cf0..778846a227 100644 --- a/src/cpp/ripple/NetworkOPs.h +++ b/src/cpp/ripple/NetworkOPs.h @@ -85,6 +85,8 @@ protected: uint256 mLastCloseHash; uint32 mLastCloseTime; uint32 mLastValidationTime; + SerializedValidation::pointer mLastValidation; + // XXX Split into more locks. boost::interprocess::interprocess_upgradable_mutex mMonitorLock; @@ -131,8 +133,10 @@ public: Ledger::pointer getLedgerByHash(const uint256& hash) { return mLedgerMaster->getLedgerByHash(hash); } Ledger::pointer getLedgerBySeq(const uint32 seq) { return mLedgerMaster->getLedgerBySeq(seq); } - uint256 getClosedLedgerHash() - { return mLedgerMaster->getClosedLedger()->getHash(); } + uint256 getClosedLedgerHash() { return mLedgerMaster->getClosedLedger()->getHash(); } + + SerializedValidation::ref getLastValidation() { return mLastValidation; } + void setLastValidation(SerializedValidation::ref v) { mLastValidation = v; } SLE::pointer getSLE(Ledger::pointer lpLedger, const uint256& uHash) { return lpLedger->getSLE(uHash); } diff --git a/src/cpp/ripple/ProofOfWork.cpp b/src/cpp/ripple/ProofOfWork.cpp index 9ccb29eb25..8d8d50b69b 100644 --- a/src/cpp/ripple/ProofOfWork.cpp +++ b/src/cpp/ripple/ProofOfWork.cpp @@ -2,9 +2,16 @@ #include +#include +#include +#include + #include #include "Serializer.h" +#include "Log.h" + +SETUP_LOG(); const uint256 ProofOfWork::sMinTarget("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); const int ProofOfWork::sMaxIterations(1 << 23); @@ -16,26 +23,35 @@ bool ProofOfWork::isValid() const uint64 ProofOfWork::getDifficulty(const uint256& target, int iterations) { // calculate the approximate number of hashes required to solve this proof of work - if ((iterations > sMaxIterations) || (target < sMinTarget)); + if ((iterations > sMaxIterations) || (target < sMinTarget)) + { + cLog(lsINFO) << "Iterations:" << iterations; + cLog(lsINFO) << "MaxIterat: " << sMaxIterations; + cLog(lsINFO) << "Target: " << target; + cLog(lsINFO) << "MinTarget: " << sMinTarget; throw std::runtime_error("invalid proof of work target/iteration"); + } // more iterations means more hashes per iteration but also a larger final hash - uint64 difficulty = iterations * (iterations / 4 + 1); + uint64 difficulty = iterations + (iterations / 4); - // Multiply the number of hashes needed by 16 for each leading zero in the hex difficulty + // Multiply the number of hashes needed by 256 for each leading zero byte in the difficulty const unsigned char *ptr = target.begin(); while (*ptr == 0) { - difficulty *= 16; - ptr++; + difficulty *= 256; + ++ptr; } - - // If the first digit after a zero isn't an F, multiply - difficulty *= (16 - *ptr); + difficulty = (difficulty * 256) / (*ptr + 1); return difficulty; } +static uint256 getSHA512Half(const std::vector& vec) +{ + return Serializer::getSHA512Half(vec.front().begin(), vec.size() * (256 / 8)); +} + uint256 ProofOfWork::solve(int maxIterations) const { if (!isValid()) @@ -44,23 +60,157 @@ uint256 ProofOfWork::solve(int maxIterations) const uint256 nonce; RAND_bytes(nonce.begin(), nonce.size()); - Serializer s1, s2; - std::vector buf; - buf.reserve((256 / 8) * mIterations); + std::vector buf2; + buf2.resize(mIterations); - while (maxIterations > 8) + std::vector buf1; + buf1.resize(3); + buf1[0] = mChallenge; + + while (maxIterations > 0) { - s1.add256(mChallenge); - s1.add256(nonce); -// uint256 base = s1.getSHA512Half(); - - for (int i = 0; i < mIterations; ++i) + buf1[1] = nonce; + buf1[2] = uint256(); + for (int i = (mIterations - 1); i >= 0; --i) { - // WRITEME + buf1[2] = getSHA512Half(buf1); + buf2[i] = buf1[2]; } - s1.erase(); - nonce++; + if (getSHA512Half(buf2) <= mTarget) + return nonce; + + ++nonce; + --maxIterations; } return uint256(); } + +bool ProofOfWork::checkSolution(const uint256& solution) const +{ + if (mIterations > sMaxIterations) + return false; + + std::vector buf1; + buf1.push_back(mChallenge); + buf1.push_back(solution); + buf1.push_back(uint256()); + + std::vector buf2; + buf2.resize(mIterations); + for (int i = (mIterations - 1); i >= 0; --i) + { + buf1[2] = getSHA512Half(buf1); + buf2[i] = buf1[2]; + } + return getSHA512Half(buf2) <= mTarget; +} + +ProofOfWorkGenerator::ProofOfWorkGenerator() : + mIterations(128), + mTarget("0003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + mLastDifficultyChange(time(NULL)), + mValidTime(180) +{ + RAND_bytes(mSecret.begin(), mSecret.size()); +} + +ProofOfWork ProofOfWorkGenerator::getProof() +{ + // challenge - target - iterations - time - validator + static boost::format f("%s-%s-%d-%d"); + + int now = static_cast(time(NULL) / 4); + + uint256 challenge; + RAND_bytes(challenge.begin(), challenge.size()); + + boost::mutex::scoped_lock sl(mLock); + + std::string s = boost::str(f % challenge.GetHex() % mTarget.GetHex() % mIterations % now); + std::string c = mSecret.GetHex() + s; + s += "-" + Serializer::getSHA512Half(c).GetHex(); + + return ProofOfWork(s, mIterations, challenge, mTarget); +} + +POWResult ProofOfWorkGenerator::checkProof(const std::string& token, const uint256& solution) +{ // challenge - target - iterations - time - validator + + std::vector fields; + boost::split(fields, token, boost::algorithm::is_any_of("-")); + if (fields.size() != 5) + { + cLog(lsDEBUG) << "PoW " << token << " is corrupt"; + return powCORRUPT; + } + + std::string v = mSecret.GetHex() + fields[0] + "-" + fields[1] + "-" + fields[2] + "-" + fields[3]; + if (fields[4] != Serializer::getSHA512Half(v).GetHex()) + { + cLog(lsDEBUG) << "PoW " << token << " has a bad token"; + return powBADTOKEN; + } + + uint256 challenge, target; + challenge.SetHex(fields[0]); + target.SetHex(fields[1]); + + time_t t = lexical_cast_s(fields[3]); + time_t now = time(NULL); + + { + boost::mutex::scoped_lock sl(mLock); + if ((t * 4) > (now + mValidTime)) + { + cLog(lsDEBUG) << "PoW " << token << " has expired"; + return powEXPIRED; + } + } + + + ProofOfWork pow(token, lexical_cast_s(fields[2]), challenge, target); + if (!pow.checkSolution(solution)) + { + cLog(lsDEBUG) << "PoW " << token << " has a bad nonce"; + return powBADNONCE; + } + + { + boost::mutex::scoped_lock sl(mLock); + if (!mSolvedChallenges.insert(powMap_vt(now, challenge)).second) + { + cLog(lsDEBUG) << "PoW " << token << " has been reused"; + return powREUSED; + } + } + + return powOK; +} + +BOOST_AUTO_TEST_SUITE(ProofOfWork_suite) + +BOOST_AUTO_TEST_CASE( ProofOfWork_test ) +{ + ProofOfWorkGenerator gen; + ProofOfWork pow = gen.getProof(); + cLog(lsINFO) << "Estimated difficulty: " << pow.getDifficulty(); + uint256 solution = pow.solve(16777216); + if (solution.isZero()) + BOOST_FAIL("Unable to solve proof of work"); + if (!pow.checkSolution(solution)) + BOOST_FAIL("Solution did not check"); + + cLog(lsDEBUG) << "A bad nonce error is expected"; + if (gen.checkProof(pow.getToken(), uint256()) != powBADNONCE) + BOOST_FAIL("Empty solution didn't show bad nonce"); + if (gen.checkProof(pow.getToken(), solution) != powOK) + BOOST_FAIL("Solution did not check with issuer"); + cLog(lsDEBUG) << "A reused nonce error is expected"; + if (gen.checkProof(pow.getToken(), solution) != powREUSED) + BOOST_FAIL("Reuse solution not detected"); +} + +BOOST_AUTO_TEST_SUITE_END() + +// vim:ts=4 diff --git a/src/cpp/ripple/ProofOfWork.h b/src/cpp/ripple/ProofOfWork.h index 1391be91c3..a09eec7377 100644 --- a/src/cpp/ripple/ProofOfWork.h +++ b/src/cpp/ripple/ProofOfWork.h @@ -5,11 +5,21 @@ #include #include -#include +#include #include #include "uint256.h" +enum POWResult +{ + powOK = 0, + powREUSED = 1, + powBADNONCE = 2, + powBADTOKEN = 3, + powEXPIRED = 4, + powCORRUPT = 5, +}; + class ProofOfWork { protected: @@ -32,6 +42,9 @@ public: uint256 solve(int maxIterations) const; bool checkSolution(const uint256& solution) const; + const std::string& getToken() const { return mToken; } + const uint256& getChallenge() const { return mChallenge; } + // approximate number of hashes needed to solve static uint64 getDifficulty(const uint256& target, int iterations); uint64 getDifficulty() const { return getDifficulty(mTarget, mIterations); } @@ -40,7 +53,7 @@ public: class ProofOfWorkGenerator { public: - typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::set_of > powMap_t; + typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::unordered_set_of > powMap_t; typedef powMap_t::value_type powMap_vt; protected: @@ -48,19 +61,23 @@ protected: int mIterations; uint256 mTarget; time_t mLastDifficultyChange; + int mValidTime; powMap_t mSolvedChallenges; boost::mutex mLock; public: - ProofOfWorkGenerator(const uint256& secret); + ProofOfWorkGenerator(); ProofOfWork getProof(); - bool checkProof(const std::string& token, const uint256& solution); + POWResult checkProof(const std::string& token, const uint256& solution); + uint64 getDifficulty() { return ProofOfWork::getDifficulty(mTarget, mIterations); } void loadHigh(); void loadLow(); - uint64 getDifficulty() { return ProofOfWork::getDifficulty(mTarget, mIterations); } + void sweep(void); }; #endif + +// vim:ts=4 diff --git a/src/cpp/ripple/RPCCommands.cpp b/src/cpp/ripple/RPCCommands.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/cpp/ripple/RPCCommands.h b/src/cpp/ripple/RPCCommands.h deleted file mode 100644 index 5417497ebd..0000000000 --- a/src/cpp/ripple/RPCCommands.h +++ /dev/null @@ -1,6 +0,0 @@ - -class RPCCommands -{ -public: - HttpReply& handleCommand(); -}; \ No newline at end of file diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index d46da78ccc..6579bb9033 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -1312,13 +1312,15 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param cLog(lsTRACE) << "RPC:" << command; cLog(lsTRACE) << "RPC params:" << params; + mRole = role; + static struct { const char* pCommand; doFuncPtr dfpFunc; int iMinParams; int iMaxParams; - bool mAdminRequired; - bool mEvented; + bool bAdminRequired; + bool bEvented; unsigned int iOptions; } commandsA[] = { // Request-response methods @@ -1335,6 +1337,7 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param { "ledger_closed", &RPCHandler::doLedgerClosed, 0, 0, false, false, optClosed }, { "ledger_current", &RPCHandler::doLedgerCurrent, 0, 0, false, false, optCurrent }, { "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, false, optCurrent }, + { "ledger_header", &RPCHandler::doLedgerHeader, -1, -1, false, false, optCurrent }, { "log_level", &RPCHandler::doLogLevel, 0, 2, true }, { "logrotate", &RPCHandler::doLogRotate, 0, 0, true }, { "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, false, optCurrent }, @@ -1380,11 +1383,11 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param { return rpcError(rpcUNKNOWN_COMMAND); } - else if (commandsA[i].mAdminRequired && role != ADMIN) + else if (commandsA[i].bAdminRequired && mRole != ADMIN) { return rpcError(rpcNO_PERMISSION); } - else if (commandsA[i].mEvented && mInfoSub == NULL) + else if (commandsA[i].bEvented && mInfoSub == NULL) { return rpcError(rpcNO_EVENTS); } @@ -1705,15 +1708,13 @@ Json::Value RPCHandler::doTransactionEntry(const Json::Value& jvRequest) return jvResult; } -Json::Value RPCHandler::doLedgerEntry(const Json::Value& jvRequest) +Json::Value RPCHandler::lookupLedger(const Json::Value& jvRequest, Ledger::pointer& lpLedger) { Json::Value jvResult; uint256 uLedger = jvRequest.isMember("ledger_hash") ? uint256(jvRequest["ledger_hash"].asString()) : 0; uint32 uLedgerIndex = jvRequest.isMember("ledger_index") && jvRequest["ledger_index"].isNumeric() ? jvRequest["ledger_index"].asUInt() : 0; - Ledger::pointer lpLedger; - if (!!uLedger) { // Ledger directly specified. @@ -1756,6 +1757,17 @@ Json::Value RPCHandler::doLedgerEntry(const Json::Value& jvRequest) jvResult["ledger_current_index"] = uLedgerIndex; } + return jvResult; +} + +Json::Value RPCHandler::doLedgerEntry(const Json::Value& jvRequest) +{ + Ledger::pointer lpLedger; + Json::Value jvResult = lookupLedger(jvRequest, lpLedger); + + if (!lpLedger) + return jvResult; + uint256 uNodeIndex; bool bNodeBinary = false; @@ -1951,6 +1963,25 @@ Json::Value RPCHandler::doLedgerEntry(const Json::Value& jvRequest) return jvResult; } +Json::Value RPCHandler::doLedgerHeader(const Json::Value& jvRequest) +{ + Ledger::pointer lpLedger; + Json::Value jvResult = lookupLedger(jvRequest, lpLedger); + + if (!lpLedger) + return jvResult; + + Serializer s; + + lpLedger->addRaw(s); + + jvResult["ledger_data"] = strHex(s.peekData()); + + if (mRole == ADMIN) + lpLedger->addJson(jvResult, 0); + + return jvRequest; +} boost::unordered_set RPCHandler::parseAccountIds(const Json::Value& jvArray) { diff --git a/src/cpp/ripple/RPCHandler.h b/src/cpp/ripple/RPCHandler.h index 7be97a6d5a..0b742c8dde 100644 --- a/src/cpp/ripple/RPCHandler.h +++ b/src/cpp/ripple/RPCHandler.h @@ -8,6 +8,7 @@ class RPCHandler { NetworkOPs* mNetOps; InfoSub* mInfoSub; + int mRole; typedef Json::Value (RPCHandler::*doFuncPtr)(const Json::Value ¶ms); enum { @@ -22,6 +23,8 @@ class RPCHandler int getParamCount(const Json::Value& params); bool extractString(std::string& param, const Json::Value& params, int index); + Json::Value lookupLedger(const Json::Value& jvRequest, Ledger::pointer& lpLedger); + Json::Value getMasterGenerator(const uint256& uLedger, const RippleAddress& naRegularSeed, RippleAddress& naMasterGenerator); Json::Value authorize(const uint256& uLedger, const RippleAddress& naRegularSeed, const RippleAddress& naSrcAccountID, RippleAddress& naAccountPublic, RippleAddress& naAccountPrivate, @@ -86,6 +89,7 @@ class RPCHandler Json::Value doLedgerClosed(const Json::Value& params); Json::Value doLedgerCurrent(const Json::Value& params); Json::Value doLedgerEntry(const Json::Value& params); + Json::Value doLedgerHeader(const Json::Value& params); Json::Value doTransactionEntry(const Json::Value& params); Json::Value doSubscribe(const Json::Value& params); diff --git a/src/cpp/ripple/RippleAddress.cpp b/src/cpp/ripple/RippleAddress.cpp index 46d769d302..ecb152857e 100644 --- a/src/cpp/ripple/RippleAddress.cpp +++ b/src/cpp/ripple/RippleAddress.cpp @@ -115,7 +115,7 @@ uint160 RippleAddress::getNodeID() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - getNodeID"); case VER_NODE_PUBLIC: // Note, we are encoding the left. @@ -129,7 +129,7 @@ const std::vector& RippleAddress::getNodePublic() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - getNodePublic"); case VER_NODE_PUBLIC: return vchData; @@ -143,7 +143,7 @@ std::string RippleAddress::humanNodePublic() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - humanNodePublic"); case VER_NODE_PUBLIC: return ToString(); @@ -209,7 +209,7 @@ const std::vector& RippleAddress::getNodePrivateData() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - getNodePrivateData"); case VER_NODE_PRIVATE: return vchData; @@ -223,7 +223,7 @@ uint256 RippleAddress::getNodePrivate() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source = getNodePrivate"); case VER_NODE_PRIVATE: return uint256(vchData); @@ -237,7 +237,7 @@ std::string RippleAddress::humanNodePrivate() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - humanNodePrivate"); case VER_NODE_PRIVATE: return ToString(); @@ -279,7 +279,7 @@ uint160 RippleAddress::getAccountID() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - getAccountID"); case VER_ACCOUNT_ID: return uint160(vchData); @@ -297,7 +297,7 @@ std::string RippleAddress::humanAccountID() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - humanAccountID"); case VER_ACCOUNT_ID: return ToString(); @@ -353,7 +353,7 @@ const std::vector& RippleAddress::getAccountPublic() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - getAccountPublic"); case VER_ACCOUNT_ID: throw std::runtime_error("public not available from account id"); @@ -371,7 +371,7 @@ std::string RippleAddress::humanAccountPublic() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - humanAccountPublic"); case VER_ACCOUNT_ID: throw std::runtime_error("public not available from account id"); @@ -446,7 +446,7 @@ uint256 RippleAddress::getAccountPrivate() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - getAccountPrivate"); case VER_ACCOUNT_PRIVATE: return uint256(vchData); @@ -460,7 +460,7 @@ std::string RippleAddress::humanAccountPrivate() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - humanAccountPrivate"); case VER_ACCOUNT_PRIVATE: return ToString(); @@ -606,7 +606,7 @@ BIGNUM* RippleAddress::getGeneratorBN() const { // returns the public generator switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - getGeneratorBN"); case VER_FAMILY_GENERATOR: // Do nothing. @@ -625,7 +625,7 @@ const std::vector& RippleAddress::getGenerator() const { // returns the public generator switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - getGenerator"); case VER_FAMILY_GENERATOR: // Do nothing. @@ -640,7 +640,7 @@ std::string RippleAddress::humanGenerator() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - humanGenerator"); case VER_FAMILY_GENERATOR: return ToString(); @@ -678,7 +678,7 @@ uint128 RippleAddress::getSeed() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - getSeed"); case VER_FAMILY_SEED: return uint128(vchData); @@ -692,7 +692,7 @@ std::string RippleAddress::humanSeed1751() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - humanSeed1751"); case VER_FAMILY_SEED: { @@ -719,7 +719,7 @@ std::string RippleAddress::humanSeed() const { switch (nVersion) { case VER_NONE: - throw std::runtime_error("unset source"); + throw std::runtime_error("unset source - humanSeed"); case VER_FAMILY_SEED: return ToString(); @@ -792,7 +792,7 @@ void RippleAddress::setSeedRandom() // XXX Maybe we should call MakeNewKey uint128 key; - RAND_bytes((unsigned char *) &key, sizeof(key)); + RAND_bytes(key.begin(), key.size()); RippleAddress::setSeed(key); } diff --git a/src/cpp/ripple/RippleCalc.cpp b/src/cpp/ripple/RippleCalc.cpp index 2b4a3ed1a9..568449eb0e 100644 --- a/src/cpp/ripple/RippleCalc.cpp +++ b/src/cpp/ripple/RippleCalc.cpp @@ -28,13 +28,13 @@ std::size_t hash_value(const aciSource& asValue) // - Set bEntryAdvance to advance to next entry. // <-- uOfferIndex : 0=end of list. TER RippleCalc::calcNodeAdvance( - const unsigned int uIndex, // 0 < uIndex < uLast + const unsigned int uNode, // 0 < uNode < uLast PathState::ref pspCur, const bool bMultiQuality, const bool bReverse) { - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnPrv = pspCur->vpnNodes[uNode-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uNode]; const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; const uint160& uPrvIssuerID = pnPrv.uIssuerID; @@ -181,7 +181,7 @@ TER RippleCalc::calcNodeAdvance( curIssuerNodeConstIterator itForward = pspCur->umForward.find(asLine); const bool bFoundForward = itForward != pspCur->umForward.end(); - if (bFoundForward && itForward->second != uIndex) + if (bFoundForward && itForward->second != uNode) { // Temporarily unfunded. Another node uses this source, ignore in this offer. cLog(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (forward)"; @@ -193,7 +193,7 @@ TER RippleCalc::calcNodeAdvance( curIssuerNodeConstIterator itPast = mumSource.find(asLine); bool bFoundPast = itPast != mumSource.end(); - if (bFoundPast && itPast->second != uIndex) + if (bFoundPast && itPast->second != uNode) { // Temporarily unfunded. Another node uses this source, ignore in this offer. cLog(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (past)"; @@ -205,7 +205,7 @@ TER RippleCalc::calcNodeAdvance( curIssuerNodeConstIterator itReverse = pspCur->umReverse.find(asLine); bool bFoundReverse = itReverse != pspCur->umReverse.end(); - if (bFoundReverse && itReverse->second != uIndex) + if (bFoundReverse && itReverse->second != uNode) { // Temporarily unfunded. Another node uses this source, ignore in this offer. cLog(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (reverse)"; @@ -245,7 +245,7 @@ TER RippleCalc::calcNodeAdvance( % STAmount::createHumanCurrency(uCurCurrencyID) % RippleAddress::createHumanAccountID(uCurIssuerID)); - pspCur->umReverse.insert(std::make_pair(asLine, uIndex)); + pspCur->umReverse.insert(std::make_pair(asLine, uNode)); } bFundsDirty = false; @@ -270,7 +270,7 @@ TER RippleCalc::calcNodeAdvance( // requirements to the previous node. The previous node adjusts the amount output and the amount spent on fees. 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 unsigned int uNode, // 0 < uNode < uLast PathState::ref pspCur, const bool bMultiQuality, const uint160& uOutAccountID, // --> Output owner's account. @@ -279,8 +279,8 @@ TER RippleCalc::calcNodeDeliverRev( { TER terResult = tesSUCCESS; - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnPrv = pspCur->vpnNodes[uNode-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uNode]; const uint160& uCurIssuerID = pnCur.uIssuerID; const uint160& uPrvAccountID = pnPrv.uAccountID; @@ -308,7 +308,7 @@ TER RippleCalc::calcNodeDeliverRev( STAmount& saTakerGets = pnCur.saTakerGets; STAmount& saRateMax = pnCur.saRateMax; - terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality, true); // If needed, advance to next funded offer. + terResult = calcNodeAdvance(uNode, pspCur, bMultiQuality, true); // If needed, advance to next funded offer. if (tesSUCCESS != terResult || !uOfferIndex) { @@ -413,7 +413,7 @@ TER RippleCalc::calcNodeDeliverRev( // Chain and compute the previous offer now. terResult = calcNodeDeliverRev( - uIndex-1, + uNode-1, pspCur, bMultiQuality, uOfrOwnerID, @@ -474,7 +474,7 @@ TER RippleCalc::calcNodeDeliverRev( // Deliver maximum amount of funds from previous node. // Goal: Make progress consuming the offer. TER RippleCalc::calcNodeDeliverFwd( - const unsigned int uIndex, // 0 < uIndex < uLast + const unsigned int uNode, // 0 < uNode < uLast PathState::ref pspCur, const bool bMultiQuality, const uint160& uInAccountID, // --> Input owner's account. @@ -485,9 +485,9 @@ TER RippleCalc::calcNodeDeliverFwd( { TER terResult = tesSUCCESS; - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; + PaymentNode& pnPrv = pspCur->vpnNodes[uNode-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uNode]; + PaymentNode& pnNxt = pspCur->vpnNodes[uNode+1]; const uint160& uNxtAccountID = pnNxt.uAccountID; const uint160& uCurIssuerID = pnCur.uIssuerID; @@ -507,7 +507,7 @@ TER RippleCalc::calcNodeDeliverFwd( && saInAct != saInReq // Did not deliver limit. && saInAct + saInFees != saInFunds) // Did not deliver all funds. { - terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality, false); // If needed, advance to next funded offer. + terResult = calcNodeAdvance(uNode, pspCur, bMultiQuality, false); // If needed, advance to next funded offer. if (tesSUCCESS == terResult) { @@ -570,7 +570,7 @@ TER RippleCalc::calcNodeDeliverFwd( STAmount saOutPassFees; terResult = RippleCalc::calcNodeDeliverFwd( - uIndex+1, + uNode+1, pspCur, bMultiQuality, uOfrOwnerID, @@ -628,14 +628,14 @@ 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 unsigned int uNode, // 0 < uNode < uLast PathState::ref pspCur, const bool bMultiQuality) { TER terResult; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; + PaymentNode& pnCur = pspCur->vpnNodes[uNode]; + PaymentNode& pnNxt = pspCur->vpnNodes[uNode+1]; if (!!pnNxt.uAccountID) { @@ -643,7 +643,7 @@ TER RippleCalc::calcNodeOfferRev( STAmount saDeliverAct; terResult = calcNodeDeliverRev( - uIndex, + uNode, pspCur, bMultiQuality, @@ -668,13 +668,13 @@ TER RippleCalc::calcNodeOfferRev( // - Payout to issuer or limbo. // - Deliver is set without transfer fees. TER RippleCalc::calcNodeOfferFwd( - const unsigned int uIndex, // 0 < uIndex < uLast + const unsigned int uNode, // 0 < uNode < uLast PathState::ref pspCur, const bool bMultiQuality ) { TER terResult; - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + PaymentNode& pnPrv = pspCur->vpnNodes[uNode-1]; if (!!pnPrv.uAccountID) { @@ -683,7 +683,7 @@ TER RippleCalc::calcNodeOfferFwd( STAmount saInFees; terResult = calcNodeDeliverFwd( - uIndex, + uNode, pspCur, bMultiQuality, pnPrv.uAccountID, @@ -822,20 +822,20 @@ void RippleCalc::calcNodeRipple( // Issues are limited based on credit limits and amount owed. // No account balance adjustments as we don't know how much is going to actually be pushed through yet. // <-- tesSUCCESS or tepPATH_DRY -TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality) +TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality) { TER terResult = tesSUCCESS; const unsigned int uLast = pspCur->vpnNodes.size() - 1; uint64 uRateMax = 0; - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + PaymentNode& pnPrv = pspCur->vpnNodes[uNode ? uNode-1 : 0]; + PaymentNode& pnCur = pspCur->vpnNodes[uNode]; + PaymentNode& pnNxt = pspCur->vpnNodes[uNode == uLast ? uLast : uNode+1]; // Current is allowed to redeem to next. - const bool bPrvAccount = !uIndex || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); - const bool bNxtAccount = uIndex == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount); + const bool bPrvAccount = !uNode || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); + const bool bNxtAccount = uNode == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount); const uint160& uCurAccountID = pnCur.uAccountID; const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; @@ -843,24 +843,24 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp const uint160& uCurrencyID = pnCur.uCurrencyID; - const uint32 uQualityIn = uIndex ? lesActive.rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; - const uint32 uQualityOut = uIndex != uLast ? lesActive.rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; + const uint32 uQualityIn = uNode ? lesActive.rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; + const uint32 uQualityOut = uNode != uLast ? lesActive.rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // For bPrvAccount - const STAmount saPrvOwed = bPrvAccount && uIndex // Previous account is owed. + const STAmount saPrvOwed = bPrvAccount && uNode // Previous account is owed. ? lesActive.rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); - const STAmount saPrvLimit = bPrvAccount && uIndex // Previous account may owe. + const STAmount saPrvLimit = bPrvAccount && uNode // Previous account may owe. ? lesActive.rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); - const STAmount saNxtOwed = bNxtAccount && uIndex != uLast // Next account is owed. + const STAmount saNxtOwed = bNxtAccount && uNode != uLast // Next account is owed. ? lesActive.rippleOwed(uCurAccountID, uNxtAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); - cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") - % uIndex + cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uNode=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") + % uNode % uLast % RippleAddress::createHumanAccountID(uPrvAccountID) % RippleAddress::createHumanAccountID(uCurAccountID) @@ -910,13 +910,13 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp if (bPrvAccount && bNxtAccount) { - if (!uIndex) + if (!uNode) { // ^ --> ACCOUNT --> account|offer // Nothing to do, there is no previous to adjust. nothing(); } - else if (uIndex == uLast) + else if (uNode == uLast) { // account --> ACCOUNT --> $ // Overall deliverable. @@ -1081,7 +1081,7 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp { saPrvDeliverAct.zero(saCurRedeemReq); - if (uIndex == uLast) + if (uNode == uLast) { // offer --> ACCOUNT --> $ const STAmount& saCurWantedReq = bPrvAccount @@ -1166,7 +1166,7 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp // - Current node: specify what to push through to next. // - Output to next node is computed as input minus quality or transfer fee. TER RippleCalc::calcNodeAccountFwd( - const unsigned int uIndex, // 0 <= uIndex <= uLast + const unsigned int uNode, // 0 <= uNode <= uLast PathState::ref pspCur, const bool bMultiQuality) { @@ -1175,9 +1175,9 @@ TER RippleCalc::calcNodeAccountFwd( uint64 uRateMax = 0; - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + PaymentNode& pnPrv = pspCur->vpnNodes[uNode ? uNode-1 : 0]; + PaymentNode& pnCur = pspCur->vpnNodes[uNode]; + PaymentNode& pnNxt = pspCur->vpnNodes[uNode == uLast ? uLast : uNode+1]; const bool bPrvAccount = isSetBit(pnPrv.uFlags, STPathElement::typeAccount); const bool bNxtAccount = isSetBit(pnNxt.uFlags, STPathElement::typeAccount); @@ -1188,8 +1188,8 @@ TER RippleCalc::calcNodeAccountFwd( const uint160& uCurrencyID = pnCur.uCurrencyID; - uint32 uQualityIn = uIndex ? lesActive.rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; - uint32 uQualityOut = uIndex == uLast ? lesActive.rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; + uint32 uQualityIn = uNode ? lesActive.rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; + uint32 uQualityOut = uNode == uLast ? lesActive.rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // When looking backward (prv) for req we care about what we just calculated: use fwd // When looking forward (cur) for req we care about what was desired: use rev @@ -1216,8 +1216,8 @@ TER RippleCalc::calcNodeAccountFwd( const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount& saCurDeliverAct = pnCur.saFwdDeliver; - cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s") - % uIndex + cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uNode=%d/%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s") + % uNode % uLast % saPrvRedeemReq.getFullText() % saPrvIssueReq.getFullText() @@ -1232,7 +1232,7 @@ TER RippleCalc::calcNodeAccountFwd( { // Next is an account, must be rippling. - if (!uIndex) + if (!uNode) { // ^ --> ACCOUNT --> account @@ -1274,7 +1274,7 @@ TER RippleCalc::calcNodeAccountFwd( % saCurIssueAct.getFullText() % saCurSendMaxPass.getFullText()); } - else if (uIndex == uLast) + else if (uNode == uLast) { // account --> ACCOUNT --> $ cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> $ : uPrvAccountID=%s uCurAccountID=%s saPrvRedeemReq=%s saPrvIssueReq=%s") @@ -1371,7 +1371,7 @@ TER RippleCalc::calcNodeAccountFwd( } else if (!bPrvAccount && bNxtAccount) { - if (uIndex == uLast) + if (uNode == uLast) { // offer --> ACCOUNT --> $ cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $ : %s") % saPrvDeliverReq.getFullText()); @@ -1472,26 +1472,27 @@ TER PathState::pushImply( { // Currency is different, need to convert via an offer. - terResult = pushNode( - STPathElement::typeCurrency // Offer. - | STPathElement::typeIssuer, - ACCOUNT_ONE, // Placeholder for offers. + terResult = pushNode( // Offer. + !!uCurrencyID + ? STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeCurrency, + ACCOUNT_XRP, // Placeholder for offers. uCurrencyID, // The offer's output is what is now wanted. uIssuerID); } const PaymentNode& pnBck = vpnNodes.back(); - // For ripple, non-stamps, ensure the issuer is on at least one side of the transaction. + // For ripple, non-XRP, ensure the issuer is on at least one side of the transaction. if (tesSUCCESS == terResult - && !!uCurrencyID // Not stamps. + && !!uCurrencyID // Not XRP. && (pnBck.uAccountID != uIssuerID // Previous is not issuing own IOUs. && uAccountID != uIssuerID)) // Current is not receiving own IOUs. { // Need to ripple through uIssuerID's account. terResult = pushNode( - STPathElement::typeAccount, + STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer, uIssuerID, // Intermediate account is the needed issuer. uCurrencyID, uIssuerID); @@ -1511,10 +1512,6 @@ TER PathState::pushNode( const uint160& uCurrencyID, const uint160& uIssuerID) { - cLog(lsINFO) << "pushNode> " - << RippleAddress::createHumanAccountID(uAccountID) - << " " << STAmount::createHumanCurrency(uCurrencyID) - << "/" << RippleAddress::createHumanAccountID(uIssuerID); PaymentNode pnCur; const bool bFirst = vpnNodes.empty(); const PaymentNode& pnPrv = bFirst ? PaymentNode() : vpnNodes.back(); @@ -1527,11 +1524,30 @@ TER PathState::pushNode( const bool bIssuer = isSetBit(iType, STPathElement::typeIssuer); TER terResult = tesSUCCESS; + cLog(lsDEBUG) << "pushNode> " + << iType + << ": " << (bAccount ? RippleAddress::createHumanAccountID(uAccountID) : "-") + << " " << (bCurrency ? STAmount::createHumanCurrency(uCurrencyID) : "-") + << "/" << (bIssuer ? RippleAddress::createHumanAccountID(uIssuerID) : "-"); + pnCur.uFlags = iType; + pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; if (iType & ~STPathElement::typeValidBits) { - cLog(lsINFO) << "pushNode: bad bits."; + cLog(lsDEBUG) << "pushNode: bad bits."; + + terResult = temBAD_PATH; + } + else if (bIssuer && !pnCur.uCurrencyID) + { + cLog(lsDEBUG) << "pushNode: issuer specified for XRP."; + + terResult = temBAD_PATH; + } + else if (bIssuer && !uIssuerID) + { + cLog(lsDEBUG) << "pushNode: specified bad issuer."; terResult = temBAD_PATH; } @@ -1540,8 +1556,11 @@ TER PathState::pushNode( // Account link pnCur.uAccountID = uAccountID; - pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; - pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; + pnCur.uIssuerID = bIssuer + ? uIssuerID + : !!pnCur.uCurrencyID + ? uAccountID + : ACCOUNT_XRP; pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID); pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID); @@ -1551,6 +1570,12 @@ TER PathState::pushNode( nothing(); } + else if (!uAccountID) + { + cLog(lsDEBUG) << "pushNode: specified bad account."; + + terResult = temBAD_PATH; + } else { // Add required intermediate nodes to deliver to current account. @@ -1612,19 +1637,28 @@ TER PathState::pushNode( { // Offer link // Offers bridge a change in currency & issuer or just a change in issuer. - pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; - pnCur.uIssuerID = bIssuer ? uIssuerID : pnCur.uAccountID; + pnCur.uIssuerID = bIssuer + ? uIssuerID + : !!pnCur.uCurrencyID + ? !!pnPrv.uIssuerID + ? pnPrv.uIssuerID // Default to previous issuer + : pnPrv.uAccountID // Or previous account if no previous issuer. + : ACCOUNT_XRP; pnCur.saRateMax = saZero; - if (!!pnPrv.uAccountID) + if (!!pnCur.uCurrencyID != !!pnCur.uIssuerID) + { + cLog(lsDEBUG) << "pushNode: currency is inconsistent with issuer."; + + terResult = temBAD_PATH; + } + else if (!!pnPrv.uAccountID) { // Previous is an account. // Insert intermediary issuer account if needed. terResult = pushImply( - !!pnPrv.uCurrencyID - ? ACCOUNT_ONE // Rippling, but offer's don't have an account. - : ACCOUNT_XRP, + ACCOUNT_XRP, // Rippling, but offer's don't have an account. pnPrv.uCurrencyID, pnPrv.uIssuerID); } @@ -1655,30 +1689,37 @@ PathState::PathState( saInReq(saSendMax), saOutReq(saSend) { - const uint160 uInCurrencyID = saSendMax.getCurrency(); + const uint160 uMaxCurrencyID = saSendMax.getCurrency(); + const uint160 uMaxIssuerID = saSendMax.getIssuer(); + const uint160 uOutCurrencyID = saSend.getCurrency(); - const uint160 uInIssuerID = !!uInCurrencyID ? saSendMax.getIssuer() : ACCOUNT_XRP; - const uint160 uOutIssuerID = !!uOutCurrencyID ? saSend.getIssuer() : ACCOUNT_XRP; + const uint160 uOutIssuerID = saSend.getIssuer(); + const uint160 uSenderIssuerID = !!uMaxCurrencyID ? uSenderID : ACCOUNT_XRP; // Sender is always issuer for non-XRP. lesEntries = lesSource.duplicate(); + terStatus = tesSUCCESS; + + if ((!uMaxCurrencyID && !!uMaxIssuerID) || (!uOutCurrencyID && !!uOutIssuerID)) + terStatus = temBAD_PATH; + // Push sending node. - terStatus = pushNode( - STPathElement::typeAccount - | STPathElement::typeCurrency - | STPathElement::typeIssuer, - uSenderID, - uInCurrencyID, - uSenderID); + if (tesSUCCESS == terStatus) + terStatus = pushNode( + !!uMaxCurrencyID + ? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeAccount | STPathElement::typeCurrency, + uSenderID, + uMaxCurrencyID, // Max specifes the currency. + uSenderIssuerID); cLog(lsDEBUG) << boost::str(boost::format("PathState: pushed: account=%s currency=%s issuer=%s") % RippleAddress::createHumanAccountID(uSenderID) - % STAmount::createHumanCurrency(uInCurrencyID) - % RippleAddress::createHumanAccountID(uSenderID)); + % STAmount::createHumanCurrency(uMaxCurrencyID) + % RippleAddress::createHumanAccountID(uSenderIssuerID)); if (tesSUCCESS == terStatus - && !!uInCurrencyID // First was not XRC - && uInIssuerID != uSenderID) { // Issuer was not same as sender + && uMaxIssuerID != uSenderIssuerID) { // Issuer was not same as sender // May have an implied node. // Figure out next node properties for implied node. @@ -1698,22 +1739,22 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: implied check: uNxtCurrenc % RippleAddress::createHumanAccountID(uNxtAccountID)); // Can't just use push implied, because it can't compensate for next account. - if (!uNxtCurrencyID // Next is XRC - will have offer next - || uInCurrencyID != uNxtCurrencyID // Next is different current - will have offer next - || uInIssuerID != uNxtAccountID) // Next is not implied issuer + if (!uNxtCurrencyID // Next is XRP - will have offer next + || uMaxCurrencyID != uNxtCurrencyID // Next is different current - will have offer next + || uMaxIssuerID != uNxtAccountID) // Next is not implied issuer { -cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s currency=%s issuer=%s") - % RippleAddress::createHumanAccountID(uInIssuerID) - % RippleAddress::createHumanAccountID(uInCurrencyID) - % RippleAddress::createHumanAccountID(uInIssuerID)); - // Add implied account. +cLog(lsDEBUG) << boost::str(boost::format("PathState: sender implied: account=%s currency=%s issuer=%s") + % RippleAddress::createHumanAccountID(uMaxIssuerID) + % RippleAddress::createHumanAccountID(uMaxCurrencyID) + % RippleAddress::createHumanAccountID(uMaxIssuerID)); + // Add account implied by SendMax. terStatus = pushNode( - STPathElement::typeAccount - | STPathElement::typeCurrency - | STPathElement::typeIssuer, - uInIssuerID, - uInCurrencyID, - uInIssuerID); + !!uMaxCurrencyID + ? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeAccount | STPathElement::typeCurrency, + uMaxIssuerID, + uMaxCurrencyID, + uMaxIssuerID); } } @@ -1726,32 +1767,37 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s curren const PaymentNode& pnPrv = vpnNodes.back(); if (tesSUCCESS == terStatus - && !!uOutCurrencyID // Next is not XRC + && !!uOutCurrencyID // Next is not XRP && uOutIssuerID != uReceiverID // Out issuer is not reciever && (pnPrv.uCurrencyID != uOutCurrencyID // Previous will be an offer. || pnPrv.uAccountID != uOutIssuerID)) // Need the implied issuer. { // Add implied account. +cLog(lsDEBUG) << boost::str(boost::format("PathState: receiver implied: account=%s currency=%s issuer=%s") + % RippleAddress::createHumanAccountID(uOutIssuerID) + % RippleAddress::createHumanAccountID(uOutCurrencyID) + % RippleAddress::createHumanAccountID(uOutIssuerID)); terStatus = pushNode( - STPathElement::typeAccount - | STPathElement::typeCurrency - | STPathElement::typeIssuer, + !!uOutCurrencyID + ? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeAccount | STPathElement::typeCurrency, uOutIssuerID, - uInCurrencyID, + uOutCurrencyID, uOutIssuerID); } if (tesSUCCESS == terStatus) { // Create receiver node. + // Last node is always an account. terStatus = pushNode( - STPathElement::typeAccount // Last node is always an account. - | STPathElement::typeCurrency - | STPathElement::typeIssuer, + !!uOutCurrencyID + ? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeAccount | STPathElement::typeCurrency, uReceiverID, // Receive to output uOutCurrencyID, // Desired currency - !!uOutCurrencyID ? uReceiverID : ACCOUNT_XRP); + uReceiverID); } if (tesSUCCESS == terStatus) @@ -1761,19 +1807,19 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s curren const unsigned int uNodes = vpnNodes.size(); - for (unsigned int uIndex = 0; tesSUCCESS == terStatus && uIndex != uNodes; ++uIndex) + for (unsigned int uNode = 0; tesSUCCESS == terStatus && uNode != uNodes; ++uNode) { - const PaymentNode& pnCur = vpnNodes[uIndex]; + const PaymentNode& pnCur = vpnNodes[uNode]; if (!!pnCur.uAccountID) { // Source is a ripple line nothing(); } - else if (!umForward.insert(std::make_pair(boost::make_tuple(pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uIndex)).second) + else if (!umForward.insert(std::make_pair(boost::make_tuple(pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uNode)).second) { // Failed to insert. Have a loop. - cLog(lsINFO) << boost::str(boost::format("PathState: loop detected: %s") + cLog(lsDEBUG) << boost::str(boost::format("PathState: loop detected: %s") % getJson()); terStatus = temBAD_PATH_LOOP; @@ -1782,8 +1828,8 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s curren } cLog(lsINFO) << boost::str(boost::format("PathState: in=%s/%s out=%s/%s %s") - % STAmount::createHumanCurrency(uInCurrencyID) - % RippleAddress::createHumanAccountID(uInIssuerID) + % STAmount::createHumanCurrency(uMaxCurrencyID) + % RippleAddress::createHumanAccountID(uMaxIssuerID) % STAmount::createHumanCurrency(uOutCurrencyID) % RippleAddress::createHumanAccountID(uOutIssuerID) % getJson()); @@ -1863,23 +1909,23 @@ Json::Value PathState::getJson() const return jvPathState; } -TER RippleCalc::calcNodeFwd(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality) +TER RippleCalc::calcNodeFwd(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality) { - const PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + const PaymentNode& pnCur = pspCur->vpnNodes[uNode]; const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); - cLog(lsINFO) << boost::str(boost::format("calcNodeFwd> uIndex=%d") % uIndex); + cLog(lsINFO) << boost::str(boost::format("calcNodeFwd> uNode=%d") % uNode); TER terResult = bCurAccount - ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) - : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); + ? calcNodeAccountFwd(uNode, pspCur, bMultiQuality) + : calcNodeOfferFwd(uNode, pspCur, bMultiQuality); - if (tesSUCCESS == terResult && uIndex + 1 != pspCur->vpnNodes.size()) + if (tesSUCCESS == terResult && uNode + 1 != pspCur->vpnNodes.size()) { - terResult = calcNodeFwd(uIndex+1, pspCur, bMultiQuality); + terResult = calcNodeFwd(uNode+1, pspCur, bMultiQuality); } - cLog(lsINFO) << boost::str(boost::format("calcNodeFwd< uIndex=%d terResult=%d") % uIndex % terResult); + cLog(lsINFO) << boost::str(boost::format("calcNodeFwd< uNode=%d terResult=%d") % uNode % terResult); return terResult; } @@ -1893,9 +1939,9 @@ TER RippleCalc::calcNodeFwd(const unsigned int uIndex, PathState::ref pspCur, co // --> [all]saWanted.mCurrency // --> [all]saAccount // <-> [0]saWanted.mAmount : --> limit, <-- actual -TER RippleCalc::calcNodeRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality) +TER RippleCalc::calcNodeRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality) { - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnCur = pspCur->vpnNodes[uNode]; const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); TER terResult; @@ -1905,14 +1951,14 @@ TER RippleCalc::calcNodeRev(const unsigned int uIndex, PathState::ref pspCur, co saTransferRate = STAmount::saFromRate(lesActive.rippleTransferRate(uCurIssuerID)); - cLog(lsINFO) << boost::str(boost::format("calcNodeRev> uIndex=%d uIssuerID=%s saTransferRate=%s") - % uIndex + cLog(lsINFO) << boost::str(boost::format("calcNodeRev> uNode=%d uIssuerID=%s saTransferRate=%s") + % uNode % RippleAddress::createHumanAccountID(uCurIssuerID) % saTransferRate.getFullText()); terResult = bCurAccount - ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) - : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); + ? calcNodeAccountRev(uNode, pspCur, bMultiQuality) + : calcNodeOfferRev(uNode, pspCur, bMultiQuality); // Do previous. if (tesSUCCESS != terResult) @@ -1920,14 +1966,14 @@ TER RippleCalc::calcNodeRev(const unsigned int uIndex, PathState::ref pspCur, co // Error, don't continue. nothing(); } - else if (uIndex) + else if (uNode) { // Continue in reverse. - terResult = calcNodeRev(uIndex-1, pspCur, bMultiQuality); + terResult = calcNodeRev(uNode-1, pspCur, bMultiQuality); } - cLog(lsINFO) << boost::str(boost::format("calcNodeRev< uIndex=%d terResult=%s/%d") % uIndex % transToken(terResult) % terResult); + cLog(lsINFO) << boost::str(boost::format("calcNodeRev< uNode=%d terResult=%s/%d") % uNode % transToken(terResult) % terResult); return terResult; } @@ -2024,7 +2070,7 @@ TER RippleCalc::rippleCalc( if (!bNoRippleDirect) { // Direct path. - // XXX Might also make a stamp bridge by default. + // XXX Might also make a XRP bridge by default. PathState::pointer pspDirect = PathState::createPathState( vpsPaths.size(), @@ -2274,7 +2320,7 @@ TER calcOfferFill(PaymentNode& pnSrc, PaymentNode& pnDst, bool bAllowPartial) if (pnDst.saWanted.isNative()) { - // Transfer stamps. + // Transfer XRP. STAmount saSrcFunds = pnSrc.saAccount->accountHolds(pnSrc.saAccount, uint160(0), uint160(0)); @@ -2366,7 +2412,7 @@ void TransactionEngine::calcOfferBridgeNext( if (saOfferPays.isNative()) { - // No additional fees for stamps. + // No additional fees for XRP. nothing(); } @@ -2427,7 +2473,7 @@ void TransactionEngine::calcOfferBridgeNext( #endif #if 0 -// If either currency is not stamps, then also calculates vs stamp bridge. +// If either currency is not XRP, then also calculates vs XRP bridge. // --> saWanted: Limit of how much is wanted out. // <-- saPay: How much to pay into the offer. // <-- saGot: How much to the offer pays out. Never more than saWanted. diff --git a/src/cpp/ripple/RippleCalc.h b/src/cpp/ripple/RippleCalc.h index 7bd6321d2e..6dffe4723d 100644 --- a/src/cpp/ripple/RippleCalc.h +++ b/src/cpp/ripple/RippleCalc.h @@ -142,16 +142,16 @@ public: PathState::pointer pathCreate(const STPath& spPath); 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 calcNode(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeFwd(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeOfferRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeOfferFwd(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeAccountRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeAccountFwd(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); + TER calcNodeAdvance(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality, const bool bReverse); TER calcNodeDeliverRev( - const unsigned int uIndex, + const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality, const uint160& uOutAccountID, @@ -159,7 +159,7 @@ public: STAmount& saOutAct); TER calcNodeDeliverFwd( - const unsigned int uIndex, + const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality, const uint160& uInAccountID, diff --git a/src/cpp/ripple/SerializeProto.h b/src/cpp/ripple/SerializeProto.h index 59acb547a6..00677319a8 100644 --- a/src/cpp/ripple/SerializeProto.h +++ b/src/cpp/ripple/SerializeProto.h @@ -133,7 +133,8 @@ FIELD(ModifiedNode, OBJECT, 5) FIELD(PreviousFields, OBJECT, 6) FIELD(FinalFields, OBJECT, 7) - FIELD(TemplateEntry, OBJECT, 8) + FIELD(NewFields, OBJECT, 8) + FIELD(TemplateEntry, OBJECT, 9) // array of objects // ARRAY/1 is reserved for end of array diff --git a/src/cpp/ripple/SerializedTransaction.cpp b/src/cpp/ripple/SerializedTransaction.cpp index bdc26d77eb..835339cac7 100644 --- a/src/cpp/ripple/SerializedTransaction.cpp +++ b/src/cpp/ripple/SerializedTransaction.cpp @@ -8,13 +8,17 @@ #include "Log.h" #include "HashPrefixes.h" +SETUP_LOG(); DECLARE_INSTANCE(SerializedTransaction); SerializedTransaction::SerializedTransaction(TransactionType type) : STObject(sfTransaction), mType(type) { mFormat = TransactionFormat::getTxnFormat(type); if (mFormat == NULL) + { + cLog(lsWARNING) << "Transaction type: " << type; throw std::runtime_error("invalid transaction type"); + } set(mFormat->elements); setFieldU16(sfTransactionType, mFormat->t_type); } @@ -24,7 +28,10 @@ SerializedTransaction::SerializedTransaction(const STObject& object) : STObject( mType = static_cast(getFieldU16(sfTransactionType)); mFormat = TransactionFormat::getTxnFormat(mType); if (!mFormat) + { + cLog(lsWARNING) << "Transaction type: " << mType; throw std::runtime_error("invalid transaction type"); + } if (!setType(mFormat->elements)) { throw std::runtime_error("transaction not valid"); @@ -45,7 +52,10 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit) : STObject mFormat = TransactionFormat::getTxnFormat(mType); if (!mFormat) + { + cLog(lsWARNING) << "Transaction type: " << mType; throw std::runtime_error("invalid transaction type"); + } if (!setType(mFormat->elements)) { assert(false); @@ -206,10 +216,10 @@ BOOST_AUTO_TEST_CASE( STrans_test ) RippleAddress publicAcct = RippleAddress::createAccountPublic(generator, 1); RippleAddress privateAcct = RippleAddress::createAccountPrivate(generator, seed, 1); - SerializedTransaction j(ttCLAIM); + SerializedTransaction j(ttACCOUNT_SET); j.setSourceAccount(publicAcct); j.setSigningPubKey(publicAcct); - j.setFieldVL(sfPublicKey, publicAcct.getAccountPublic()); + j.setFieldVL(sfMessageKey, publicAcct.getAccountPublic()); j.sign(privateAcct); if (!j.checkSign()) BOOST_FAIL("Transaction fails signature test"); diff --git a/src/cpp/ripple/SerializedValidation.cpp b/src/cpp/ripple/SerializedValidation.cpp index 75d8249abb..c344e10029 100644 --- a/src/cpp/ripple/SerializedValidation.cpp +++ b/src/cpp/ripple/SerializedValidation.cpp @@ -39,26 +39,32 @@ SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSi } SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 signTime, - const RippleAddress& naPub, const RippleAddress& naPriv, bool isFull, uint256& signingHash) + const RippleAddress& raPub, bool isFull) : STObject(sValidationFormat, sfValidation), mTrusted(false) -{ +{ // Does not sign setFieldH256(sfLedgerHash, ledgerHash); setFieldU32(sfSigningTime, signTime); - setFieldVL(sfSigningPubKey, naPub.getNodePublic()); - mNodeID = naPub.getNodeID(); + setFieldVL(sfSigningPubKey, raPub.getNodePublic()); + mNodeID = raPub.getNodeID(); assert(mNodeID.isNonZero()); if (!isFull) setFlag(sFullFlag); +} +void SerializedValidation::sign(const RippleAddress& raPriv) +{ + uint256 signingHash; + sign(signingHash, raPriv); +} + +void SerializedValidation::sign(uint256& signingHash, const RippleAddress& raPriv) +{ signingHash = getSigningHash(); std::vector signature; - naPriv.signNodePrivate(signingHash, signature); + raPriv.signNodePrivate(signingHash, signature); setFieldVL(sfSignature, signature); - // XXX Check if this can fail. - // if (!RippleAddress::createNodePrivate(naSeed).signNodePrivate(getSigningHash(), mSignature.peekValue())) - // throw std::runtime_error("Unable to sign validation"); } uint256 SerializedValidation::getSigningHash() const @@ -90,8 +96,8 @@ bool SerializedValidation::isValid(const uint256& signingHash) const { try { - RippleAddress naPublicKey = RippleAddress::createNodePublic(getFieldVL(sfSigningPubKey)); - return naPublicKey.isValid() && naPublicKey.verifyNodePublic(signingHash, getFieldVL(sfSignature)); + RippleAddress raPublicKey = RippleAddress::createNodePublic(getFieldVL(sfSigningPubKey)); + return raPublicKey.isValid() && raPublicKey.verifyNodePublic(signingHash, getFieldVL(sfSignature)); } catch (...) { diff --git a/src/cpp/ripple/SerializedValidation.h b/src/cpp/ripple/SerializedValidation.h index 57b3b42a8b..72e1fc50ec 100644 --- a/src/cpp/ripple/SerializedValidation.h +++ b/src/cpp/ripple/SerializedValidation.h @@ -24,13 +24,14 @@ public: // These throw if the object is not valid SerializedValidation(SerializerIterator& sit, bool checkSignature = true); - SerializedValidation(const uint256& ledgerHash, uint32 signTime, const RippleAddress& naPub, - const RippleAddress& naPriv, bool isFull, uint256& signingHash); + + // Does not sign the validation + SerializedValidation(const uint256& ledgerHash, uint32 signTime, const RippleAddress& raPub, bool isFull); uint256 getLedgerHash() const; uint32 getSignTime() const; uint32 getFlags() const; - RippleAddress getSignerPublic() const; + RippleAddress getSignerPublic() const; uint160 getNodeID() const { return mNodeID; } bool isValid() const; bool isFull() const; @@ -41,6 +42,8 @@ public: void setTrusted() { mTrusted = true; } std::vector getSigned() const; std::vector getSignature() const; + void sign(uint256& signingHash, const RippleAddress& raPrivate); + void sign(const RippleAddress& raPrivate); // The validation this replaced const uint256& getPreviousHash() { return mPreviousHash; } diff --git a/src/cpp/ripple/TaggedCache.h b/src/cpp/ripple/TaggedCache.h index 2cdfc708c2..c8ee1d20eb 100644 --- a/src/cpp/ripple/TaggedCache.h +++ b/src/cpp/ripple/TaggedCache.h @@ -12,7 +12,7 @@ #include "Log.h" extern LogPartition TaggedCachePartition; -// This class implemented a cache and a map. The cache keeps objects alive +// This class implements a cache and a map. The cache keeps objects alive // in the map. The map allows multiple code paths that reference objects // with the same tag to get the same actual object. @@ -258,4 +258,4 @@ bool TaggedCache::retrieve(const key_type& key, c_Data& data) return true; } -#endif \ No newline at end of file +#endif diff --git a/src/cpp/ripple/TransactionMeta.cpp b/src/cpp/ripple/TransactionMeta.cpp index 182a25a77c..f7b21bb8de 100644 --- a/src/cpp/ripple/TransactionMeta.cpp +++ b/src/cpp/ripple/TransactionMeta.cpp @@ -31,13 +31,14 @@ bool TransactionMetaSet::isNodeAffected(const uint256& node) const return false; } -void TransactionMetaSet::setAffectedNode(const uint256& node, SField::ref type) +void TransactionMetaSet::setAffectedNode(const uint256& node, SField::ref type, uint16 nodeType) { // make sure the node exists and force its type BOOST_FOREACH(STObject& it, mNodes) { if (it.getFieldH256(sfLedgerIndex) == node) { it.setFName(type); + it.setFieldU16(sfLedgerEntryType, nodeType); return; } } @@ -47,6 +48,7 @@ void TransactionMetaSet::setAffectedNode(const uint256& node, SField::ref type) assert(obj.getFName() == type); obj.setFieldH256(sfLedgerIndex, node); + obj.setFieldU16(sfLedgerEntryType, nodeType); } /* diff --git a/src/cpp/ripple/TransactionMeta.h b/src/cpp/ripple/TransactionMeta.h index 994e325a01..a22058089e 100644 --- a/src/cpp/ripple/TransactionMeta.h +++ b/src/cpp/ripple/TransactionMeta.h @@ -39,7 +39,7 @@ public: uint32 getLgrSeq() { return mLedger; } bool isNodeAffected(const uint256&) const; - void setAffectedNode(const uint256&, SField::ref type); + void setAffectedNode(const uint256&, SField::ref type, uint16 nodeType); STObject& getAffectedNode(const uint256&, SField::ref type); STObject& getAffectedNode(const uint256&); const STObject& peekAffectedNode(const uint256&) const; diff --git a/src/cpp/ripple/ValidationCollection.cpp b/src/cpp/ripple/ValidationCollection.cpp index f4c7b941ba..eded830c66 100644 --- a/src/cpp/ripple/ValidationCollection.cpp +++ b/src/cpp/ripple/ValidationCollection.cpp @@ -97,12 +97,12 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren uint32 now = theApp->getOPs().getNetworkTimeNC(); if (set) { - for (ValidationSet::iterator vit = set->begin(), end = set->end(); vit != end; ++vit) + BOOST_FOREACH(u160_val_pair& it, *set) { - bool isTrusted = vit->second->isTrusted(); + bool isTrusted = it.second->isTrusted(); if (isTrusted && currentOnly) { - uint32 closeTime = vit->second->getSignTime(); + uint32 closeTime = it.second->getSignTime(); if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_VAL_INTERVAL))) isTrusted = false; else @@ -119,6 +119,28 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren cLog(lsTRACE) << "VC: " << ledger << "t:" << trusted << " u:" << untrusted; } +void ValidationCollection::getValidationTypes(const uint256& ledger, int& full, int& partial) +{ + full = partial = 0; + boost::mutex::scoped_lock sl(mValidationLock); + VSpointer set = findSet(ledger); + if (set) + { + BOOST_FOREACH(u160_val_pair& it, *set) + { + if (it.second->isTrusted()) + { + if (it.second->isFull()) + ++full; + else + ++partial; + } + } + } + cLog(lsTRACE) << "VC: " << ledger << "f:" << full << " p:" << partial; +} + + int ValidationCollection::getTrustedValidationCount(const uint256& ledger) { int trusted = 0; @@ -126,9 +148,9 @@ int ValidationCollection::getTrustedValidationCount(const uint256& ledger) VSpointer set = findSet(ledger); if (set) { - for (ValidationSet::iterator vit = set->begin(), end = set->end(); vit != end; ++vit) + BOOST_FOREACH(u160_val_pair& it, *set) { - if (vit->second->isTrusted()) + if (it.second->isTrusted()) ++trusted; } } diff --git a/src/cpp/ripple/ValidationCollection.h b/src/cpp/ripple/ValidationCollection.h index e4a22ec4fc..51f60a5a94 100644 --- a/src/cpp/ripple/ValidationCollection.h +++ b/src/cpp/ripple/ValidationCollection.h @@ -38,6 +38,7 @@ public: bool addValidation(const SerializedValidation::pointer&); ValidationSet getValidations(const uint256& ledger); void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted); + void getValidationTypes(const uint256& ledger, int& full, int& partial); int getTrustedValidationCount(const uint256& ledger); diff --git a/src/cpp/ripple/uint256.h b/src/cpp/ripple/uint256.h index 3e2ab10e62..e7e5e449ee 100644 --- a/src/cpp/ripple/uint256.h +++ b/src/cpp/ripple/uint256.h @@ -23,7 +23,7 @@ #endif // These classes all store their values internally -// in little-endian form +// in big-endian form inline int Testuint256AdHoc(std::vector vArg); @@ -36,7 +36,7 @@ protected: enum { WIDTH=BITS/32 }; // This is really big-endian in byte order. - // We use unsigned int for speed. + // We sometimes use unsigned int for speed. unsigned int pn[WIDTH]; public: @@ -73,7 +73,7 @@ public: zero(); // Put in least significant bits. - ((uint64_t *) end())[-1] = htobe64(uHost); + ((uint64_t *) end())[-1] = htobe64(uHost); return *this; } @@ -105,10 +105,12 @@ public: base_uint& operator++() { // prefix operator - int i = WIDTH; - - while (i-- && !++pn[i]) - ; + for (int i = WIDTH - 1; i >= 0; --i) + { + pn[i] = htobe32(be32toh(pn[i]) + 1); + if (pn[i] != 0) + break; + } return *this; } @@ -124,10 +126,13 @@ public: base_uint& operator--() { - int i = WIDTH; - - while (i-- && !pn[i]--) - ; + for (int i = WIDTH - 1; i >= 0; --i) + { + uint32 prev = pn[i]; + pn[i] = htobe32(be32toh(pn[i]) - 1); + if (prev != 0) + break; + } return *this; } @@ -169,10 +174,14 @@ public: const unsigned char* pAEnd = a.end(); const unsigned char* pB = b.begin(); - while (pA != pAEnd && *pA == *pB) - pA++, pB++; + while (*pA == *pB) + { + if (++pA == pAEnd) + return 0; + ++pB; + } - return pA == pAEnd ? 0 : *pA < *pB ? -1 : *pA > *pB ? 1 : 0; + return (*pA < *pB) ? -1 : 1; } friend inline bool operator<(const base_uint& a, const base_uint& b) diff --git a/src/js/remote.js b/src/js/remote.js index 40e931f9d7..9e3ee74979 100644 --- a/src/js/remote.js +++ b/src/js/remote.js @@ -530,21 +530,16 @@ Remote.prototype.request = function (request) { }; Remote.prototype.request_server_info = function () { - var request = new Request(this, 'rpc'); - - request.message.command = 'server_info'; - - return request; + return new Request(this, 'server_info'); }; Remote.prototype.request_ledger = function (params) { // XXX Does this require the server to be trusted? //assert(this.trusted); - var request = new Request(this, 'rpc'); + var request = new Request(this, 'ledger'); - request.message.command = 'ledger'; - request.message.params = params; + request.message.params = params; return request; }; @@ -553,21 +548,19 @@ Remote.prototype.request_ledger = function (params) { Remote.prototype.request_ledger_hash = function () { assert(this.trusted); // If not trusted, need to check proof. - var request = new Request(this, 'rpc'); - - request.message.command = 'ledger_closed'; + return new Request(this, 'ledger_closed'); +}; - return request; +// .ledger() +// .ledger_index() +Remote.prototype.request_ledger_header = function () { + return new Request(this, 'ledger_header'); }; // Get the current proposed ledger entry. May be closed (and revised) at any time (even before returning). // Only for unit testing. Remote.prototype.request_ledger_current = function () { - var request = new Request(this, 'rpc'); - - request.message.command = 'ledger_current'; - - return request; + return new Request(this, 'ledger_current'); }; // --> type : the type of ledger entry. @@ -578,9 +571,7 @@ Remote.prototype.request_ledger_entry = function (type) { assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol. var self = this; - var request = new Request(this, 'rpc'); - - request.message.command = 'ledger_entry'; + var request = new Request(this, 'ledger_entry'); if (type) this.type = type; @@ -662,11 +653,7 @@ Remote.prototype.request_unsubscribe = function (streams) { Remote.prototype.request_transaction_entry = function (hash) { assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol. - var request = new Request(this, 'rpc'); - - request.message.command = 'transaction_entry'; - - return request + return (new Request(this, 'transaction_entry')) .tx_hash(hash); }; @@ -674,9 +661,8 @@ Remote.prototype.request_ripple_lines_get = function (accountID) { // XXX Does this require the server to be trusted? //assert(this.trusted); - var request = new Request(this, 'rpc'); + var request = new Request(this, 'ripple_lines_get'); - request.message.command = 'ripple_lines_get'; // XXX Convert API call to JSON request.message.params = [accountID]; @@ -687,9 +673,8 @@ Remote.prototype.request_wallet_accounts = function (key) { // XXX Does this require the server to be trusted? //assert(this.trusted); - var request = new Request(this, 'rpc'); + var request = new Request(this, 'wallet_accounts'); - request.message.command = 'wallet_accounts'; // XXX Convert API call to JSON request.message.params = [key]; @@ -700,9 +685,8 @@ Remote.prototype.request_account_tx = function (accountID, minLedger, maxLedger) // XXX Does this require the server to be trusted? //assert(this.trusted); - var request = new Request(this, 'rpc'); + var request = new Request(this, 'account_tx'); - request.message.command = 'account_tx'; // XXX Convert API call to JSON request.message.params = [accountID, minLedger, maxLedger]; @@ -751,9 +735,7 @@ Remote.prototype.submit = function (transaction) { .request(); } else { - var submit_request = new Request(this, 'rpc'); - - submit_request.message.command = 'submit_json'; + var submit_request = new Request(this, 'submit_json'); submit_request.tx_json(transaction.tx_json); submit_request.secret(transaction.secret); @@ -808,9 +790,7 @@ Remote.prototype._server_subscribe = function () { Remote.prototype.ledger_accept = function () { if (this.stand_alone || undefined === this.stand_alone) { - var request = new Request(this, 'rpc'); - - request.message.command = 'ledger_accept'; + var request = new Request(this, 'ledger_accept'); request .request(); @@ -957,43 +937,32 @@ Remote.prototype.request_ripple_balance = function (account, issuer, currency, c } Remote.prototype.request_unl_list = function () { - var request = new Request(this, 'rpc'); - - request.message.command = 'unl_list'; - - return request; + return new Request(this, 'unl_list'); }; Remote.prototype.request_unl_add = function (addr, note) { - var request = new Request(this, 'rpc'); + var request = new Request(this, 'unl_add'); - request.message.command = 'unl_add'; request.message.params = [addr, note]; return request; }; Remote.prototype.request_unl_delete = function (publicKey) { - var request = new Request(this, 'rpc'); + var request = new Request(this, 'unl_delete'); - request.message.command = 'unl_delete'; request.message.params = [publicKey]; return request; }; Remote.prototype.request_peers = function () { - var request = new Request(this, 'rpc'); - - request.message.command = 'peers'; - - return request; + return new Request(this, 'peers'); }; Remote.prototype.request_connect = function (ip, port) { - var request = new Request(this, 'rpc'); + var request = new Request(this, 'connect'); - request.message.command = 'connect'; request.message.params = [ip, port]; return request; @@ -1421,7 +1390,7 @@ Transaction.prototype.payment = function (src, dst, deliver_amount) { Transaction.prototype.ripple_line_set = function (src, limit, quality_in, quality_out) { this.secret = this._account_secret(src); - this.tx_json.TransactionType = 'CreditSet'; + this.tx_json.TransactionType = 'TrustSet'; this.tx_json.Account = UInt160.json_rewrite(src); // Allow limit of 0 through.