diff --git a/src/Amount.cpp b/src/Amount.cpp index f02acf78b8..a141dc7ca8 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -45,11 +45,16 @@ bool STAmount::currencyFromString(uint160& uDstCurrency, const std::string& sCur } // XXX Broken for custom currencies? -std::string STAmount::getCurrencyHuman() const +std::string STAmount::getHumanCurrency() const +{ + return createHumanCurrency(mCurrency); +} + +std::string STAmount::createHumanCurrency(const uint160& uCurrency) { std::string sCurrency; - if (mIsNative) + if (uCurrency.isZero()) { return SYSTEM_CURRENCY_CODE; } @@ -57,7 +62,7 @@ std::string STAmount::getCurrencyHuman() const { Serializer s(160/8); - s.add160(mCurrency); + s.add160(uCurrency); SerializerIterator sit(s); @@ -664,9 +669,6 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16 uint64 value1 = v1.mValue, value2 = v2.mValue; int offset1 = v1.mOffset, offset2 = v2.mOffset; - int finOffset = offset1 + offset2; - if ((finOffset > 80) || (finOffset < 22)) - throw std::runtime_error("multiplication produces out of range result"); if (v1.mIsNative) { @@ -698,11 +700,15 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16 --offset2; } + int finOffset = offset1 + offset2; + if ((finOffset > 80) || (finOffset < -96)) + throw std::runtime_error("multiplication produces out of range result"); + // Compute (numerator*10 * denominator*10) / 10^18 with rounding CBigNum v; if ((BN_add_word(&v, value1) != 1) || (BN_mul_word(&v, value2) != 1) || - (BN_div_word(&v, 1000000000000000000ul) == ((BN_ULONG) -1))) + (BN_div_word(&v, 100000000000000ul) == ((BN_ULONG) -1))) { throw std::runtime_error("internal bn error"); } @@ -836,13 +842,15 @@ Json::Value STAmount::getJson(int) const { Json::Value elem(Json::objectValue); - - // This is a hack, many places don't specify a currency. STAmount is used just as a value. if (!mIsNative) { elem["value"] = getText(); - elem["currency"] = getCurrencyHuman(); + elem["currency"] = getHumanCurrency(); + + if (!mIssuer.isZero()) + elem["issuer"] = NewcoinAddress::createHumanAccountID(mIssuer); + }else { elem=getText(); @@ -1028,6 +1036,12 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test ) if (STAmount(currency,31,1).getText() != "310") BOOST_FAIL("STAmount fail"); if (STAmount(currency,31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail"); if (STAmount(currency,31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail"); + + if (STAmount::multiply(STAmount(currency, 20) , STAmount(3), currency).getText() != "60") + BOOST_FAIL("STAmount multiply fail"); + if (STAmount::multiply(STAmount(currency, 20) , STAmount(3), uint160()).getText() != "60") + BOOST_FAIL("STAmount multiply fail"); + BOOST_TEST_MESSAGE("Amount CC Complete"); } diff --git a/src/CallRPC.cpp b/src/CallRPC.cpp index f12acaede6..38f697a1e7 100644 --- a/src/CallRPC.cpp +++ b/src/CallRPC.cpp @@ -131,7 +131,7 @@ Json::Value callRPC(const std::string& strMethod, const Json::Value& params) std::string strPost = createHTTPPost(strRequest, mapRequestHeaders); stream << strPost << std::flush; - std::cout << "post " << strPost << std::endl; + // std::cout << "post " << strPost << std::endl; // Receive reply std::map mapHeaders; diff --git a/src/Config.cpp b/src/Config.cpp index f2347cc6f0..e8e81747d3 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -106,9 +106,9 @@ void Config::setup(const std::string& strConf) if (ec) throw std::runtime_error(str(boost::format("Can not create %s") % DATA_DIR)); - std::cerr << "CONFIG FILE: " << CONFIG_FILE << std::endl; - std::cerr << "CONFIG DIR: " << CONFIG_DIR << std::endl; - std::cerr << "DATA DIR: " << DATA_DIR << std::endl; + // std::cerr << "CONFIG FILE: " << CONFIG_FILE << std::endl; + // std::cerr << "CONFIG DIR: " << CONFIG_DIR << std::endl; + // std::cerr << "DATA DIR: " << DATA_DIR << std::endl; // // Defaults @@ -190,7 +190,7 @@ void Config::load() if (smtTmp) { IPS = *smtTmp; - sectionEntriesPrint(&IPS, SECTION_IPS); + // sectionEntriesPrint(&IPS, SECTION_IPS); } (void) sectionSingleB(secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE); diff --git a/src/Ledger.cpp b/src/Ledger.cpp index ef85985e39..aa279f8a46 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -230,11 +230,6 @@ bool Ledger::addTransaction(const uint256& txID, const Serializer& txn) return true; } -bool Ledger::hasTransaction(const uint256& transID) const -{ - return mTransactionMap->hasItem(transID); -} - Transaction::pointer Ledger::getTransaction(const uint256& transID) const { SHAMapItem::pointer item = mTransactionMap->peekItem(transID); diff --git a/src/Ledger.h b/src/Ledger.h index 5ba21b74fc..f830124e22 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -151,7 +151,7 @@ public: bool isAcquiringAS(void); // Transaction Functions - bool hasTransaction(const uint256& TransID) const; + bool hasTransaction(const uint256& TransID) const { return mTransactionMap->hasItem(TransID); } Transaction::pointer getTransaction(const uint256& transID) const; // high-level functions @@ -167,12 +167,12 @@ public: // next/prev function SLE::pointer getSLE(const uint256& uHash); - SLE::pointer getFirstSLE(); - SLE::pointer getLastSLE(); - SLE::pointer getNextSLE(const uint256& uHash); // first node >hash - SLE::pointer getNextSLE(const uint256& uHash, const uint256& uEnd); // first node >hash, begin + uint256 getFirstLedgerIndex(); + uint256 getLastLedgerIndex(); + uint256 getNextLedgerIndex(const uint256& uHash); // first node >hash + uint256 getNextLedgerIndex(const uint256& uHash, const uint256& uEnd); // first node >hash, begin // index calculation functions static uint256 getAccountRootIndex(const uint160& uAccountID); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 82ec0b42e5..8b2d51cf23 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -180,7 +180,7 @@ bool LCTransaction::updatePosition(int percentTime, bool proposing) { #ifdef LC_DEBUG Log(lsTRACE) << "No change (" << (mOurPosition ? "YES" : "NO") << ") : weight " - << weight << ", seconds " << seconds; + << weight << ", percent " << percentTime; #endif return false; } @@ -191,14 +191,14 @@ bool LCTransaction::updatePosition(int percentTime, bool proposing) LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime) : mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger), - mCurrentSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false) + mCurrentMSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false) { mValSeed = theConfig.VALIDATION_SEED; Log(lsDEBUG) << "Creating consensus object"; Log(lsTRACE) << "LCL:" << previousLedger->getHash().GetHex() <<", ct=" << closeTime; mPreviousProposers = theApp->getOPs().getPreviousProposers(); - mPreviousSeconds = theApp->getOPs().getPreviousSeconds(); - assert(mPreviousSeconds); + mPreviousMSeconds = theApp->getOPs().getPreviousConvergeTime(); + assert(mPreviousMSeconds); mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( previousLedger->getCloseResolution(), previousLedger->getCloseAgree(), previousLedger->getLedgerSeq() + 1); @@ -226,11 +226,11 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre } } -void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger) +void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) { - SHAMap::pointer initialSet = initialLedger->peekTransactionMap()->snapShot(false); + SHAMap::pointer initialSet = initialLedger.peekTransactionMap()->snapShot(false); uint256 txSet = initialSet->getHash(); - assert (!mHaveCorrectLCL || (initialLedger->getParentHash() == mPreviousLedger->getHash())); + assert (!mHaveCorrectLCL || (initialLedger.getParentHash() == mPreviousLedger->getHash())); // if any peers have taken a contrary position, process disputes boost::unordered_set found; @@ -248,11 +248,12 @@ void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger) if (mValidating) mOurPosition = boost::make_shared - (mValSeed, initialLedger->getParentHash(), txSet, mCloseTime); + (mValSeed, initialLedger.getParentHash(), txSet, mCloseTime); else - mOurPosition = boost::make_shared(initialLedger->getParentHash(), txSet, mCloseTime); + mOurPosition = boost::make_shared(initialLedger.getParentHash(), txSet, mCloseTime); mapComplete(txSet, initialSet, false); - if (mProposing) propose(std::vector(), std::vector()); + if (mProposing) + propose(std::vector(), std::vector()); } void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2) @@ -339,18 +340,18 @@ void LedgerConsensus::adjustCount(SHAMap::pointer map, const std::vectorgetLedgerSeq()); + s.set_ledgerseq(ledger.getLedgerSeq()); s.set_networktime(theApp->getOPs().getNetworkTimeNC()); - uint256 hash = ledger->getParentHash(); + uint256 hash = ledger.getParentHash(); s.set_ledgerhashprevious(hash.begin(), hash.size()); - hash = ledger->getHash(); + hash = ledger.getHash(); s.set_ledgerhash(hash.begin(), hash.size()); PackedMessage::pointer packet = boost::make_shared(s, newcoin::mtSTATUS_CHANGE); theApp->getConnectionPool().relayMessage(NULL, packet); @@ -367,26 +368,25 @@ void LedgerConsensus::statePreClose() bool anyTransactions = theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap()->getHash().isNonZero(); int proposersClosed = mPeerPositions.size(); - int sinceClose = theApp->getOPs().getNetworkTimeNC() - theApp->getOPs().getLastCloseNetTime(); + // This ledger is open. This computes how long since the last ledger closed + int sinceClose = 1000 * (theApp->getOPs().getNetworkTimeNC() - theApp->getOPs().getLastCloseNetTime()); if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed, - mPreviousSeconds, sinceClose)) - { // it is time to close the ledger (swap default and wobble ledgers) - Log(lsINFO) << "CLC:: closing ledger"; + mPreviousMSeconds, sinceClose)) + { // it is time to close the ledger + Log(lsINFO) << "CLC: closing ledger"; mState = lcsESTABLISH; mConsensusStartTime = boost::posix_time::second_clock::universal_time(); mCloseTime = theApp->getOPs().getNetworkTimeNC(); theApp->getOPs().setLastCloseNetTime(mCloseTime); - statusChange(newcoin::neCLOSING_LEDGER, mPreviousLedger); - Ledger::pointer initial = theApp->getMasterLedger().closeLedger(); - assert (initial->getParentHash() == mPreviousLedger->getHash()); - takeInitialPosition(initial); + statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger); + takeInitialPosition(*theApp->getMasterLedger().closeLedger()); } } void LedgerConsensus::stateEstablish() { // we are establishing consensus - if (mCurrentSeconds < LEDGER_MIN_CONSENSUS) + if (mCurrentMSeconds < LEDGER_MIN_CONSENSUS) return; updateOurPositions(); if (!mHaveCloseTimeConsensus) @@ -406,9 +406,7 @@ void LedgerConsensus::stateFinished() // logic of calculating next ledger advances us out of this state // CHECKME: Should we count proposers that didn't converge to our consensus set? - int convergeTime = (boost::posix_time::second_clock::universal_time() - mConsensusStartTime).seconds(); - if (convergeTime <= 0) convergeTime = 1; - theApp->getOPs().newLCL(mPeerPositions.size(), convergeTime, mNewLedgerHash); + theApp->getOPs().newLCL(mPeerPositions.size(), mCurrentMSeconds, mNewLedgerHash); } void LedgerConsensus::stateAccepted() @@ -433,14 +431,15 @@ void LedgerConsensus::timerEntry() else Log(lsINFO) << "We still don't have it"; } - mCurrentSeconds = (mCloseTime != 0) ? (theApp->getOPs().getNetworkTimeNC() - mCloseTime) : 0; - mClosePercent = mCurrentSeconds * 100 / mPreviousSeconds; + mCurrentMSeconds = (mCloseTime == 0) ? 0 : + (boost::posix_time::second_clock::universal_time() - mConsensusStartTime).total_milliseconds(); + mClosePercent = mCurrentMSeconds * 100 / mPreviousMSeconds; switch (mState) { - case lcsPRE_CLOSE: statePreClose(); return; - case lcsESTABLISH: stateEstablish(); return; - case lcsFINISHED: stateFinished(); return; + case lcsPRE_CLOSE: statePreClose(); if (mState != lcsESTABLISH) return; + case lcsESTABLISH: stateEstablish(); if (mState != lcsFINISHED) return; + case lcsFINISHED: stateFinished(); if (mState != lcsACCEPTED) return; case lcsACCEPTED: stateAccepted(); return; } assert(false); @@ -527,7 +526,7 @@ bool LedgerConsensus::haveConsensus() } int currentValidations = theApp->getValidations().getCurrentValidationCount(mPreviousLedger->getCloseTimeNC()); return ContinuousLedgerTiming::haveConsensus(mPreviousProposers, agree + disagree, agree, currentValidations, - mPreviousSeconds, mCurrentSeconds); + mPreviousMSeconds, mCurrentMSeconds); } SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool doAcquire) @@ -535,6 +534,19 @@ SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool do boost::unordered_map::iterator it = mComplete.find(hash); if (it == mComplete.end()) { // we have not completed acquiring this ledger + + if (mState == lcsPRE_CLOSE) + { + SHAMap::pointer currentMap = theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(); + if (currentMap->getHash() == hash) + { + Log(lsINFO) << "node proposes our open transaction set"; + currentMap = currentMap->snapShot(false); + mapComplete(hash, currentMap, false); + return currentMap; + } + } + if (doAcquire) { TransactionAcquire::pointer& acquiring = mAcquiring[hash]; @@ -735,29 +747,32 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTran #endif } -void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer ledger, +void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer applyLedger, Ledger::pointer checkLedger, CanonicalTXSet& failedTransactions, bool final) { TransactionEngineParams parms = final ? (tepNO_CHECK_FEE | tepUPDATE_TOTAL) : tepNONE; - TransactionEngine engine(ledger); + TransactionEngine engine(applyLedger); for (SHAMapItem::pointer item = set->peekFirstItem(); !!item; item = set->peekNextItem(item->getTag())) { - Log(lsINFO) << "Processing candidate transaction: " << item->getTag().GetHex(); -#ifndef TRUST_NETWORK - try + if (!checkLedger->hasTransaction(item->getTag())) { -#endif - SerializerIterator sit(item->peekSerializer()); - SerializedTransaction::pointer txn = boost::make_shared(boost::ref(sit)); - applyTransaction(engine, txn, ledger, failedTransactions, final); + Log(lsINFO) << "Processing candidate transaction: " << item->getTag().GetHex(); #ifndef TRUST_NETWORK - } - catch (...) - { - Log(lsWARNING) << " Throws"; - } + try + { #endif + SerializerIterator sit(item->peekSerializer()); + SerializedTransaction::pointer txn = boost::make_shared(boost::ref(sit)); + applyTransaction(engine, txn, applyLedger, failedTransactions, final); +#ifndef TRUST_NETWORK + } + catch (...) + { + Log(lsWARNING) << " Throws"; + } +#endif + } } int successes; @@ -800,7 +815,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) newLCL->armDirty(); CanonicalTXSet failedTransactions(set->getHash()); - applyTransactions(set, newLCL, failedTransactions, true); + applyTransactions(set, newLCL, newLCL, failedTransactions, true); newLCL->setClosed(); uint32 closeTime = mOurPosition->getCloseTime(); @@ -815,7 +830,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) newLCL->updateHash(); uint256 newLCLHash = newLCL->getHash(); Log(lsTRACE) << "newLCL " << newLCLHash.GetHex(); - statusChange(newcoin::neACCEPTED_LEDGER, newLCL); + statusChange(newcoin::neACCEPTED_LEDGER, *newLCL); if (mValidating) { assert (theApp->getOPs().getNetworkTimeNC() > newLCL->getCloseTimeNC()); @@ -843,6 +858,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) { // we voted NO try { + Log(lsINFO) << "Test applying disputed transaction that did not get in"; SerializerIterator sit(it->second->peekTransaction()); SerializedTransaction::pointer txn = boost::make_shared(boost::ref(sit)); applyTransaction(engine, txn, newOL, failedTransactions, false); @@ -854,7 +870,8 @@ void LedgerConsensus::accept(SHAMap::pointer set) } } - applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), newOL, + Log(lsINFO) << "Applying transactions from current ledger"; + applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), newOL, newLCL, failedTransactions, false); theApp->getMasterLedger().pushLedger(newLCL, newOL); mNewLedgerHash = newLCL->getHash(); diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 235c670686..215175d8e3 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -86,12 +86,12 @@ protected: NewcoinAddress mValSeed; bool mProposing, mValidating, mHaveCorrectLCL; - int mCurrentSeconds, mClosePercent, mCloseResolution; + int mCurrentMSeconds, mClosePercent, mCloseResolution; bool mHaveCloseTimeConsensus; boost::posix_time::ptime mConsensusStartTime; int mPreviousProposers; - int mPreviousSeconds; + int mPreviousMSeconds; // Convergence tracking, trusted peers indexed by hash of public key boost::unordered_map mPeerPositions; @@ -125,14 +125,14 @@ protected: void addPosition(LedgerProposal&, bool ours); void removePosition(LedgerProposal&, bool ours); void sendHaveTxSet(const uint256& set, bool direct); - void applyTransactions(SHAMap::pointer transactionSet, Ledger::pointer targetLedger, + void applyTransactions(SHAMap::pointer transactionSet, Ledger::pointer targetLedger, Ledger::pointer checkLedger, CanonicalTXSet& failedTransactions, bool final); void applyTransaction(TransactionEngine& engine, SerializedTransaction::pointer txn, Ledger::pointer targetLedger, CanonicalTXSet& failedTransactions, bool final); // manipulating our own position - void statusChange(newcoin::NodeEvent, Ledger::pointer ledger); - void takeInitialPosition(Ledger::pointer initialLedger); + void statusChange(newcoin::NodeEvent, Ledger& ledger); + void takeInitialPosition(Ledger& initialLedger); void updateOurPositions(); int getThreshold(); void beginAccept(); diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp index 442925875c..bbb4b7e969 100644 --- a/src/LedgerNode.cpp +++ b/src/LedgerNode.cpp @@ -53,52 +53,44 @@ SLE::pointer Ledger::getSLE(const uint256& uHash) return boost::make_shared(node->peekSerializer(), node->getTag()); } -SLE::pointer Ledger::getFirstSLE() +uint256 Ledger::getFirstLedgerIndex() { SHAMapItem::pointer node = mAccountStateMap->peekFirstItem(); - if (!node) - return SLE::pointer(); - return boost::make_shared(node->peekSerializer(), node->getTag()); + return node ? node->getTag() : uint256(); } -SLE::pointer Ledger::getLastSLE() +uint256 Ledger::getLastLedgerIndex() { SHAMapItem::pointer node = mAccountStateMap->peekLastItem(); - if (!node) - return SLE::pointer(); - return boost::make_shared(node->peekSerializer(), node->getTag()); + return node ? node->getTag() : uint256(); } -SLE::pointer Ledger::getNextSLE(const uint256& uHash) +uint256 Ledger::getNextLedgerIndex(const uint256& uHash) { SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash); - if (!node) - return SLE::pointer(); - return boost::make_shared(node->peekSerializer(), node->getTag()); + return node ? node->getTag() : uint256(); } -SLE::pointer Ledger::getNextSLE(const uint256& uHash, const uint256& uEnd) +uint256 Ledger::getNextLedgerIndex(const uint256& uHash, const uint256& uEnd) { SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash); if ((!node) || (node->getTag() > uEnd)) - return SLE::pointer(); - return boost::make_shared(node->peekSerializer(), node->getTag()); + return uint256(); + return node->getTag(); } -SLE::pointer Ledger::getPrevSLE(const uint256& uHash) +uint256 Ledger::getPrevLedgerIndex(const uint256& uHash) { SHAMapItem::pointer node = mAccountStateMap->peekPrevItem(uHash); - if (!node) - return SLE::pointer(); - return boost::make_shared(node->peekSerializer(), node->getTag()); + return node ? node->getTag() : uint256(); } -SLE::pointer Ledger::getPrevSLE(const uint256& uHash, const uint256& uBegin) +uint256 Ledger::getPrevLedgerIndex(const uint256& uHash, const uint256& uBegin) { SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash); if ((!node) || (node->getTag() < uBegin)) - return SLE::pointer(); - return boost::make_shared(node->peekSerializer(), node->getTag()); + return uint256(); + return node->getTag(); } SLE::pointer Ledger::getASNode(LedgerStateParms& parms, const uint256& nodeID, diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index 360ae2d341..e3ea061640 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -16,15 +16,15 @@ int ContinuousLedgerTiming::shouldClose( bool anyTransactions, int previousProposers, // proposers in the last closing int proposersClosed, // proposers who have currently closed this ledgers - int previousSeconds, // seconds the previous ledger took to reach consensus - int currentSeconds) // seconds since the previous ledger closed + int previousMSeconds, // seconds the previous ledger took to reach consensus + int currentMSeconds) // seconds since the previous ledger closed { - assert((previousSeconds > 0) && (previousSeconds < 600)); - assert((currentSeconds >= 0) && (currentSeconds < 600)); + assert((previousMSeconds > 0) && (previousMSeconds < 600000)); + assert((currentMSeconds >= 0) && (currentMSeconds < 600000)); #if 0 Log(lsTRACE) << boost::str(boost::format("CLC::shouldClose Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % - (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentSeconds % previousSeconds); + (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds); #endif if (!anyTransactions) @@ -32,24 +32,26 @@ int ContinuousLedgerTiming::shouldClose( if (proposersClosed > (previousProposers / 4)) // did we miss a transaction? { Log(lsTRACE) << "no transactions, many proposers: now"; - return currentSeconds; + return currentMSeconds; } - if (previousSeconds > (LEDGER_IDLE_INTERVAL + 2)) // the last ledger was very slow to close + if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close { Log(lsTRACE) << "slow to close"; - return previousSeconds - 1; + if (previousMSeconds < 2000) + return previousMSeconds; + return previousMSeconds - 1000; } - return LEDGER_IDLE_INTERVAL; // normal idle + return LEDGER_IDLE_INTERVAL * 1000; // normal idle } - if (previousSeconds == LEDGER_IDLE_INTERVAL) // coming out of idle, close now + if (previousMSeconds == (1000 * LEDGER_IDLE_INTERVAL)) // coming out of idle, close now { Log(lsTRACE) << "leaving idle, close now"; - return currentSeconds; + return currentMSeconds; } Log(lsTRACE) << "close now"; - return currentSeconds; // this ledger should close now + return currentMSeconds; // this ledger should close now } // Returns whether we have a consensus or not. If so, we expect all honest nodes @@ -70,7 +72,7 @@ bool ContinuousLedgerTiming::haveConsensus( if (currentProposers < (previousProposers * 3 / 4)) { // Less than 3/4 of the last ledger's proposers are present, we may need more time - if (currentAgreeTime < (previousAgreeTime + 2)) + if (currentAgreeTime < (previousAgreeTime + LEDGER_MIN_CONSENSUS)) { Log(lsTRACE) << "too fast, not enough proposers"; return false; diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index 2b580a6057..add26558f1 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -7,8 +7,8 @@ // The number of seconds a validation remains current # define LEDGER_MAX_INTERVAL 60 -// The number of seconds we wait minimum to ensure participation -# define LEDGER_MIN_CONSENSUS 2 +// The number of milliseconds we wait minimum to ensure participation +# define LEDGER_MIN_CONSENSUS 2000 // Initial resolution of ledger close time # define LEDGER_TIME_ACCURACY 30 @@ -19,6 +19,9 @@ // How often to decrease resolution # define LEDGER_RES_DECREASE 1 +// How often we check state or change positions (in milliseconds) +# define LEDGER_GRANULARITY 1000 + // Avalanche tuning #define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 085284ff0e..a8de542b8c 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -44,6 +44,24 @@ uint32 NetworkOPs::getCurrentLedgerID() return mLedgerMaster->getCurrentLedger()->getLedgerSeq(); } +// Sterilize transaction through serialization. +void NetworkOPs::submitTransaction(Transaction::pointer tpTrans) +{ + Serializer s; + + tpTrans->getSTransaction()->add(s); + + std::vector vucTransaction = s.getData(); + + SerializerIterator sit(s); + + Transaction::pointer tpTransNew = Transaction::sharedTransaction(s.getData(), true); + + assert(tpTransNew); + + (void) NetworkOPs::processTransaction(tpTransNew); +} + Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, uint32 tgtLedger, Peer* source) { Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true); @@ -280,7 +298,7 @@ RippleState::pointer NetworkOPs::accessRippleState(const uint256& uLedger, const void NetworkOPs::setStateTimer() { // set timer early if ledger is closing - mNetTimer.expires_from_now(boost::posix_time::seconds(1)); + mNetTimer.expires_from_now(boost::posix_time::milliseconds(LEDGER_GRANULARITY)); mNetTimer.async_wait(boost::bind(&NetworkOPs::checkState, this, boost::asio::placeholders::error)); } diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index a037e67366..bf9aede3b9 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -100,7 +100,11 @@ public: uint256 getCurrentLedger() { return mLedgerMaster->getCurrentLedger()->getHash(); } - // transaction operations + // + // Transaction operations + // + void submitTransaction(Transaction::pointer tpTrans); + Transaction::pointer processTransaction(Transaction::pointer transaction, uint32 targetLedger = 0, Peer* source = NULL); Transaction::pointer findTransactionByID(const uint256& transactionID); @@ -182,7 +186,7 @@ public: void setStateTimer(); void newLCL(int proposers, int convergeTime, const uint256& ledgerHash); int getPreviousProposers() { return mLastCloseProposers; } - int getPreviousSeconds() { return mLastCloseConvergeTime; } + int getPreviousConvergeTime() { return mLastCloseConvergeTime; } uint32 getLastCloseNetTime() { return mLastCloseNetTime; } void setLastCloseNetTime(uint32 t) { mLastCloseNetTime = t; } Json::Value getServerInfo(); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 985573e281..1c410b672b 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -463,7 +463,7 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value ¶ms) uint256(), NewcoinAddress()); - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -572,7 +572,7 @@ Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) { uint256(), naMessagePubKey); - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -624,7 +624,7 @@ Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) { uWalletLocator, NewcoinAddress()); - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -822,7 +822,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) saMinimumOffer, vucSignature); - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -897,7 +897,7 @@ Json::Value RPCServer::doOfferCreate(const Json::Value ¶ms) saTakerGets, uExpiration); - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -940,7 +940,7 @@ Json::Value RPCServer::doOfferCancel(const Json::Value ¶ms) 0, // YYY No source tag uSequence); - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -1026,7 +1026,7 @@ Json::Value RPCServer::doPasswordFund(const Json::Value ¶ms) 0, // YYY No source tag naDstAccountID); - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -1112,7 +1112,7 @@ Json::Value RPCServer::doPasswordSet(const Json::Value& params) naRegular0Public.getAccountPublic(), vucGeneratorSig); - (void) mNetOps->processTransaction(trns); + (void) mNetOps->submitTransaction(trns); Json::Value obj(Json::objectValue); @@ -1186,7 +1186,7 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) saLimitAmount, uAcceptRate); - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -1274,7 +1274,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) // Amount reported is positive if current account hold's other account's IOUs. // Amount reported is negative if other account hold's current account's IOUs. jPeer["balance"] = saBalance.getText(); - jPeer["currency"] = saBalance.getCurrencyHuman(); + jPeer["currency"] = saBalance.getHumanCurrency(); jPeer["limit"] = saLimit.getText(); jPeer["limit_peer"] = saLimitPeer.getText(); @@ -1424,7 +1424,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) saDstAmount); // Initial funds in XNS. } - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -1434,9 +1434,9 @@ Json::Value RPCServer::doSend(const Json::Value& params) obj["srcAccountID"] = naSrcAccountID.humanAccountID(); obj["dstAccountID"] = naDstAccountID.humanAccountID(); obj["srcAmount"] = saSrcAmount.getText(); - obj["srcISO"] = saSrcAmount.getCurrencyHuman(); + obj["srcISO"] = saSrcAmount.getHumanCurrency(); obj["dstAmount"] = saDstAmount.getText(); - obj["dstISO"] = saDstAmount.getCurrencyHuman(); + obj["dstISO"] = saDstAmount.getHumanCurrency(); return obj; } @@ -1810,7 +1810,7 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) naNewAccountPublic, vucSignature); - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); @@ -1885,7 +1885,7 @@ Json::Value RPCServer::doWalletClaim(const Json::Value& params) naRegular0Public.getAccountPublic(), vucGeneratorSig); - (void) mNetOps->processTransaction(trns); + (void) mNetOps->submitTransaction(trns); Json::Value obj(Json::objectValue); @@ -1963,7 +1963,7 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) naDstAccountID, saInitialFunds); // Initial funds in XNC. - (void) mNetOps->processTransaction(trans); + (void) mNetOps->submitTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 116cc470bf..738d1858ef 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -170,7 +170,7 @@ SHAMapTreeNode* SHAMap::walkToPointer(const uint256& id) { int branch = inNode->selectBranch(id); const uint256& nextHash = inNode->getChildHash(branch); - if (!nextHash) return NULL; + if (nextHash.isZero()) return NULL; inNode = getNodePointer(inNode->getChildNodeID(branch), nextHash); if (!inNode) throw SHAMapMissingNode(inNode->getChildNodeID(branch), nextHash); @@ -437,7 +437,7 @@ bool SHAMap::delItem(const uint256& id) SHAMapTreeNode::pointer leaf=stack.top(); stack.pop(); - if( !leaf || !leaf->hasItem() || (leaf->peekItem()->getTag()!=id) ) + if (!leaf || !leaf->hasItem() || (leaf->peekItem()->getTag() != id)) return false; SHAMapTreeNode::TNType type=leaf->getType(); @@ -446,19 +446,19 @@ bool SHAMap::delItem(const uint256& id) assert(false); uint256 prevHash; - while(!stack.empty()) + while (!stack.empty()) { SHAMapTreeNode::pointer node=stack.top(); stack.pop(); returnNode(node, true); assert(node->isInner()); - if(!node->setChildHash(node->selectBranch(id), prevHash)) + if (!node->setChildHash(node->selectBranch(id), prevHash)) { assert(false); return true; } - if(!node->isRoot()) + if (!node->isRoot()) { // we may have made this a node with 1 or 0 children int bc=node->getBranchCount(); if(bc==0) @@ -467,7 +467,7 @@ bool SHAMap::delItem(const uint256& id) std::cerr << "delItem makes empty node" << std::endl; #endif prevHash=uint256(); - if(!mTNByID.erase(*node)) + if (!mTNByID.erase(*node)) assert(false); } else if(bc==1) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 3739473a6c..0cd2eedebe 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -271,7 +271,7 @@ public: int64 getSNValue() const; void setSNValue(int64); - std::string getCurrencyHuman() const; + std::string getHumanCurrency() const; bool isNative() const { return mIsNative; } bool isZero() const { return mValue == 0; } @@ -344,6 +344,7 @@ public: static STAmount convertToInternalAmount(uint64 displayAmount, uint64 totalNow, uint64 totalInit, const char* name = NULL); + static std::string createHumanCurrency(const uint160& uCurrency); static STAmount deserialize(SerializerIterator&); static bool currencyFromString(uint160& uDstCurrency, const std::string& sCurrency); diff --git a/src/Transaction.cpp b/src/Transaction.cpp index a1fdfc41bd..9387f7d348 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -70,6 +70,7 @@ Transaction::Transaction( Log(lsINFO) << str(boost::format("Transaction: account: %s") % naSourceAccount.humanAccountID()); Log(lsINFO) << str(boost::format("Transaction: mAccountFrom: %s") % mAccountFrom.humanAccountID()); + mTransaction->setSigningPubKey(mFromPubKey); mTransaction->setSourceAccount(mAccountFrom); mTransaction->setSequence(uSeq); diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 5d5ccbc688..e73333bad7 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -98,7 +98,7 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std STAmount TransactionEngine::rippleHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID) { STAmount saBalance; - SLE::pointer sleRippleState = mLedger->getRippleState(Ledger::getRippleStateIndex(uAccountID, uIssuerID, uCurrency)); + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uAccountID, uIssuerID, uCurrency)); if (sleRippleState) { @@ -117,13 +117,22 @@ STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint16 if (uCurrency.isZero()) { - SLE::pointer sleAccount = mLedger->getAccountRoot(uAccountID); + SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID)); saAmount = sleAccount->getIValueFieldAmount(sfBalance); + + Log(lsINFO) << "accountHolds: stamps: " << saAmount.getText(); } else { saAmount = rippleHolds(uAccountID, uCurrency, uIssuerID); + + Log(lsINFO) << "accountHolds: " + << saAmount.getText() + << " : " + << STAmount::createHumanCurrency(uCurrency) + << "/" + << NewcoinAddress::createHumanAccountID(uIssuerID); } return saAmount; @@ -134,6 +143,12 @@ STAmount TransactionEngine::accountFunds(const uint160& uAccountID, const STAmou { STAmount saFunds; + Log(lsINFO) << "accountFunds: uAccountID=" + << NewcoinAddress::createHumanAccountID(uAccountID); + Log(lsINFO) << "accountFunds: saDefault.isNative()=" << saDefault.isNative(); + Log(lsINFO) << "accountFunds: saDefault.getIssuer()=" + << NewcoinAddress::createHumanAccountID(saDefault.getIssuer()); + if (!saDefault.isNative() && saDefault.getIssuer() == uAccountID) { saFunds = saDefault; @@ -144,7 +159,14 @@ STAmount TransactionEngine::accountFunds(const uint160& uAccountID, const STAmou { saFunds = accountHolds(uAccountID, saDefault.getCurrency(), saDefault.getIssuer()); - Log(lsINFO) << "accountFunds: offer funds: " << saFunds.getText(); + Log(lsINFO) << "accountFunds: offer funds: uAccountID =" + << NewcoinAddress::createHumanAccountID(uAccountID) + << " : " + << saFunds.getText() + << "/" + << saDefault.getHumanCurrency() + << "/" + << NewcoinAddress::createHumanAccountID(saDefault.getIssuer()); } return saFunds; @@ -157,7 +179,7 @@ STAmount TransactionEngine::rippleTransit(const uint160& uSenderID, const uint16 if (uSenderID != uIssuerID && uReceiverID != uIssuerID) { - SLE::pointer sleIssuerAccount = mLedger->getAccountRoot(uIssuerID); + SLE::pointer sleIssuerAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uIssuerID)); uint32 uTransitRate; if (sleIssuerAccount->getIFieldPresent(sfTransferRate)) @@ -189,7 +211,7 @@ STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160& bool bFlipped = uSenderID > uReceiverID; uint256 uIndex = Ledger::getRippleStateIndex(uSenderID, uReceiverID, saAmount.getCurrency()); - SLE::pointer sleRippleState = mLedger->getRippleState(uIndex); + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, uIndex); if (!sleRippleState) { @@ -248,8 +270,8 @@ STAmount TransactionEngine::accountSend(const uint160& uSenderID, const uint160& if (saAmount.isNative()) { - SLE::pointer sleSender = mLedger->getAccountRoot(uSenderID); - SLE::pointer sleReceiver = mLedger->getAccountRoot(uReceiverID); + SLE::pointer sleSender = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uSenderID)); + SLE::pointer sleReceiver = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uReceiverID)); sleSender->setIFieldAmount(sfBalance, sleSender->getIValueFieldAmount(sfBalance) - saAmount); sleReceiver->setIFieldAmount(sfBalance, sleReceiver->getIValueFieldAmount(sfBalance) + saAmount); @@ -294,8 +316,7 @@ TransactionEngineResult TransactionEngine::dirAdd( { SLE::pointer sleNode; STVector256 svIndexes; - LedgerStateParms lspRoot = lepNONE; - SLE::pointer sleRoot = mLedger->getDirNode(lspRoot, uRootIndex); + SLE::pointer sleRoot = entryCache(ltDIR_NODE, uRootIndex); if (!sleRoot) { @@ -312,8 +333,7 @@ TransactionEngineResult TransactionEngine::dirAdd( if (uNodeDir) { // Try adding to last node. - lspRoot = lepNONE; - sleNode = mLedger->getDirNode(lspRoot, Ledger::getDirNodeIndex(uRootIndex, uNodeDir)); + sleNode = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir)); assert(sleNode); } @@ -348,8 +368,7 @@ TransactionEngineResult TransactionEngine::dirAdd( { // Previous node is not root node. - lspRoot = lepNONE; - SLE::pointer slePrevious = mLedger->getDirNode(lspRoot, Ledger::getDirNodeIndex(uRootIndex, uNodeDir-1)); + SLE::pointer slePrevious = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir-1)); slePrevious->setIFieldU64(sfIndexNext, uNodeDir); entryModify(slePrevious); @@ -390,8 +409,7 @@ TransactionEngineResult TransactionEngine::dirDelete( const uint256& uLedgerIndex) { uint64 uNodeCur = uNodeDir; - LedgerStateParms lspNode = lepNONE; - SLE::pointer sleNode = mLedger->getDirNode(lspNode, uNodeCur ? Ledger::getDirNodeIndex(uRootIndex, uNodeCur) : uRootIndex); + SLE::pointer sleNode = entryCache(ltDIR_NODE, uNodeCur ? Ledger::getDirNodeIndex(uRootIndex, uNodeCur) : uRootIndex); assert(sleNode); @@ -458,8 +476,7 @@ TransactionEngineResult TransactionEngine::dirDelete( else { // Have only a root node and a last node. - LedgerStateParms lspLast = lepNONE; - SLE::pointer sleLast = mLedger->getDirNode(lspLast, Ledger::getDirNodeIndex(uRootIndex, uNodeNext)); + SLE::pointer sleLast = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeNext)); assert(sleLast); @@ -483,13 +500,11 @@ TransactionEngineResult TransactionEngine::dirDelete( { // Not root and not last node. Can delete node. - LedgerStateParms lspPrevious = lepNONE; - SLE::pointer slePrevious = mLedger->getDirNode(lspPrevious, uNodePrevious ? Ledger::getDirNodeIndex(uRootIndex, uNodePrevious) : uRootIndex); + SLE::pointer slePrevious = entryCache(ltDIR_NODE, uNodePrevious ? Ledger::getDirNodeIndex(uRootIndex, uNodePrevious) : uRootIndex); assert(slePrevious); - LedgerStateParms lspNext = lepNONE; - SLE::pointer sleNext = mLedger->getDirNode(lspNext, uNodeNext ? Ledger::getDirNodeIndex(uRootIndex, uNodeNext) : uRootIndex); + SLE::pointer sleNext = entryCache(ltDIR_NODE, uNodeNext ? Ledger::getDirNodeIndex(uRootIndex, uNodeNext) : uRootIndex); assert(slePrevious); assert(sleNext); @@ -527,8 +542,7 @@ TransactionEngineResult TransactionEngine::dirDelete( else { // Last and only node besides the root. - LedgerStateParms lspRoot = lepNONE; - SLE::pointer sleRoot = mLedger->getDirNode(lspRoot, uRootIndex); + SLE::pointer sleRoot = entryCache(ltDIR_NODE, uRootIndex); assert(sleRoot); @@ -556,8 +570,7 @@ TransactionEngineResult TransactionEngine::dirDelete( // <-- uEntryNode void TransactionEngine::dirFirst(const uint256& uRootIndex, uint256& uEntryIndex, uint64& uEntryNode) { - LedgerStateParms lspRoot = lepNONE; - SLE::pointer sleRoot = mLedger->getDirNode(lspRoot, uRootIndex); + SLE::pointer sleRoot = entryCache(ltDIR_NODE, uRootIndex); STVector256 svIndexes = sleRoot->getIFieldV256(sfIndexes); std::vector& vuiIndexes = svIndexes.peekValue(); @@ -566,8 +579,7 @@ void TransactionEngine::dirFirst(const uint256& uRootIndex, uint256& uEntryIndex { uEntryNode = sleRoot->getIFieldU64(sfIndexNext); - LedgerStateParms lspNext = lepNONE; - SLE::pointer sleNext = mLedger->getDirNode(lspNext, Ledger::getDirNodeIndex(uRootIndex, uEntryNode)); + SLE::pointer sleNext = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uEntryNode)); uEntryIndex = sleNext->getIFieldV256(sfIndexes).peekValue()[0]; } else @@ -600,8 +612,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac // Create generator. uint160 hGeneratorID = naAccountPublic.getAccountID(); - LedgerStateParms qry = lepNONE; - SLE::pointer sleGen = mLedger->getGenerator(qry, hGeneratorID); + SLE::pointer sleGen = entryCache(ltGENERATOR_MAP, Ledger::getGeneratorIndex(hGeneratorID)); if (!sleGen) { // Create the generator. @@ -630,6 +641,37 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac return terSUCCESS; } +SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint256& uIndex) +{ + SLE::pointer sleEntry; + + if (!uIndex.isZero()) + { + entryMap::const_iterator it = mEntries.find(uIndex); + + switch (it == mEntries.end() ? taaNONE : it->second.second) + { + case taaNONE: + sleEntry = mLedger->getSLE(uIndex); + if (sleEntry) + mEntries[uIndex] = std::make_pair(sleEntry, taaCACHED); // Add to cache. + break; + + case taaCREATE: + case taaCACHED: + case taaMODIFY: + sleEntry = it->second.first; // Get from cache. + break; + + case taaDELETE: + assert(false); // Unexpected case. + break; + } + } + + return sleEntry; +} + SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType, const uint256& uIndex) { assert(!uIndex.isZero()); @@ -653,16 +695,17 @@ void TransactionEngine::entryDelete(SLE::pointer sleEntry) switch (it == mEntries.end() ? taaNONE : it->second.second) { case taaCREATE: - assert(false); // Unexpected case. + assert(false); // Unexpected case. break; + case taaCACHED: case taaMODIFY: case taaNONE: mEntries[uIndex] = std::make_pair(sleEntry, taaDELETE); // Upgrade. break; case taaDELETE: - nothing(); // No change. + nothing(); // No change. break; } } @@ -676,16 +719,17 @@ void TransactionEngine::entryModify(SLE::pointer sleEntry) switch (it == mEntries.end() ? taaNONE : it->second.second) { case taaDELETE: - assert(false); // Unexpected case. + assert(false); // Unexpected case. break; + case taaCACHED: case taaNONE: mEntries[uIndex] = std::make_pair(sleEntry, taaMODIFY); // Upgrade. break; case taaCREATE: case taaMODIFY: - nothing(); // No change. + nothing(); // No change. break; } } @@ -703,6 +747,9 @@ void TransactionEngine::txnWrite() assert(false); break; + case taaCACHED: + break; + case taaCREATE: { Log(lsINFO) << "applyTransaction: taaCREATE: " << sleEntry->getText(); @@ -733,6 +780,21 @@ void TransactionEngine::txnWrite() } } +// This is for when a transaction fails from the issuer's point of view and the current changes need to be cleared so other +// actions can be applied to the ledger. +void TransactionEngine::entryReset(const SerializedTransaction& txn) +{ + mEntries.clear(); // Lose old SLE modifications. + mTxnAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(mTxnAccountID)); // Get new SLE. + + entryModify(mTxnAccount); + + STAmount saPaid = txn.getTransactionFee(); + STAmount saSrcBalance = mTxnAccount->getIValueFieldAmount(sfBalance); + + mTxnAccount->setIFieldAmount(sfBalance, saSrcBalance - saPaid); +} + TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn, TransactionEngineParams params) { @@ -811,8 +873,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttNICKNAME_SET: { - LedgerStateParms qry = lepNONE; - SLE::pointer sleNickname = mLedger->getNickname(qry, txn.getITFieldH256(sfNickname)); + SLE::pointer sleNickname = entryCache(ltNICKNAME, txn.getITFieldH256(sfNickname)); if (!sleNickname) saCost = theConfig.FEE_NICKNAME_CREATE; @@ -880,7 +941,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran boost::recursive_mutex::scoped_lock sl(mLedger->mLock); - mTxnAccount = mLedger->getAccountRoot(mTxnAccountID); + mTxnAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(mTxnAccountID)); // Find source account // If are only forwarding, due to resource limitations, we might verifying only some transactions, this would be probablistic. @@ -1118,28 +1179,6 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman; -#if 0 - if (terSUCCESS == terResult) - { - // Transaction failed. Process possible unfunded offers. - // XXX Make sure this stop changed cached entries: - mEntries.clear(); // Drop old modifications. - - BOOST_FOREACH(const uint256& uOfferIndex, mUnfunded) - { - SLE::pointer sleOffer = mLedger->getOffer(uOfferIndex); - uint160 uOfferID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saOfferFunds = sleOffer->getIValueFieldAmount(sfTakerGets); - - if (!accountFunds(uOfferID, saOfferFunds).isPositive()) - { - offerDelete(sleOffer, uOfferIndex, uOfferID); - bWrite = true; - } - } - } -#endif - if (terSUCCESS == terResult) { txnWrite(); @@ -1263,7 +1302,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti return tenDST_IS_SRC; } - SLE::pointer sleDst = mLedger->getAccountRoot(uDstAccountID); + SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); if (!sleDst) { Log(lsINFO) << "doCreditSet: Delay transaction: Destination account does not exist."; @@ -1279,7 +1318,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti bool bAddIndex = false; bool bDelIndex = false; - SLE::pointer sleRippleState = mLedger->getRippleState(mTxnAccountID, uDstAccountID, uCurrency); + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrency)); if (sleRippleState) { // A line exists in one or more directions. @@ -1366,8 +1405,7 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac bool bMinOffer = txn.getITFieldPresent(sfMinimumOffer); STAmount saMinOffer = bMinOffer ? txn.getITFieldAmount(sfAmount) : STAmount(); - LedgerStateParms qry = lepNONE; - SLE::pointer sleNickname = mLedger->getNickname(qry, uNickname); + SLE::pointer sleNickname = entryCache(ltNICKNAME, uNickname); if (sleNickname) { @@ -1412,7 +1450,7 @@ TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransa uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); SLE::pointer sleDst = mTxnAccountID == uDstAccountID ? mTxnAccount - : mLedger->getAccountRoot(uDstAccountID); + : entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); if (!sleDst) { // Destination account does not exist. @@ -1622,7 +1660,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } else if (!saDstAmount.isPositive()) { - Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getCurrencyHuman() << " " << saDstAmount.getText(); + Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getHumanCurrency() << " " << saDstAmount.getText(); return tenBAD_AMOUNT; } @@ -1637,7 +1675,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return tenREDUNDANT; } - SLE::pointer sleDst = mLedger->getAccountRoot(uDstAccountID); + SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); if (!sleDst) { // Destination account does not exist. @@ -1703,7 +1741,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Try direct ripple first. if (!bNoRippleDirect && mTxnAccountID != uDstAccountID && uSrcCurrency == uDstCurrency) { - SLE::pointer sleRippleState = mLedger->getRippleState(mTxnAccountID, uDstAccountID, uDstCurrency); + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uDstCurrency)); if (sleRippleState) { @@ -1804,6 +1842,28 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } #endif +#if 0 +// XXX Or additionally queue unfundeds for removal on failure. + if (terSUCCESS == terResult) + { + // Transaction failed. Process possible unfunded offers. + entryReset(txn); + + BOOST_FOREACH(const uint256& uOfferIndex, mUnfunded) + { + SLE::pointer sleOffer = mLedger->getOffer(uOfferIndex); + uint160 uOfferID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + STAmount saOfferFunds = sleOffer->getIValueFieldAmount(sfTakerGets); + + if (!accountFunds(uOfferID, saOfferFunds).isPositive()) + { + offerDelete(sleOffer, uOfferIndex, uOfferID); + bWrite = true; + } + } + } +#endif + Log(lsINFO) << "doPayment: Delay transaction: No ripple paths could be satisfied."; return terBAD_RIPPLE; @@ -1826,7 +1886,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti return tenBAD_ADD_AUTH; } - SLE::pointer sleDst = mLedger->getAccountRoot(uDstAccountID); + SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); if (sleDst) { @@ -1879,8 +1939,6 @@ TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction // <-- saTakerGot: What taker got not including fees. To reduce an offer. // <-- terResult: terSUCCESS or terNO_ACCOUNT // Note: All SLE modifications must always occur even on failure. -// XXX The tricky part - make sure all adjusted balances should stick for the errors found or make an undo. -// XXX Or additionally queue unfundeds for removal on failure. TransactionEngineResult TransactionEngine::takeOffers( bool bPassive, const uint256& uBookBase, @@ -1917,7 +1975,7 @@ TransactionEngineResult TransactionEngine::takeOffers( { // Taker has needs. - sleOfferDir = mLedger->getNextSLE(uTipIndex, uBookEnd); + sleOfferDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uTipIndex, uBookEnd)); if (sleOfferDir) { Log(lsINFO) << "takeOffers: possible counter offer found"; @@ -1951,7 +2009,7 @@ TransactionEngineResult TransactionEngine::takeOffers( dirFirst(uTipIndex, uOfferIndex, uOfferNode); - SLE::pointer sleOffer = mLedger->getSLE(uOfferIndex); + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); Log(lsINFO) << "takeOffers: considering offer : " << sleOffer->getJson(0); @@ -1978,9 +2036,9 @@ TransactionEngineResult TransactionEngine::takeOffers( else { // Get offer funds available. - uint160 uPaysIssuerID = sleOffer->getIValueFieldAccount(sfPaysIssuer).getAccountID(); - saOfferPays.setIssuer(uPaysIssuerID); + if (sleOffer->getIFieldPresent(sfPaysIssuer)) + saOfferPays.setIssuer(sleOffer->getIValueFieldAccount(sfPaysIssuer).getAccountID()); STAmount saOfferFunds = accountFunds(uOfferOwnerID, saOfferPays); STAmount saTakerFunds = accountFunds(uTakerAccountID, saTakerPays); @@ -2050,12 +2108,17 @@ TransactionEngineResult TransactionEngine::takeOffers( TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransaction& txn) { +Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); uint32 txFlags = txn.getFlags(); bool bPassive = !!(txFlags & tfPassive); - STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); - STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); uint160 uPaysIssuerID = txn.getITFieldAccount(sfPaysIssuer); uint160 uGetsIssuerID = txn.getITFieldAccount(sfGetsIssuer); + STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); + saTakerPays.setIssuer(uPaysIssuerID); +Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getJson(0); + STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); + saTakerGets.setIssuer(uGetsIssuerID); +Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getJson(0); uint32 uExpiration = txn.getITFieldU32(sfExpiration); bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); uint32 uSequence = txn.getSequence(); @@ -2110,7 +2173,7 @@ TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransac terResult = tenBAD_ISSUER; } - else if (!accountFunds(mTxnAccountID, saTakerPays).isPositive()) + else if (!accountFunds(mTxnAccountID, saTakerGets).isPositive()) { Log(lsWARNING) << "doOfferCreate: delay: offers must be funded"; @@ -2119,7 +2182,7 @@ TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransac if (terSUCCESS == terResult && !saTakerPays.isNative()) { - SLE::pointer sleTakerPays = mLedger->getAccountRoot(uPaysIssuerID); + SLE::pointer sleTakerPays = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uPaysIssuerID)); if (!sleTakerPays) { @@ -2137,9 +2200,9 @@ TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransac Log(lsINFO) << str(boost::format("doOfferCreate: take against book: %s : %s/%s -> %s/%s") % uTakeBookBase.ToString() - % saTakerGets.getCurrencyHuman() + % saTakerGets.getHumanCurrency() % NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()) - % saTakerPays.getCurrencyHuman() + % saTakerPays.getHumanCurrency() % NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer())); // Take using the parameters of the offer. @@ -2155,6 +2218,8 @@ TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransac ); Log(lsWARNING) << "doOfferCreate: takeOffers=" << terResult; + Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferPaid=" << saOfferPaid.getText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferGot=" << saOfferGot.getText(); if (terSUCCESS == terResult) { @@ -2163,14 +2228,18 @@ TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransac } } - // Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getText(); - // Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getJson(0); + Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()); + Log(lsWARNING) << "doOfferCreate: takeOffers: mTxnAccountID=" << NewcoinAddress::createHumanAccountID(mTxnAccountID); + Log(lsWARNING) << "doOfferCreate: takeOffers: funds=" << accountFunds(mTxnAccountID, saTakerGets).getText(); + // Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); if (terSUCCESS == terResult - && !saTakerGets.isZero() // Still offering something. && !saTakerPays.isZero() // Still wanting something. + && !saTakerGets.isZero() // Still offering something. && accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. { // We need to place the remainder of the offer into its order book. @@ -2184,9 +2253,9 @@ TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransac Log(lsINFO) << str(boost::format("doOfferCreate: adding to book: %s : %s/%s -> %s/%s") % uBookBase.ToString() - % saTakerPays.getCurrencyHuman() + % saTakerPays.getHumanCurrency() % NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer()) - % saTakerGets.getCurrencyHuman() + % saTakerGets.getHumanCurrency() % NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer())); uDirectory = Ledger::getQualityIndex(uBookBase, uRate); // Use original rate. @@ -2201,8 +2270,8 @@ TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransac // Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); // Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative(); // Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative(); - // Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getCurrencyHuman(); - // Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getCurrencyHuman(); + // Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency(); + // Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency(); sleOffer->setIFieldAccount(sfAccount, mTxnAccountID); sleOffer->setIFieldU32(sfSequence, uSequence); @@ -2234,7 +2303,7 @@ TransactionEngineResult TransactionEngine::doOfferCancel(const SerializedTransac TransactionEngineResult terResult; uint32 uSequence = txn.getITFieldU32(sfOfferSequence); uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); - SLE::pointer sleOffer = mLedger->getOffer(uOfferIndex); + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); if (sleOffer) { diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 2f8e9db3fe..b84c4a0102 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -93,9 +93,10 @@ enum TransactionEngineParams enum TransactionAccountAction { taaNONE, - taaCREATE, - taaMODIFY, - taaDELETE, + taaCACHED, // Unmodified. + taaMODIFY, // Modifed, must have previously been taaCACHED. + taaDELETE, // Delete, must have previously been taaDELETE or taaMODIFY. + taaCREATE, // Newly created. }; typedef std::pair AffectedAccount; @@ -167,18 +168,21 @@ protected: boost::unordered_set mUnfunded; // Indexes that were found unfunded. SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); + SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex); void entryDelete(SLE::pointer sleEntry); void entryModify(SLE::pointer sleEntry); - STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID); - STAmount rippleTransit(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount); - STAmount rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); + void entryReset(const SerializedTransaction& txn); - STAmount accountHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID); - STAmount accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); - STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault); + STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID); + STAmount rippleTransit(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount); + STAmount rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); - void txnWrite(); + STAmount accountHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID); + STAmount accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); + STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault); + + void txnWrite(); TransactionEngineResult offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID);