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

This commit is contained in:
jed
2012-08-27 08:01:42 -07:00
14 changed files with 657 additions and 569 deletions

View File

@@ -651,10 +651,10 @@ STAmount operator-(const STAmount& v1, const STAmount& v2)
return STAmount(v1.name, v1.mCurrency, -fv, ov1, true);
}
STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& currencyOut)
STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID)
{
if (den.isZero()) throw std::runtime_error("division by zero");
if (num.isZero()) return STAmount(currencyOut);
if (num.isZero()) return STAmount(uCurrencyID, uIssuerID);
uint64 numVal = num.mValue, denVal = den.mValue;
int numOffset = num.mOffset, denOffset = den.mOffset;
@@ -690,14 +690,14 @@ STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint16
assert(BN_num_bytes(&v) <= 64);
if (num.mIsNegative != den.mIsNegative)
return -STAmount(currencyOut, v.getulong(), finOffset);
else return STAmount(currencyOut, v.getulong(), finOffset);
return -STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset);
else return STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset);
}
STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut)
STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID)
{
if (v1.isZero() || v2.isZero())
return STAmount(currencyOut);
return STAmount(uCurrencyID, uIssuerID);
if (v1.mIsNative && v2.mIsNative) // FIXME: overflow
return STAmount(v1.name, v1.getSNValue() * v2.getSNValue());
@@ -753,8 +753,8 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16
assert(BN_num_bytes(&v) <= 64);
if (v1.mIsNegative != v2.mIsNegative)
return -STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14);
else return STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14);
return -STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14);
else return STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14);
}
// Convert an offer into an index amount so they sort by rate.
@@ -769,7 +769,7 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn)
{
if (offerOut.isZero()) throw std::runtime_error("Worthless offer");
STAmount r = divide(offerIn, offerOut, uint160(1));
STAmount r = divide(offerIn, offerOut, CURRENCY_ONE, ACCOUNT_ONE);
assert((r.getExponent() >= -100) && (r.getExponent() <= 155));
@@ -778,12 +778,12 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn)
return (ret << (64 - 8)) | r.getMantissa();
}
STAmount STAmount::setRate(uint64 rate, const uint160& currencyOut)
STAmount STAmount::setRate(uint64 rate)
{
uint64 mantissa = rate & ~(255ull << (64 - 8));
int exponent = static_cast<int>(rate >> (64 - 8)) - 100;
return STAmount(currencyOut, mantissa, exponent);
return STAmount(CURRENCY_ONE, ACCOUNT_ONE, mantissa, exponent);
}
// Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds.
@@ -814,7 +814,7 @@ bool STAmount::applyOffer(
STAmount saOfferGetsAvailable =
saOfferFunds == saOfferPays
? saOfferGets // Offer was fully funded, avoid shenanigans.
: divide(multiply(saTakerPays, saOfferPaysAvailable, uint160(1)), saTakerGets, saOfferGets.getCurrency());
: divide(multiply(saTakerPays, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saTakerGets, saOfferGets.getCurrency(), saOfferGets.getIssuer());
if (saOfferGets == saOfferGetsAvailable && saTakerFunds >= saOfferGets)
{
@@ -836,7 +836,7 @@ bool STAmount::applyOffer(
{
// Taker only get's a portion of offer.
saTakerPaid = saTakerFunds; // Taker paid all he had.
saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, uint160(1)), saOfferGetsAvailable, saOfferPays.getCurrency());
saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saOfferGetsAvailable, saOfferPays.getCurrency(), saOfferPays.getIssuer());
Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot.getFullText();
Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText();
@@ -848,7 +848,7 @@ bool STAmount::applyOffer(
STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed)
{ // Someone wants to get (needed) out of the offer, how much should they pay in?
if (offerOut.isZero())
return STAmount(offerIn.getCurrency());
return STAmount(offerIn.getCurrency(), offerIn.getIssuer());
if (needed >= offerOut)
{
@@ -856,7 +856,7 @@ STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, con
return needed;
}
STAmount ret = divide(multiply(needed, offerIn, uint160(1)), offerOut, offerIn.getCurrency());
STAmount ret = divide(multiply(needed, offerIn, CURRENCY_ONE, ACCOUNT_ONE), offerOut, offerIn.getCurrency(), offerIn.getIssuer());
return (ret > offerIn) ? offerIn : ret;
}
@@ -1063,8 +1063,7 @@ BOOST_AUTO_TEST_CASE( NativeCurrency_test )
BOOST_AUTO_TEST_CASE( CustomCurrency_test )
{
uint160 currency(1);
STAmount zero(currency), one(currency, 1), hundred(currency, 100);
STAmount zero(CURRENCY_ONE, ACCOUNT_ONE), one(CURRENCY_ONE, ACCOUNT_ONE, 1), hundred(CURRENCY_ONE, ACCOUNT_ONE, 100);
serdes(one).getRaw();
@@ -1131,33 +1130,33 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test )
if (!(hundred != zero)) BOOST_FAIL("STAmount fail");
if (!(hundred != one)) BOOST_FAIL("STAmount fail");
if ((hundred != hundred)) BOOST_FAIL("STAmount fail");
if (STAmount(currency).getText() != "0") BOOST_FAIL("STAmount fail");
if (STAmount(currency,31).getText() != "31") BOOST_FAIL("STAmount fail");
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(CURRENCY_ONE, ACCOUNT_ONE).getText() != "0") BOOST_FAIL("STAmount fail");
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31).getText() != "31") BOOST_FAIL("STAmount fail");
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,1).getText() != "310") BOOST_FAIL("STAmount fail");
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail");
if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail");
if (STAmount::multiply(STAmount(currency, 20), STAmount(3), currency).getText() != "60")
if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::multiply(STAmount(currency, 20), STAmount(3), uint160()).getText() != "60")
if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::multiply(STAmount(20), STAmount(3), currency).getText() != "60")
if (STAmount::multiply(STAmount(20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::multiply(STAmount(20), STAmount(3), uint160()).getText() != "60")
if (STAmount::multiply(STAmount(20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::divide(STAmount(currency, 60) , STAmount(3), currency).getText() != "20")
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20")
BOOST_FAIL("STAmount divide fail");
if (STAmount::divide(STAmount(currency, 60) , STAmount(3), uint160()).getText() != "20")
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "20")
BOOST_FAIL("STAmount divide fail");
if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), currency).getText() != "20")
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20")
BOOST_FAIL("STAmount divide fail");
if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), uint160()).getText() != "20")
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), uint160(), ACCOUNT_XNS).getText() != "20")
BOOST_FAIL("STAmount divide fail");
STAmount a1(currency, 60), a2 (currency, 10, -1);
if (STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency))
STAmount a1(CURRENCY_ONE, ACCOUNT_ONE, 60), a2 (CURRENCY_ONE, ACCOUNT_ONE, 10, -1);
if (STAmount::divide(a2, a1, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a1, a2)))
BOOST_FAIL("STAmount setRate(getRate) fail");
if (STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency))
if (STAmount::divide(a1, a2, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a2, a1)))
BOOST_FAIL("STAmount setRate(getRate) fail");
BOOST_TEST_MESSAGE("Amount CC Complete");
@@ -1168,22 +1167,21 @@ BOOST_AUTO_TEST_CASE( CurrencyMulDivTests )
// Test currency multiplication and division operations such as
// convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded
uint160 c(1);
if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(c, 1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(c, 10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(c, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(c, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
if (STAmount::getRate(STAmount(10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
if (STAmount::getRate(STAmount(10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul))
BOOST_FAIL("STAmount getRate fail");
}

View File

@@ -230,8 +230,77 @@ Json::Value LedgerEntrySet::getJson(int) const
return ret;
}
void LedgerEntrySet::addRawMeta(Serializer& s, Ledger::pointer origLedger)
SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::pointer& ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods)
{
boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator it = mEntries.find(node);
if (it != mEntries.end())
{
if (it->second.mAction == taaDELETE)
return SLE::pointer();
if (it->second.mAction == taaCACHED)
it->second.mAction = taaMODIFY;
if (it->second.mSeq != mSeq)
{
it->second.mEntry = boost::make_shared<SerializedLedgerEntry>(*it->second.mEntry);
it->second.mSeq = mSeq;
}
return it->second.mEntry;
}
boost::unordered_map<uint256, SLE::pointer>::iterator me = newMods.find(node);
if (me != newMods.end())
return me->second;
SLE::pointer ret = ledger->getSLE(node);
if (ret)
newMods.insert(std::make_pair(node, ret));
return ret;
}
bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::pointer& ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods)
{
SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods);
if (!sle)
return false;
return threadTx(metaNode, sle, ledger, newMods);
}
bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::pointer& ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods)
{ // node = the node that was modified/deleted/created
// threadTo = the node that needs to know
uint256 prevTxID;
uint32 prevLgrID;
if (!threadTo->thread(mSet.getTxID(), mSet.getLgrSeq(), prevTxID, prevLgrID))
return false;
if (metaNode.thread(prevTxID, prevLgrID))
return true;
assert(false);
return false;
}
bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::pointer& ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods)
{ // thread new or modified node to owner or owners
if (node->hasOneOwner()) // thread to owner's account
return threadTx(metaNode, node->getOwner(), ledger, newMods);
else if (node->hasTwoOwners()) // thread to owner's accounts
return
threadTx(metaNode, node->getFirstOwner(), ledger, newMods) ||
threadTx(metaNode, node->getSecondOwner(), ledger, newMods);
else
return false;
}
void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::pointer& origLedger)
{ // calculate the raw meta data and return it. This must be called before the set is committed
// Entries modified only as a result of building the transaction metadata
boost::unordered_map<uint256, SLE::pointer> newMod;
for (boost::unordered_map<uint256, LedgerEntrySetEntry>::const_iterator it = mEntries.begin(),
end = mEntries.end(); it != end; ++it)
{
@@ -256,11 +325,40 @@ void LedgerEntrySet::addRawMeta(Serializer& s, Ledger::pointer origLedger)
{
SLE::pointer origNode = origLedger->getSLE(it->first);
SLE::pointer curNode = it->second.mEntry;
TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType);
// FINISH
if (nType == TMNDeletedNode)
{
threadOwners(metaNode, origNode, origLedger, newMod);
if (origNode->getType() == ltOFFER)
{ // check for non-zero balances
// WRITEME
}
}
if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode))
{
if (nType == TMNCreatedNode) // if created, thread to owner(s)
threadOwners(metaNode, curNode, origLedger, newMod);
if (curNode->isThreadedType()) // always thread to self
threadTx(metaNode, curNode, origLedger, newMod);
if (nType == TMNModifiedNode)
{
// analyze changes WRITEME
}
}
}
}
// add any new modified nodes to the modification set
for (boost::unordered_map<uint256, SLE::pointer>::iterator it = newMod.begin(), end = newMod.end();
it != end; ++it)
entryCache(it->second);
mSet.addRaw(s);
}

View File

@@ -38,6 +38,18 @@ protected:
LedgerEntrySet(const boost::unordered_map<uint256, LedgerEntrySetEntry> &e, const TransactionMetaSet& s, int m) :
mEntries(e), mSet(s), mSeq(m) { ; }
SLE::pointer getForMod(const uint256& node, Ledger::pointer& ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::pointer& ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::pointer& ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::pointer& ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
public:
LedgerEntrySet() : mSeq(0) { ; }
@@ -60,7 +72,7 @@ public:
void entryModify(const SLE::pointer&); // This entry will be modified
Json::Value getJson(int) const;
void addRawMeta(Serializer&, Ledger::pointer originalLedger);
void calcRawMeta(Serializer&, Ledger::pointer& originalLedger);
// iterator functions
bool isEmpty() const { return mEntries.empty(); }

View File

@@ -85,7 +85,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
}
TransactionEngineResult r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tepNONE);
if (r == tenFAILED) throw Fault(IO_ERROR);
if (r == tefFAILURE) throw Fault(IO_ERROR);
if (r == terPRE_SEQ)
{ // transaction should be held
@@ -95,14 +95,14 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
mLedgerMaster->addHeldTransaction(trans);
return trans;
}
if ((r == terPAST_SEQ) || (r == terPAST_LEDGER))
if ((r == tefPAST_SEQ))
{ // duplicate or conflict
Log(lsINFO) << "Transaction is obsolete";
trans->setStatus(OBSOLETE);
return trans;
}
if (r == terSUCCESS)
if (r == tesSUCCESS)
{
Log(lsINFO) << "Transaction is now included";
trans->setStatus(INCLUDED);
@@ -875,7 +875,7 @@ void NetworkOPs::pubLedger(const Ledger::pointer& lpAccepted)
SerializedTransaction::pointer stTxn = theApp->getMasterTransaction().fetch(item, false, 0);
// XXX Need to support other results.
// XXX Need to give failures too.
TransactionEngineResult terResult = terSUCCESS;
TransactionEngineResult terResult = tesSUCCESS;
if (bAll)
{

View File

@@ -21,9 +21,9 @@ TODO: what is a good way to come up with multiple paths?
OrderDB:
getXNSOffers();
// return list of all orderbooks that want XNS
getXNSOffers();
// return list of all orderbooks that want XNS
// return list of all orderbooks that want IssuerID
// return list of all orderbooks that want this issuerID and currencyID
*/
@@ -49,7 +49,7 @@ bool sortPathOptions(PathOption::pointer first, PathOption::pointer second)
{
if(first->mTotalCost<second->mTotalCost) return(true);
if(first->mTotalCost>second->mTotalCost) return(false);
if(first->mCorrectCurrency && !second->mCorrectCurrency) return(true);
if(!first->mCorrectCurrency && second->mCorrectCurrency) return(false);
@@ -57,7 +57,7 @@ bool sortPathOptions(PathOption::pointer first, PathOption::pointer second)
if(first->mPath.getElementCount()>second->mPath.getElementCount()) return(false);
if(first->mMinWidth<second->mMinWidth) return true;
return false;
}
@@ -77,7 +77,7 @@ PathOption::PathOption(PathOption::pointer other)
Pathfinder::Pathfinder(NewcoinAddress& srcAccountID, NewcoinAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount) :
mSrcAccountID(srcAccountID.getAccountID()) , mDstAccountID(dstAccountID.getAccountID()), mSrcCurrencyID(srcCurrencyID) , mDstAmount(dstAmount), mOrderBook(theApp->getMasterLedger().getCurrentLedger())
mSrcAccountID(srcAccountID.getAccountID()), mDstAccountID(dstAccountID.getAccountID()), mDstAmount(dstAmount), mSrcCurrencyID(srcCurrencyID), mOrderBook(theApp->getMasterLedger().getCurrentLedger())
{
mLedger=theApp->getMasterLedger().getCurrentLedger();
}
@@ -99,9 +99,8 @@ bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet
}
if(checkComplete(retPathSet)) return(true);
}
}
return(false);
}
@@ -125,8 +124,8 @@ bool Pathfinder::checkComplete(STPathSet& retPathSet)
// get all the options from this accountID
// if source is XNS
// every offer that wants XNS
// else
// every ripple line that starts with the source currency
// else
// every ripple line that starts with the source currency
// every offer that we can take that wants the source currency
void Pathfinder::addOptions(PathOption::pointer tail)
@@ -150,7 +149,7 @@ void Pathfinder::addOptions(PathOption::pointer tail)
BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines())
{
// TODO: make sure we can move in the correct direction
STAmount balance=line->getBalance();
STAmount balance=line->getBalance();
if(balance.getCurrency()==tail->mCurrencyID)
{ // we have a ripple line from the tail to somewhere else
PathOption::pointer pathOption(new PathOption(tail));
@@ -161,7 +160,7 @@ void Pathfinder::addOptions(PathOption::pointer tail)
pathOption->mCurrentAccount=line->getAccountIDPeer().getAccountID();
addPathOption(pathOption);
}
}
}
// every offer that wants the source currency
@@ -184,7 +183,7 @@ void Pathfinder::addOptions(PathOption::pointer tail)
void Pathfinder::addPathOption(PathOption::pointer pathOption)
{
if(pathOption->mCurrencyID==mDstAmount.getCurrency())
if(pathOption->mCurrencyID==mDstAmount.getCurrency())
{
pathOption->mCorrectCurrency=true;
@@ -192,11 +191,11 @@ void Pathfinder::addPathOption(PathOption::pointer pathOption)
{ // this path is complete
mCompletePaths.push_back(pathOption);
}else mBuildingPaths.push_back(pathOption);
}else
}
else
{
pathOption->mCorrectCurrency=false;
mBuildingPaths.push_back(pathOption);
}
}
// vim:ts=4

View File

@@ -33,7 +33,6 @@ class Pathfinder
OrderBookDB mOrderBook;
Ledger::pointer mLedger;
std::list<PathOption::pointer> mBuildingPaths;
std::list<PathOption::pointer> mCompletePaths;
@@ -49,4 +48,5 @@ public:
// returns false if there is no path. otherwise fills out retPath
bool findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet);
};
};
// vim:ts=4

View File

@@ -45,7 +45,7 @@ Json::Value RPCServer::RPCError(int iError)
{ rpcBAD_SEED, "badSeed", "Disallowed seed." },
{ rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." },
{ rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exists." },
{ rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." },
{ rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed." },
{ rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." },
{ rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." },
{ rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed." },
@@ -74,7 +74,7 @@ Json::Value RPCServer::RPCError(int iError)
{ rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed." },
{ rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." },
{ rpcSRC_ACT_MISSING, "srcActMissing", "Source account does not exist." },
{ rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency is malformed." },
{ rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." },
{ rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." },
{ rpcSUCCESS, "success", "Success." },
{ rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." },
@@ -1706,7 +1706,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value &params)
return ret;
}
// send regular_seed paying_account account_id amount [currency] [send_max] [send_currency]
// send regular_seed paying_account account_id amount [currency] [issuer] [send_max] [send_currency] [send_issuer]
Json::Value RPCServer::doSend(const Json::Value& params)
{
NewcoinAddress naSeed;
@@ -1716,13 +1716,21 @@ Json::Value RPCServer::doSend(const Json::Value& params)
STAmount saDstAmount;
std::string sSrcCurrency;
std::string sDstCurrency;
std::string sSrcIssuer;
std::string sDstIssuer;
if (params.size() >= 5)
sDstCurrency = params[4u].asString();
if (params.size() >= 6)
sDstIssuer = params[5u].asString();
if (params.size() >= 7)
sSrcCurrency = params[6u].asString();
if (params.size() >= 8)
sSrcIssuer = params[7u].asString();
if (!naSeed.setSeedGeneric(params[0u].asString()))
{
return RPCError(rpcBAD_SEED);
@@ -1735,11 +1743,11 @@ Json::Value RPCServer::doSend(const Json::Value& params)
{
return RPCError(rpcDST_ACT_MALFORMED);
}
else if (!saDstAmount.setFullValue(params[3u].asString(), sDstCurrency))
else if (!saDstAmount.setFullValue(params[3u].asString(), sDstCurrency, sDstIssuer))
{
return RPCError(rpcDST_AMT_MALFORMED);
}
else if (params.size() >= 6 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency))
else if (params.size() >= 7 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency, sSrcIssuer))
{
return RPCError(rpcSRC_AMT_MALFORMED);
}
@@ -1758,10 +1766,16 @@ Json::Value RPCServer::doSend(const Json::Value& params)
Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
saSrcBalance, saFee, asSrc, naVerifyGenerator);
// Log(lsINFO) << boost::str(boost::format("doSend: sSrcIssuer=%s sDstIssuer=%s saSrcAmountMax=%s saDstAmount=%s")
// % sSrcIssuer
// % sDstIssuer
// % saSrcAmountMax.getFullText()
// % saDstAmount.getFullText());
if (!obj.empty())
return obj;
if (params.size() < 6)
if (params.size() < 7)
saSrcAmountMax = saDstAmount;
// Do a few simple checks.
@@ -2554,7 +2568,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params
{ "ripple", &RPCServer::doRipple, 8, -1, false, optCurrent|optClosed },
{ "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent },
{ "ripple_line_set", &RPCServer::doRippleLineSet, 4, 7, false, optCurrent },
{ "send", &RPCServer::doSend, 3, 7, false, optCurrent },
{ "send", &RPCServer::doSend, 3, 9, false, optCurrent },
{ "server_info", &RPCServer::doServerInfo, 0, 0, true },
{ "stop", &RPCServer::doStop, 0, 0, true },
{ "tx", &RPCServer::doTx, 1, 1, true },

View File

@@ -109,6 +109,31 @@ bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint25
return true;
}
bool SerializedLedgerEntry::hasOneOwner()
{
return (mType != ltACCOUNT_ROOT) && (getIFieldIndex(sfAccount) != -1);
}
bool SerializedLedgerEntry::hasTwoOwners()
{
return mType == ltRIPPLE_STATE;
}
NewcoinAddress SerializedLedgerEntry::getOwner()
{
return getIValueFieldAccount(sfAccount);
}
NewcoinAddress SerializedLedgerEntry::getFirstOwner()
{
return getIValueFieldAccount(sfLowID);
}
NewcoinAddress SerializedLedgerEntry::getSecondOwner()
{
return getIValueFieldAccount(sfHighID);
}
std::vector<uint256> SerializedLedgerEntry::getOwners()
{
std::vector<uint256> owners;

View File

@@ -65,6 +65,11 @@ public:
bool isThreadedType(); // is this a ledger entry that can be threaded
bool isThreaded(); // is this ledger entry actually threaded
bool hasOneOwner(); // This node has one other node that owns it (like nickname)
bool hasTwoOwners(); // This node has two nodes that own it (like ripple balance)
NewcoinAddress getOwner();
NewcoinAddress getFirstOwner();
NewcoinAddress getSecondOwner();
uint256 getThreadedTransaction();
uint32 getThreadedLedger();
bool thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID);

View File

@@ -261,10 +261,11 @@ public:
: SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false)
{ ; }
STAmount(const uint160& uCurrency, uint64 uV=0, int iOff=0, bool bNegative=false)
: mCurrency(uCurrency), mValue(uV), mOffset(iOff), mIsNegative(bNegative)
STAmount(const uint160& uCurrencyID, const uint160& uIssuerID, uint64 uV=0, int iOff=0, bool bNegative=false)
: mCurrency(uCurrencyID), mIssuer(uIssuerID), mValue(uV), mOffset(iOff), mIsNegative(bNegative)
{ canonicalize(); }
// YYY This should probably require issuer too.
STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) :
SerializedType(n), mCurrency(currency), mValue(v), mOffset(off), mIsNegative(isNeg)
{ canonicalize(); }
@@ -274,14 +275,14 @@ public:
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, const char* name)
{ return std::auto_ptr<SerializedType>(construct(sit, name)); }
static STAmount saFromRate(uint64 uV = 0)
static STAmount saFromRate(uint64 uRate = 0)
{
return STAmount(CURRENCY_ONE, uV, -9, false);
return STAmount(CURRENCY_ONE, ACCOUNT_ONE, uRate, -9, false);
}
static STAmount saFromSigned(const uint160& uCurrency, int64 iV=0, int iOff=0)
static STAmount saFromSigned(const uint160& uCurrencyID, const uint160& uIssuerID, int64 iV=0, int iOff=0)
{
return STAmount(uCurrency, iV < 0 ? -iV : iV, iOff, iV < 0);
return STAmount(uCurrencyID, uIssuerID, iV < 0 ? -iV : iV, iOff, iV < 0);
}
int getLength() const { return mIsNative ? 8 : 28; }
@@ -351,13 +352,13 @@ public:
friend STAmount operator+(const STAmount& v1, const STAmount& v2);
friend STAmount operator-(const STAmount& v1, const STAmount& v2);
static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& currencyOut);
static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut);
static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID);
static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID);
// Someone is offering X for Y, what is the rate?
// Rate: smaller is better, the taker wants the most out: in/out
static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn);
static STAmount setRate(uint64 rate, const uint160& currencyOut);
static STAmount setRate(uint64 rate);
// Someone is offering X for Y, I try to pay Z, how much do I get?
// And what's left of the offer? And how much do I actually pay?

File diff suppressed because it is too large Load Diff

View File

@@ -14,75 +14,71 @@
enum TransactionEngineResult
{
// Note: Numbers are currently unstable. Use tokens.
// Note: Range is stable. Exact numbers are currently unstable. Use tokens.
// tenCAN_NEVER_SUCCEED = <0
// -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit)
// Not forwarded, no fee. Only valid during non-consensus processing
telLOCAL_ERROR = -399,
telBAD_PATH_COUNT,
telINSUF_FEE_P,
// Malformed: Fee claimed
tenGEN_IN_USE = -300,
tenBAD_ADD_AUTH,
tenBAD_AMOUNT,
tenBAD_CLAIM_ID,
tenBAD_EXPIRATION,
tenBAD_GEN_AUTH,
tenBAD_ISSUER,
tenBAD_OFFER,
tenBAD_PATH,
tenBAD_PATH_COUNT,
tenBAD_PUBLISH,
tenBAD_SET_ID,
tenCREATEXNS,
tenDST_IS_SRC,
tenDST_NEEDED,
tenEXPLICITXNS,
tenREDUNDANT,
tenRIPPLE_EMPTY,
// -299 .. -200: M Malformed (bad signature)
// Transaction corrupt, not forwarded, cannot charge fee, reject
// Never can succeed in any ledger
temMALFORMED = -299,
temBAD_AMOUNT,
temBAD_AUTH_MASTER,
temBAD_EXPIRATION,
temBAD_ISSUER,
temBAD_OFFER,
temBAD_PUBLISH,
temBAD_SET_ID,
temCREATEXNS,
temDST_IS_SRC,
temDST_NEEDED,
temINSUF_FEE_P,
temINVALID,
temREDUNDANT,
temRIPPLE_EMPTY,
temUNKNOWN,
// Invalid: Ledger won't allow.
tenCLAIMED = -200,
tenBAD_RIPPLE,
tenCREATED,
tenEXPIRED,
tenMSG_SET,
terALREADY,
// -199 .. -100: F Failure (sequence number previously used)
// Transaction cannot succeed because of ledger state, unexpected ledger state, C++ exception, not forwarded, cannot be
// applied, Could succeed in an imaginary ledger.
tefFAILURE = -199,
tefALREADY,
tefBAD_ADD_AUTH,
tefBAD_AUTH,
tefBAD_CLAIM_ID,
tefBAD_GEN_AUTH,
tefBAD_LEDGER,
tefCLAIMED,
tefCREATED,
tefGEN_IN_USE,
tefPAST_SEQ,
// Other
tenFAILED = -100,
tenINSUF_FEE_P,
tenINVALID,
tenUNKNOWN,
terSUCCESS = 0,
// terFAILED_BUT_COULD_SUCCEED = >0
// Conflict with ledger database: Fee claimed
// Might succeed if not conflict is not caused by transaction ordering.
terBAD_AUTH,
terBAD_AUTH_MASTER,
terBAD_LEDGER,
terBAD_RIPPLE,
terBAD_SEQ,
terCREATED,
// -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent)
// Transaction cannot be applied, cannot charge fee, not forwarded, might succeed later, hold
terRETRY = -99,
terDIR_FULL,
terFUNDS_SPENT,
terINSUF_FEE_B,
terINSUF_FEE_T,
terNODE_NOT_FOUND,
terNODE_NOT_MENTIONED,
terNODE_NO_ROOT,
terNO_ACCOUNT,
terNO_DST,
terNO_LINE_NO_ZERO,
terNO_PATH,
terOFFER_NOT_FOUND,
terOVER_LIMIT,
terPAST_LEDGER,
terPAST_SEQ,
terOFFER_NOT_FOUND, // XXX If we check sequence first this could be hard failure.
terPRE_SEQ,
terSET_MISSING_DST,
terUNCLAIMED,
terUNFUNDED,
// 0: S Success (success)
// Transaction succeeds, can be applied, can charge fee, forwarded
tesSUCCESS = 0,
// 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account)
// Transaction can be applied, can charge fee, forwarded, but does not achieve optimal result.
tesPARITAL = 100,
// Might succeed in different order.
// XXX claim fee and try to delete unfunded.
terPATH_EMPTY,
@@ -133,9 +129,19 @@ protected:
public:
typedef boost::shared_ptr<PathState> pointer;
bool bValid;
std::vector<paymentNode> vpnNodes;
LedgerEntrySet lesEntries;
bool bValid;
std::vector<paymentNode> vpnNodes;
// If the transaction fails to meet some constraint, still need to delete unfunded offers.
boost::unordered_set<uint256> usUnfundedFound; // Offers that were found unfunded.
// When processing, don't want to complicate directory walking with deletion.
std::vector<uint256> vUnfundedBecame; // Offers that became unfunded.
// First time working in reverse a funding source was mentioned. Source may only be used there.
boost::unordered_map<std::pair<uint160, uint160>, int> umSource; // Map of currency, issuer to node index.
LedgerEntrySet lesEntries;
int mIndex;
uint64 uQuality; // 0 = none.
@@ -222,14 +228,15 @@ protected:
SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex);
SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex);
void entryDelete(SLE::pointer sleEntry, bool unfunded = false);
void entryDelete(SLE::pointer sleEntry, bool bUnfunded = false);
void entryModify(SLE::pointer sleEntry);
uint32 rippleTransferRate(const uint160& uIssuerID);
STAmount rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
STAmount rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, const SOE_Field sfLow=sfLowQualityIn, const SOE_Field sfHigh=sfHighQualityIn);
uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
{ return rippleQualityIn(uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut); }
STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
STAmount rippleTransferFee(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount);

View File

@@ -262,6 +262,14 @@ bool TransactionMetaSet::isNodeAffected(const uint256& node) const
return mNodes.find(node) != mNodes.end();
}
TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type)
{
std::map<uint256, TransactionMetaNode>::iterator it = mNodes.find(node);
if (it != mNodes.end())
return it->second;
return mNodes.insert(std::make_pair(node, TransactionMetaNode(node, type))).first->second;
}
const TransactionMetaNode& TransactionMetaSet::peekAffectedNode(const uint256& node) const
{
std::map<uint256, TransactionMetaNode>::const_iterator it = mNodes.find(node);
@@ -283,28 +291,3 @@ void TransactionMetaSet::swap(TransactionMetaSet& s)
mNodes.swap(s.mNodes);
}
TransactionMetaNode& TransactionMetaSet::modifyNode(const uint256& node)
{
std::map<uint256, TransactionMetaNode>::iterator it = mNodes.find(node);
if (it != mNodes.end())
return it->second;
return mNodes.insert(std::make_pair(node, TransactionMetaNode(node))).first->second;
}
#if 0
void TransactionMetaSet::threadNode(const uint256& node, const uint256& prevTx, uint32 prevLgr)
{
modifyNode(node).thread(prevTx, prevLgr);
}
void TransactionMetaSet::deleteUnfunded(const uint256& nodeID,
const STAmount& firstBalance, const STAmount &secondBalance)
{
TransactionMetaNode& node = modifyNode(nodeID);
TMNEUnfunded* entry = dynamic_cast<TMNEUnfunded*>(node.findEntry(TransactionMetaNodeEntry::TMNDeleteUnfunded));
if (entry)
entry->setBalances(firstBalance, secondBalance);
else
node.addNode(new TMNEUnfunded(firstBalance, secondBalance));
}
#endif

View File

@@ -133,7 +133,7 @@ protected:
boost::ptr_vector<TransactionMetaNodeEntry> mEntries;
public:
TransactionMetaNode(const uint256 &node) : mNode(node) { ; }
TransactionMetaNode(const uint256 &node, int type) : mType(type), mNode(node) { ; }
const uint256& getNode() const { return mNode; }
const boost::ptr_vector<TransactionMetaNodeEntry>& peekEntries() const { return mEntries; }
@@ -163,8 +163,6 @@ protected:
uint32 mLedger;
std::map<uint256, TransactionMetaNode> mNodes;
TransactionMetaNode& modifyNode(const uint256&);
public:
TransactionMetaSet() : mLedger(0) { ; }
TransactionMetaSet(const uint256& txID, uint32 ledger) : mTransactionID(txID), mLedger(ledger) { ; }
@@ -174,6 +172,9 @@ public:
void clear() { mNodes.clear(); }
void swap(TransactionMetaSet&);
const uint256& getTxID() { return mTransactionID; }
uint32 getLgrSeq() { return mLedger; }
bool isNodeAffected(const uint256&) const;
TransactionMetaNode& getAffectedNode(const uint256&, int type);
const TransactionMetaNode& peekAffectedNode(const uint256&) const;