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

This commit is contained in:
jed
2012-10-11 09:19:19 -07:00
19 changed files with 302 additions and 119 deletions

BIN
LICENSE

Binary file not shown.

View File

@@ -208,17 +208,25 @@ void Application::startNewLedger()
void Application::loadOldLedger()
{
Ledger::pointer lastLedger = Ledger::getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;");
if (!lastLedger)
try
{
std::cout << "No Ledger found?" << std::endl;
Ledger::pointer lastLedger = Ledger::getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;");
if (!lastLedger)
{
std::cout << "No Ledger found?" << std::endl;
exit(-1);
}
lastLedger->setClosed();
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*lastLedger));
mMasterLedger.switchLedgers(lastLedger, openLedger);
mNetOps.setLastCloseTime(lastLedger->getCloseTimeNC());
}
catch (SHAMapMissingNode& mn)
{
Log(lsFATAL) << "Cannot load ledger. " << mn;
exit(-1);
}
lastLedger->setClosed();
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*lastLedger));
mMasterLedger.switchLedgers(lastLedger, openLedger);
mNetOps.setLastCloseTime(lastLedger->getCloseTimeNC());
}
// vim:ts=4

View File

@@ -24,7 +24,8 @@ SETUP_LOG();
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1),
mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap())
mTransactionMap(boost::make_shared<SHAMap>(smtTRANSACTION)),
mAccountStateMap(boost::make_shared<SHAMap>(smtSTATE))
{
// special case: put coins in root account
AccountState::pointer startAccount = boost::make_shared<AccountState>(masterID);
@@ -38,13 +39,21 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s
}
Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution, uint32 ledgerSeq,bool isMutable)
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution, uint32 ledgerSeq)
: mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash), mTotCoins(totCoins),
mLedgerSeq(ledgerSeq), mCloseTime(closeTime), mParentCloseTime(parentCloseTime),
mCloseResolution(closeResolution), mCloseFlags(closeFlags),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(isMutable)
{
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true),
mTransactionMap(boost::make_shared<SHAMap>(smtTRANSACTION, transHash)),
mAccountStateMap(boost::make_shared<SHAMap>(smtSTATE, accountHash))
{ // This will throw if the root nodes are not available locally
updateHash();
if (mTransHash.isNonZero())
mTransactionMap->fetchRoot(mTransHash);
if (mAccountHash.isNonZero())
mAccountStateMap->fetchRoot(mAccountHash);
mTransactionMap->setImmutable();
mAccountStateMap->setImmutable();
}
Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins), mLedgerSeq(ledger.mLedgerSeq),
@@ -62,7 +71,8 @@ Ledger::Ledger(bool /* dummy */, Ledger& prevLedger) :
mTotCoins(prevLedger.mTotCoins), mLedgerSeq(prevLedger.mLedgerSeq + 1),
mParentCloseTime(prevLedger.mCloseTime), mCloseResolution(prevLedger.mCloseResolution),
mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger.mAccountStateMap->snapShot(true))
mTransactionMap(boost::make_shared<SHAMap>(smtTRANSACTION)),
mAccountStateMap(prevLedger.mAccountStateMap->snapShot(true))
{ // Create a new ledger that follows this one
prevLedger.updateHash();
mParentHash = prevLedger.getHash();
@@ -123,8 +133,8 @@ void Ledger::setRaw(const Serializer &s)
updateHash();
if(mValidHash)
{
mTransactionMap = boost::make_shared<SHAMap>(mTransHash);
mAccountStateMap = boost::make_shared<SHAMap>(mAccountHash);
mTransactionMap = boost::make_shared<SHAMap>(smtTRANSACTION, mTransHash);
mAccountStateMap = boost::make_shared<SHAMap>(smtSTATE, mAccountHash);
}
}
@@ -328,10 +338,11 @@ void Ledger::saveAcceptedLedger(Ledger::ref ledger)
ledger->mAccountHash.GetHex() % ledger->mTransHash.GetHex()));
// write out dirty nodes
while(ledger->mTransactionMap->flushDirty(256, hotTRANSACTION_NODE, ledger->mLedgerSeq))
{ ; }
while(ledger->mAccountStateMap->flushDirty(256, hotACCOUNT_NODE, ledger->mLedgerSeq))
{ ; }
int fc;
while ((fc = ledger->mTransactionMap->flushDirty(256, hotTRANSACTION_NODE, ledger->mLedgerSeq)) > 0)
{ cLog(lsINFO) << "Flushed " << fc << " dirty transaction nodes"; }
while ((fc = ledger->mAccountStateMap->flushDirty(256, hotACCOUNT_NODE, ledger->mLedgerSeq)) > 0)
{ cLog(lsINFO) << "Flushed " << fc << " dirty state nodes"; }
ledger->disarmDirty();
SHAMap& txSet = *ledger->peekTransactionMap();
@@ -425,7 +436,7 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
}
Ledger::pointer ret = Ledger::pointer(new Ledger(prevHash, transHash, accountHash, totCoins,
closingTime, prevClosingTime, closeFlags, closeResolution, ledgerSeq, true));
closingTime, prevClosingTime, closeFlags, closeResolution, ledgerSeq));
if (ret->getHash() != ledgerHash)
{
if (sLog(lsERROR))

View File

@@ -93,7 +93,7 @@ public:
Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution,
uint32 ledgerSeq, bool immutable); // used for database ledgers
uint32 ledgerSeq); // used for database ledgers
Ledger(const std::vector<unsigned char>& rawLedger);

View File

@@ -96,6 +96,45 @@ LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE
#endif
}
bool LedgerAcquire::tryLocal()
{ // return value: true = no more work to do
HashedObject::pointer node = theApp->getHashedObjectStore().retrieve(mHash);
if (!node)
return false;
mLedger = boost::make_shared<Ledger>(strCopy(node->getData()));
assert(mLedger->getHash() == mHash);
mHaveBase = true;
if (!mLedger->getTransHash())
mHaveTransactions = true;
else
{
try
{
mLedger->peekTransactionMap()->fetchRoot(mLedger->getTransHash());
}
catch (SHAMapMissingNode&)
{
}
}
if (!mLedger->getAccountHash())
mHaveState = true;
else
{
try
{
mLedger->peekAccountStateMap()->fetchRoot(mLedger->getAccountHash());
}
catch (SHAMapMissingNode&)
{
}
}
return mHaveTransactions && mHaveState;
}
void LedgerAcquire::onTimer()
{
if (getTimeouts() > 6)
@@ -124,7 +163,7 @@ void LedgerAcquire::done()
setComplete();
mLock.lock();
triggers = mOnComplete;
mOnComplete.empty();
mOnComplete.clear();
mLock.unlock();
if (mLedger)

View File

@@ -94,6 +94,7 @@ public:
bool takeAsNode(const std::list<SHAMapNode>& IDs, const std::list<std::vector<unsigned char> >& data);
bool takeAsRootNode(const std::vector<unsigned char>& data);
void trigger(Peer::ref, bool timer);
bool tryLocal();
};
class LedgerAcquireMaster

View File

@@ -27,7 +27,7 @@ SETUP_LOG();
TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false)
{
mMap = boost::make_shared<SHAMap>(hash);
mMap = boost::make_shared<SHAMap>(smtTRANSACTION, hash);
}
void TransactionAcquire::done()
@@ -759,7 +759,7 @@ SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool do
{
if (!hash)
{
SHAMap::pointer empty = boost::make_shared<SHAMap>();
SHAMap::pointer empty = boost::make_shared<SHAMap>(smtTRANSACTION);
mapComplete(hash, empty, false);
return empty;
}

View File

@@ -585,7 +585,6 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerLis
if (!mAcquiringLedger->isComplete())
{ // add more peers
int count = 0;
std::vector<Peer::pointer> peers=theApp->getConnectionPool().getPeerVector();
BOOST_FOREACH(Peer::ref it, peerList)
{
if (it->getClosedLedgerHash() == closedLedger)

View File

@@ -69,6 +69,6 @@ CKey::pointer PubKeyCache::store(const NewcoinAddress& id, const CKey::pointer&
void PubKeyCache::clear()
{
boost::mutex::scoped_lock sl(mLock);
mCache.empty();
mCache.clear();
}
// vim:ts=4

View File

@@ -2711,8 +2711,10 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params
try {
return (this->*(commandsA[i].dfpFunc))(params);
}
catch (...)
catch (std::exception& e)
{
cLog(lsINFO) << "Caught throw: " << e.what();
return RPCError(rpcINTERNAL);
}
}

View File

@@ -478,6 +478,8 @@ TER RippleCalc::calcNodeDeliverFwd(
const uint160& uPrvIssuerID = pnPrv.uIssuerID;
const STAmount& saTransferRate = pnPrv.saTransferRate;
STAmount& saCurDeliverAct = pnCur.saFwdDeliver;
saInAct = 0;
saInFees = 0;
@@ -594,8 +596,11 @@ TER RippleCalc::calcNodeDeliverFwd(
bEntryAdvance = true;
}
saInAct += saInPassAct;
saInFees += saInPassFees;
saInAct += saInPassAct;
saInFees += saInPassFees;
// Adjust amount available to next node.
saCurDeliverAct += saOutPassAct;
}
}
@@ -856,18 +861,19 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p
const STAmount& saCurDeliverReq = pnCur.saRevDeliver;
STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer());
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurRedeemReq=%s saNxtOwed=%s")
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurRedeemReq=%s saCurIssueReq=%s saNxtOwed=%s")
% saPrvRedeemReq.getFullText()
% saPrvIssueReq.getFullText()
% saCurRedeemReq.getFullText()
% saCurIssueReq.getFullText()
% saNxtOwed.getFullText());
cLog(lsINFO) << pspCur->getJson();
assert(!saCurRedeemReq || (-saNxtOwed) >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand.
assert(!saCurIssueReq // If not issuing, fine.
|| !saNxtOwed.isNegative() // Not hold next IOUs: owed is >= 0
|| saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed.
|| !saNxtOwed.isNegative() // saNxtOwed >= 0: Sender not holding next IOUs, saNxtOwed < 0: Sender holding next IOUs.
|| -saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed.
if (bPrvAccount && bNxtAccount)
{
@@ -882,8 +888,8 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p
// account --> ACCOUNT --> $
// Overall deliverable.
const STAmount& saCurWantedReq = bPrvAccount
? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit.
: pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs.
? std::min(pspCur->saOutReq-pspCur->saOutAct, saPrvLimit+saPrvOwed) // If previous is an account, limit.
: pspCur->saOutReq-pspCur->saOutAct; // Previous is an offer, no limit: redeem own IOUs.
STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer());
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $ : saCurWantedReq=%s")
@@ -1017,8 +1023,8 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p
{
// offer --> ACCOUNT --> $
const STAmount& saCurWantedReq = bPrvAccount
? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit.
: pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs.
? std::min(pspCur->saOutReq-pspCur->saOutAct, saPrvLimit+saPrvOwed) // If previous is an account, limit.
: pspCur->saOutReq-pspCur->saOutAct; // Previous is an offer, no limit: redeem own IOUs.
STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer());
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $ : saCurWantedReq=%s")
@@ -1086,10 +1092,10 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p
return terResult;
}
// Perfrom balance adjustments between previous and current node.
// Perform balance adjustments between previous and current node.
// - The previous node: specifies what to push through to current.
// - All of previous output is consumed.
// Then, compute output for next node.
// Then, compute current node's output for next node.
// - Current node: specify what to push through to next.
// - Output to next node is computed as input minus quality or transfer fee.
TER RippleCalc::calcNodeAccountFwd(
@@ -1159,16 +1165,12 @@ TER RippleCalc::calcNodeAccountFwd(
// ^ --> ACCOUNT --> account
// First node, calculate amount to send.
// XXX Use stamp/ripple balance
PaymentNode& pnCur = pspCur->vpnNodes[uIndex];
// XXX Limit by stamp/ripple balance
const STAmount& saCurRedeemReq = pnCur.saRevRedeem;
STAmount& saCurRedeemAct = pnCur.saFwdRedeem;
const STAmount& saCurIssueReq = pnCur.saRevIssue;
STAmount& saCurIssueAct = pnCur.saFwdIssue;
const STAmount& saCurSendMaxReq = pspCur->saInReq; // Negative for no limit, doing a calculation.
STAmount& saCurSendMaxAct = pspCur->saInAct; // Report to user how much this sends.
const STAmount& saCurSendMaxReq = pspCur->saInReq.isNegative()
? pspCur->saInReq // Negative for no limit, doing a calculation.
: pspCur->saInReq-pspCur->saInAct; // request - done.
STAmount& saCurSendMaxPass = pspCur->saInPass; // Report how much pass sends.
if (saCurRedeemReq)
{
@@ -1179,28 +1181,35 @@ TER RippleCalc::calcNodeAccountFwd(
}
else
{
saCurRedeemAct = STAmount(saCurRedeemReq);
}
saCurSendMaxAct = saCurRedeemAct;
// No redeeming.
if (saCurIssueReq && (saCurSendMaxReq.isNegative() || saCurSendMaxReq != saCurRedeemAct))
saCurRedeemAct = saCurRedeemReq;
}
saCurSendMaxPass = saCurRedeemAct;
if (saCurIssueReq && (saCurSendMaxReq.isNegative() || saCurSendMaxPass != saCurSendMaxReq))
{
// Issue requested and not over budget.
// Issue requested and pass does not meet max.
saCurIssueAct = saCurSendMaxReq.isNegative()
? saCurIssueReq
: std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq);
}
else
{
// No issuing.
saCurIssueAct = STAmount(saCurIssueReq);
}
saCurSendMaxAct += saCurIssueAct;
saCurSendMaxPass += saCurIssueAct;
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s")
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saInReq=%s saInAct=%s saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s saCurSendMaxPass=%s")
% pspCur->saInReq.getFullText()
% pspCur->saInAct.getFullText()
% saCurSendMaxReq.getFullText()
% saCurRedeemAct.getFullText()
% saCurIssueReq.getFullText()
% saCurIssueAct.getFullText());
% saCurIssueAct.getFullText()
% saCurSendMaxPass.getFullText());
}
else if (uIndex == uLast)
{
@@ -1213,7 +1222,7 @@ TER RippleCalc::calcNodeAccountFwd(
// Last node. Accept all funds. Calculate amount actually to credit.
STAmount& saCurReceive = pspCur->saOutAct;
STAmount& saCurReceive = pspCur->saOutPass;
STAmount saIssueCrd = uQualityIn >= QUALITY_ONE
? saPrvIssueReq // No fee.
@@ -1299,12 +1308,12 @@ TER RippleCalc::calcNodeAccountFwd(
if (uIndex == uLast)
{
// offer --> ACCOUNT --> $
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $"));
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $ : %s") % saPrvDeliverReq.getFullText());
STAmount& saCurReceive = pspCur->saOutAct;
STAmount& saCurReceive = pspCur->saOutPass;
// Amount to credit.
saCurReceive = saPrvDeliverAct;
saCurReceive = saPrvDeliverReq;
// No income balance adjustments necessary. The paying side inside the offer paid to this account.
}
@@ -1359,8 +1368,8 @@ bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::poi
return lhs->uQuality > rhs->uQuality; // Bigger is worse.
// Best quanity is second rank.
if (lhs->saOutAct != rhs->saOutAct)
return lhs->saOutAct < rhs->saOutAct; // Smaller is worse.
if (lhs->saOutPass != rhs->saOutPass)
return lhs->saOutPass < rhs->saOutPass; // Smaller is worse.
// Path index is third rank.
return lhs->mIndex > rhs->mIndex; // Bigger is worse.
@@ -1549,7 +1558,11 @@ PathState::PathState(
const STAmount& saSend,
const STAmount& saSendMax
)
: mLedger(lesSource.getLedgerRef()), mIndex(iIndex), uQuality(0)
: mLedger(lesSource.getLedgerRef()),
mIndex(iIndex),
uQuality(1), // Mark path as active.
saInReq(saSendMax),
saOutReq(saSend)
{
const uint160 uInCurrencyID = saSendMax.getCurrency();
const uint160 uOutCurrencyID = saSend.getCurrency();
@@ -1558,9 +1571,6 @@ PathState::PathState(
lesEntries = lesSource.duplicate();
saInReq = saSendMax;
saOutReq = saSend;
// Push sending node.
terStatus = pushNode(
STPathElement::typeAccount
@@ -1684,12 +1694,18 @@ Json::Value PathState::getJson() const
if (saInAct)
jvPathState["in_act"] = saInAct.getJson(0);
if (saInPass)
jvPathState["in_pass"] = saInPass.getJson(0);
if (saOutReq)
jvPathState["out_req"] = saOutReq.getJson(0);
if (saOutAct)
jvPathState["out_act"] = saOutAct.getJson(0);
if (saOutPass)
jvPathState["out_pass"] = saOutPass.getJson(0);
if (uQuality)
jvPathState["uQuality"] = Json::Value::UInt(uQuality);
@@ -1775,13 +1791,17 @@ void RippleCalc::pathNext(const PathState::pointer& pspCur, const int iPaths, co
const bool bMultiQuality = iPaths == 1;
const unsigned int uLast = pspCur->vpnNodes.size() - 1;
cLog(lsINFO) << "Path In: " << pspCur->getJson();
assert(pspCur->vpnNodes.size() >= 2);
// YYY This clearing should only be needed for nice logging.
pspCur->saInPass = STAmount(pspCur->saInReq.getCurrency(), pspCur->saInReq.getIssuer());
pspCur->saOutPass = STAmount(pspCur->saOutReq.getCurrency(), pspCur->saOutReq.getIssuer());
pspCur->vUnfundedBecame.clear();
pspCur->umReverse.clear();
cLog(lsINFO) << "Path In: " << pspCur->getJson();
assert(pspCur->vpnNodes.size() >= 2);
lesCurrent = lesCheckpoint; // Restore from checkpoint.
lesCurrent.bumpSeq(); // Begin ledger varance.
@@ -1797,9 +1817,17 @@ void RippleCalc::pathNext(const PathState::pointer& pspCur, const int iPaths, co
pspCur->terStatus = calcNodeFwd(0, pspCur, bMultiQuality);
tLog(tesSUCCESS == pspCur->terStatus, lsDEBUG)
<< boost::str(boost::format("saOutPass=%s saInPass=%s")
% pspCur->saOutPass.getFullText()
% pspCur->saInPass.getFullText());
// Make sure we have a quality.
assert(tesSUCCESS != pspCur->terStatus || (!!pspCur->saOutPass && !!pspCur->saInPass));
pspCur->uQuality = tesSUCCESS == pspCur->terStatus
? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality.
: 0; // Mark path as inactive.
? STAmount::getRate(pspCur->saOutPass, pspCur->saInPass) // Calculate relative quality.
: 0; // Mark path as inactive.
cLog(lsINFO) << "Path after forward: " << pspCur->getJson();
}
@@ -1913,8 +1941,8 @@ TER RippleCalc::rippleCalc(
terResult = temUNCERTAIN;
}
STAmount saPaid;
STAmount saWanted;
STAmount saInAct;
STAmount saOutAct;
const LedgerEntrySet lesBase = lesActive; // Checkpoint with just fees paid.
const uint64 uQualityLimit = bLimitQuality ? STAmount::getRate(saDstAmountReq, saMaxAmountReq) : 0;
// When processing, don't want to complicate directory walking with deletion.
@@ -1928,15 +1956,26 @@ TER RippleCalc::rippleCalc(
// Find the best path.
BOOST_FOREACH(PathState::pointer& pspCur, vpsPaths)
{
rc.pathNext(pspCur, vpsPaths.size(), lesCheckpoint, lesActive); // Compute increment.
if (pspCur->uQuality)
{
pspCur->saInAct = saInAct; // Update to current amount processed.
pspCur->saOutAct = saOutAct;
if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality.
|| !pspBest // Best is not yet set.
|| (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) // Current is better than set.
{
lesActive.swapWith(pspCur->lesEntries); // For the path, save ledger state.
pspBest = pspCur;
}
rc.pathNext(pspCur, vpsPaths.size(), lesCheckpoint, lesActive); // Compute increment.
if (!pspCur->uQuality) {
// Path was dry.
nothing();
}
else if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality.
|| !pspBest // Best is not yet set.
|| PathState::lessPriority(pspBest, pspCur)) // Current is better than set.
{
lesActive.swapWith(pspCur->lesEntries); // For the path, save ledger state.
pspBest = pspCur;
}
}
}
if (pspBest)
@@ -1949,18 +1988,35 @@ TER RippleCalc::rippleCalc(
// Record best pass' LedgerEntrySet to build off of and potentially return.
lesActive.swapWith(pspBest->lesEntries);
// Figure out if done.
if (temUNCERTAIN == terResult && saPaid == saWanted)
saInAct += pspBest->saInPass;
saOutAct += pspBest->saOutPass;
if (temUNCERTAIN == terResult && saOutAct == saDstAmountReq)
{
// Done. Delivered requested amount.
terResult = tesSUCCESS;
}
else
else if (saInAct != saMaxAmountReq)
{
// Prepare for next pass.
// Have not met requested amount or max send. Prepare for next pass.
// Merge best pass' umReverse.
rc.mumSource.insert(pspBest->umReverse.begin(), pspBest->umReverse.end());
}
else if (!bPartialPayment)
{
// Have sent maximum allowed. Partial payment not allowed.
terResult = tepPATH_PARTIAL;
lesActive = lesBase; // Revert to just fees charged.
}
else
{
// Have sent maximum allowed. Partial payment allowed. Success.
terResult = tesSUCCESS;
}
}
// Not done and ran out of paths.
else if (!bPartialPayment)
@@ -1970,7 +2026,7 @@ TER RippleCalc::rippleCalc(
lesActive = lesBase; // Revert to just fees charged.
}
// Partial payment ok.
else if (!saPaid)
else if (!saOutAct)
{
// No payment at all.
terResult = tepPATH_DRY;

View File

@@ -91,10 +91,12 @@ public:
int mIndex;
uint64 uQuality; // 0 = none.
STAmount saInReq; // Max amount to spend by sender
STAmount saInAct; // Amount spent by sender (calc output)
STAmount saOutReq; // Amount to send (calc input)
STAmount saOutAct; // Amount actually sent (calc output).
const STAmount& saInReq; // --> Max amount to spend by sender.
STAmount saInAct; // --> Amount spent by sender so far.
STAmount saInPass; // <-- Amount spent by sender.
const STAmount& saOutReq; // --> Amount to send.
STAmount saOutAct; // --> Amount actually sent so far.
STAmount saOutPass; // <-- Amount actually sent.
PathState(
const int iIndex,

View File

@@ -41,14 +41,14 @@ std::size_t hash_value(const uint160& u)
}
SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(smsModifying)
SHAMap::SHAMap(SHAMapType t, uint32 seq) : mSeq(seq), mState(smsModifying), mType(t)
{
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
root->makeInner();
mTNByID[*root] = root;
}
SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(smsSynching)
SHAMap::SHAMap(SHAMapType t, const uint256& hash) : mSeq(0), mState(smsSynching), mType(t)
{ // FIXME: Need to acquire root node
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
root->makeInner();
@@ -58,7 +58,7 @@ SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(smsSynching)
SHAMap::pointer SHAMap::snapShot(bool isMutable)
{ // Return a new SHAMap that is an immutable snapshot of this one
// Initially nodes are shared, but CoW is forced on both ledgers
SHAMap::pointer ret = boost::make_shared<SHAMap>();
SHAMap::pointer ret = boost::make_shared<SHAMap>(mType);
SHAMap& newMap = *ret;
newMap.mSeq = ++mSeq;
newMap.mTNByID = mTNByID;
@@ -93,7 +93,8 @@ std::stack<SHAMapTreeNode::pointer> SHAMap::getStack(const uint256& id, bool inc
{
if (partialOk)
return stack;
throw mn;
mn.setTargetNode(id);
throw;
}
}
@@ -153,10 +154,15 @@ SHAMapTreeNode::pointer SHAMap::walkTo(const uint256& id, bool modify)
return inNode;
uint256 childHash = inNode->getChildHash(branch);
SHAMapTreeNode::pointer nextNode = getNode(inNode->getChildNodeID(branch), childHash, false);
if (!nextNode)
throw SHAMapMissingNode(inNode->getChildNodeID(branch), childHash);
inNode = nextNode;
try
{
inNode = getNode(inNode->getChildNodeID(branch), childHash, false);
}
catch (SHAMapMissingNode& mn)
{
mn.setTargetNode(id);
throw;
}
}
if (inNode->getTag() != id)
return SHAMapTreeNode::pointer();
@@ -175,7 +181,7 @@ SHAMapTreeNode* SHAMap::walkToPointer(const uint256& id)
if (nextHash.isZero()) return NULL;
inNode = getNodePointer(inNode->getChildNodeID(branch), nextHash);
if (!inNode)
throw SHAMapMissingNode(inNode->getChildNodeID(branch), nextHash);
throw SHAMapMissingNode(mType, inNode->getChildNodeID(branch), nextHash, id);
}
return (inNode->getTag() == id) ? inNode : NULL;
}
@@ -680,11 +686,14 @@ void SHAMapItem::dump()
SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const uint256& hash)
{
if (!theApp->running())
throw SHAMapMissingNode(id, hash);
throw SHAMapMissingNode(mType, id, hash);
HashedObject::pointer obj(theApp->getHashedObjectStore().retrieve(hash));
if (!obj)
throw SHAMapMissingNode(id, hash);
{
Log(lsTRACE) << "fetchNodeExternal: missing " << hash;
throw SHAMapMissingNode(mType, id, hash);
}
assert(Serializer::getSHA512Half(obj->getData()) == hash);
try
@@ -698,10 +707,17 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui
catch (...)
{
cLog(lsWARNING) << "fetchNodeExternal gets an invalid node: " << hash;
throw SHAMapMissingNode(id, hash);
throw SHAMapMissingNode(mType, id, hash);
}
}
void SHAMap::fetchRoot(const uint256& hash)
{
root = fetchNodeExternal(SHAMapNode(), hash);
root->makeInner();
mTNByID[*root] = root;
}
void SHAMap::armDirty()
{ // begin saving dirty nodes
++mSeq;
@@ -719,6 +735,8 @@ int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq)
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = dirtyNodes.begin();
while (it != dirtyNodes.end())
{
tLog(mType == smtTRANSACTION, lsDEBUG) << "TX node write " << it->first;
tLog(mType == smtSTATE, lsDEBUG) << "STATE node write " << it->first;
s.erase();
it->second->addRaw(s, snfPREFIX);
theApp->getHashedObjectStore().store(t, seq, s.peekData(), s.getSHA512Half());
@@ -802,7 +820,7 @@ BOOST_AUTO_TEST_CASE( SHAMap_test )
h4.SetHex("b92891fe4ef6cee585fdc6fda2e09eb4d386363158ec3321b8123e5a772c6ca8");
h5.SetHex("a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7");
SHAMap sMap;
SHAMap sMap(smtFREE);
SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5));
if (!sMap.addItem(i2, true, false)) BOOST_FAIL("no add");

View File

@@ -128,6 +128,13 @@ enum SHANodeFormat
snfWIRE = 2, // Compressed form used on the wire
};
enum SHAMapType
{
smtTRANSACTION =1, // A tree of transactions
smtSTATE =2, // A tree of state nodes
smtFREE =3, // A tree not part of a ledger
};
class SHAMapTreeNode : public SHAMapNode
{
friend class SHAMap;
@@ -239,20 +246,35 @@ public:
class SHAMapMissingNode : public std::runtime_error
{
protected:
SHAMapType mType;
SHAMapNode mNodeID;
uint256 mNodeHash;
uint256 mTargetIndex;
public:
SHAMapMissingNode(const SHAMapNode& nodeID, const uint256& nodeHash) :
std::runtime_error(nodeID.getString()), mNodeID(nodeID), mNodeHash(nodeHash)
SHAMapMissingNode(SHAMapType t, const SHAMapNode& nodeID, const uint256& nodeHash) :
std::runtime_error(nodeID.getString()), mType(t), mNodeID(nodeID), mNodeHash(nodeHash)
{ ; }
SHAMapMissingNode(SHAMapType t, const SHAMapNode& nodeID, const uint256& nodeHash, const uint256& targetIndex) :
std::runtime_error(nodeID.getString()), mType(t),
mNodeID(nodeID), mNodeHash(nodeHash), mTargetIndex(targetIndex)
{ ; }
virtual ~SHAMapMissingNode() throw()
{ ; }
const SHAMapNode& getNodeID() const { return mNodeID; }
const uint256& getNodeHash() const { return mNodeHash; }
void setTargetNode(const uint256& tn) { mTargetIndex = tn; }
SHAMapType getMapType() const { return mType; }
const SHAMapNode& getNodeID() const { return mNodeID; }
const uint256& getNodeHash() const { return mNodeHash; }
const uint256& getTargetIndex() const { return mTargetIndex; }
bool hasTargetIndex() const { return !mTargetIndex.isZero(); }
};
extern std::ostream& operator<<(std::ostream&, const SHAMapMissingNode&);
class SHAMap
{
public:
@@ -272,6 +294,8 @@ private:
SHAMapState mState;
SHAMapType mType;
protected:
void dirtyUp(std::stack<SHAMapTreeNode::pointer>& stack, const uint256& target, uint256 prevHash);
@@ -296,8 +320,8 @@ protected:
public:
// build new map
SHAMap(uint32 seq = 0);
SHAMap(const uint256& hash);
SHAMap(SHAMapType t, uint32 seq = 0);
SHAMap(SHAMapType t, const uint256& hash);
~SHAMap() { mState = smsInvalid; }
@@ -308,6 +332,7 @@ public:
ScopedLock Lock() const { return ScopedLock(mLock); }
bool hasNode(const SHAMapNode& id);
void fetchRoot(const uint256& hash);
// normal hash access functions
bool hasItem(const uint256& id);

View File

@@ -120,7 +120,7 @@ bool SHAMap::compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount
if (!ourNode || !otherNode)
{
assert(false);
throw SHAMapMissingNode(dNode.mNodeID, uint256());
throw SHAMapMissingNode(mType, dNode.mNodeID, uint256());
}
if (ourNode->isLeaf() && otherNode->isLeaf())

View File

@@ -18,6 +18,9 @@
std::string SHAMapNode::getString() const
{
if ((mDepth == 0) && (mNodeID.isZero()))
return "NodeID(root)";
return str(boost::format("NodeID(%s,%s)")
% boost::lexical_cast<std::string>(mDepth)
% mNodeID.GetHex());
@@ -507,4 +510,16 @@ bool SHAMapTreeNode::setChildHash(int m, const uint256 &hash)
return updateHash();
}
std::ostream& operator<<(std::ostream& out, const SHAMapMissingNode& mn)
{
if (mn.getMapType() == smtTRANSACTION)
out << "Missing/TXN(" << mn.getNodeID() << ")";
else if (mn.getMapType() == smtSTATE)
out << "Missing/STA(" << mn.getNodeID() << ")";
else
out << "Missing/" << mn.getNodeID();
}
// vim:ts=4

View File

@@ -53,7 +53,7 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
{
d = getNode(childID, childHash, false);
}
catch (SHAMapMissingNode& )
catch (SHAMapMissingNode&)
{ // node is not in the map
if (filter != NULL)
{
@@ -269,14 +269,15 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigned cha
if (nextNode->isInner() && !nextNode->isFullBelow())
return true;
}
catch (SHAMapMissingNode)
catch (SHAMapMissingNode&)
{
return true;
}
}
iNode->setFullBelow();
} while (!stack.empty());
if (root->isFullBelow()) clearSynching();
if (root->isFullBelow())
clearSynching();
return true;
}
@@ -420,7 +421,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test )
srand(seed);
cLog(lsTRACE) << "Constructing maps";
SHAMap source, destination;
SHAMap source(smtFREE), destination(smtFREE);
// add random data to the source map
cLog(lsTRACE) << "Adding random data";

View File

@@ -120,8 +120,8 @@ std::auto_ptr<SerializedType> STObject::makeDeserializedObject(SerializedTypeID
void STObject::set(const std::vector<SOElement::ptr>& type)
{
mData.empty();
mType.empty();
mData.clear();
mType.clear();
BOOST_FOREACH(const SOElement::ptr& elem, type)
{
@@ -138,7 +138,7 @@ bool STObject::setType(const std::vector<SOElement::ptr> &type)
boost::ptr_vector<SerializedType> newData;
bool valid = true;
mType.empty();
mType.clear();
BOOST_FOREACH(const SOElement::ptr& elem, type)
{
bool match = false;
@@ -204,7 +204,7 @@ bool STObject::isFieldAllowed(SField::ref field)
bool STObject::set(SerializerIterator& sit, int depth)
{ // return true = terminated with end-of-object
mData.empty();
mData.clear();
while (!sit.empty())
{
int type, field;

View File

@@ -504,9 +504,15 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac
return temDST_NEEDED;
}
else if (bMax && !saMaxAmount.isPositive())
{
Log(lsINFO) << "doPayment: Invalid transaction: bad max amount: " << saMaxAmount.getFullText();
return temBAD_AMOUNT;
}
else if (!saDstAmount.isPositive())
{
Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getHumanCurrency() << " " << saDstAmount.getText();
Log(lsINFO) << "doPayment: Invalid transaction: bad dst amount: " << saDstAmount.getFullText();
return temBAD_AMOUNT;
}