Merge branch 'master' of github.com:jedmccaleb/NewCoin

This commit is contained in:
jed
2012-07-18 17:39:06 -07:00
18 changed files with 361 additions and 241 deletions

View File

@@ -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");
}

View File

@@ -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<std::string, std::string> mapHeaders;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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, <end
SLE::pointer getPrevSLE(const uint256& uHash); // last node <hash
SLE::pointer getPrevSLE(const uint256& uHash, const uint256& uBegin); // last 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, <end
uint256 getPrevLedgerIndex(const uint256& uHash); // last node <hash
uint256 getPrevLedgerIndex(const uint256& uHash, const uint256& uBegin); // last node <hash, >begin
// index calculation functions
static uint256 getAccountRootIndex(const uint160& uAccountID);

View File

@@ -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<uint256> found;
@@ -248,11 +248,12 @@ void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
if (mValidating)
mOurPosition = boost::make_shared<LedgerProposal>
(mValSeed, initialLedger->getParentHash(), txSet, mCloseTime);
(mValSeed, initialLedger.getParentHash(), txSet, mCloseTime);
else
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger->getParentHash(), txSet, mCloseTime);
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger.getParentHash(), txSet, mCloseTime);
mapComplete(txSet, initialSet, false);
if (mProposing) propose(std::vector<uint256>(), std::vector<uint256>());
if (mProposing)
propose(std::vector<uint256>(), std::vector<uint256>());
}
void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2)
@@ -339,18 +340,18 @@ void LedgerConsensus::adjustCount(SHAMap::pointer map, const std::vector<uint160
}
}
void LedgerConsensus::statusChange(newcoin::NodeEvent event, Ledger::pointer ledger)
void LedgerConsensus::statusChange(newcoin::NodeEvent event, Ledger& ledger)
{ // Send a node status change message to our peers
newcoin::TMStatusChange s;
if (!mHaveCorrectLCL)
s.set_newevent(newcoin::neLOST_SYNC);
else
s.set_newevent(event);
s.set_ledgerseq(ledger->getLedgerSeq());
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<PackedMessage>(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<uint256, SHAMap::pointer>::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<SerializedTransaction>(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<SerializedTransaction>(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<SerializedTransaction>(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();

View File

@@ -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<uint160, LedgerProposal::pointer> 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();

View File

@@ -53,52 +53,44 @@ SLE::pointer Ledger::getSLE(const uint256& uHash)
return boost::make_shared<SLE>(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<SLE>(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<SLE>(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<SLE>(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<SLE>(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<SLE>(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<SLE>(node->peekSerializer(), node->getTag());
return uint256();
return node->getTag();
}
SLE::pointer Ledger::getASNode(LedgerStateParms& parms, const uint256& nodeID,

View File

@@ -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;

View File

@@ -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

View File

@@ -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<unsigned char> 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));
}

View File

@@ -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();

View File

@@ -463,7 +463,7 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value &params)
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 &params)
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 &params)
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 &params)
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 &params)
// 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();

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<uint256>& 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)
{

View File

@@ -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<TransactionAccountAction, SerializedLedgerEntry::pointer> AffectedAccount;
@@ -167,18 +168,21 @@ protected:
boost::unordered_set<uint256> 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);