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

This commit is contained in:
jed
2013-03-08 09:46:46 -08:00
17 changed files with 202 additions and 122 deletions

View File

@@ -109,6 +109,7 @@
<ClCompile Include="src\cpp\ripple\DBInit.cpp" />
<ClCompile Include="src\cpp\ripple\DeterministicKeys.cpp" />
<ClCompile Include="src\cpp\ripple\ECIES.cpp" />
<ClCompile Include="src\cpp\ripple\FeatureTable.cpp" />
<ClCompile Include="src\cpp\ripple\FieldNames.cpp" />
<ClCompile Include="src\cpp\ripple\HashedObject.cpp" />
<ClCompile Include="src\cpp\ripple\HTTPRequest.cpp" />
@@ -295,8 +296,9 @@
<None Include="html\newcoin.html">
<SubType>Designer</SubType>
</None>
<None Include="newcoind.cfg" />
<None Include="README" />
<None Include="ripple-example.txt" />
<None Include="rippled-example.cfg" />
<None Include="SConstruct" />
<CustomBuild Include="src\cpp\ripple\ripple.proto">
<FileType>Document</FileType>
@@ -307,7 +309,7 @@
<None Include="test\server.js" />
<None Include="test\standalone-test.js" />
<None Include="test\utils.js" />
<None Include="validators.txt" />
<None Include="validators-example.txt" />
<None Include="wallet.xml" />
</ItemGroup>
<ItemGroup>

View File

@@ -26,7 +26,9 @@ Application* theApp = NULL;
DatabaseCon::DatabaseCon(const std::string& strName, const char *initStrings[], int initCount)
{
boost::filesystem::path pPath = theConfig.RUN_STANDALONE ? "" : theConfig.DATA_DIR / strName;
boost::filesystem::path pPath = (theConfig.RUN_STANDALONE && (!theConfig.START_UP != Config::LOAD))
? "" // Use temporary files.
: (theConfig.DATA_DIR / strName); // Use regular db files.
mDatabase = new SqliteDatabase(pPath.string().c_str());
mDatabase->connect();
@@ -43,7 +45,7 @@ DatabaseCon::~DatabaseCon()
Application::Application() :
mIOWork(mIOService), mAuxWork(mAuxService), mUNL(mIOService), mNetOps(mIOService, &mLedgerMaster),
mTempNodeCache("NodeCache", 16384, 90), mHashedObjectStore(16384, 300), mSLECache("LedgerEntryCache", 4096, 120),
mSNTPClient(mAuxService), mRPCHandler(&mNetOps), mFeeTrack(),
mSNTPClient(mAuxService), mFeeTrack(),
mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL),
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mWSPublicDoor(NULL), mWSPrivateDoor(NULL),
mSweepTimer(mAuxService), mShutdown(false)

View File

@@ -64,7 +64,6 @@ class Application
SLECache mSLECache;
SNTPClient mSNTPClient;
JobQueue mJobQueue;
RPCHandler mRPCHandler;
ProofOfWorkGenerator mPOWGen;
LoadManager mLoadMgr;
LoadFeeTrack mFeeTrack;
@@ -114,7 +113,6 @@ public:
ValidationCollection& getValidations() { return mValidations; }
JobQueue& getJobQueue() { return mJobQueue; }
SuppressionTable& getSuppression() { return mSuppressions; }
RPCHandler& getRPCHandler() { return mRPCHandler; }
boost::recursive_mutex& getMasterLock() { return mMasterLock; }
ProofOfWorkGenerator& getPowGen() { return mPOWGen; }
LoadManager& getLoadManager() { return mLoadMgr; }

View File

@@ -442,16 +442,23 @@ Json::Value RPCParser::parseAccountItems(const Json::Value& jvParams)
return jvRequest;
}
// ripple_path_find json
// ripple_path_find <json> [<ledger>]
Json::Value RPCParser::parseRipplePathFind(const Json::Value& jvParams)
{
Json::Value txJSON;
Json::Reader reader;
Json::Value jvRequest;
bool bLedger = 2 == jvParams.size();
cLog(lsTRACE) << "RPC json:" << jvParams[0u];
if (reader.parse(jvParams[0u].asString(), txJSON))
cLog(lsTRACE) << "RPC json: " << jvParams[0u];
if (bLedger)
{
return txJSON;
jvParseLedger(jvRequest, jvParams[1u].asString());
}
if (reader.parse(jvParams[0u].asString(), jvRequest))
{
return jvRequest;
}
return rpcError(rpcINVALID_PARAMS);
@@ -652,7 +659,7 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
{ "ping", &RPCParser::parseAsIs, 0, 0 },
// { "profile", &RPCParser::parseProfile, 1, 9 },
{ "random", &RPCParser::parseAsIs, 0, 0 },
{ "ripple_path_find", &RPCParser::parseRipplePathFind, 1, 1 },
{ "ripple_path_find", &RPCParser::parseRipplePathFind, 1, 2 },
{ "sign", &RPCParser::parseSignSubmit, 2, 2 },
{ "submit", &RPCParser::parseSignSubmit, 1, 2 },
{ "server_info", &RPCParser::parseAsIs, 0, 0 },

View File

@@ -61,14 +61,20 @@ public:
static const int lsfOutbound = 2; // outbound connection
protected:
int mBalance;
int mFlags;
int mLastUpdate;
int mLastWarning;
std::string mName;
int mBalance;
int mFlags;
int mLastUpdate;
int mLastWarning;
public:
LoadSource() : mBalance(0), mFlags(0), mLastWarning(0)
{ mLastUpdate = upTime(); }
LoadSource(bool admin) : mBalance(0), mFlags(admin ? lsfPrivileged : 0), mLastUpdate(upTime()), mLastWarning(0)
{ ; }
LoadSource(const std::string& name) : mName(name), mBalance(0), mFlags(0), mLastUpdate(upTime()), mLastWarning(0)
{ ; }
void rename(const std::string& name)
{ mName = name; }
bool isPrivileged() const { return (mFlags & lsfPrivileged) != 0; }
void setPrivileged() { mFlags |= lsfPrivileged; }

View File

@@ -38,6 +38,7 @@ TER OfferCreateTransactor::takeOffers(
cLog(lsINFO) << "takeOffers: against book: " << uBookBase.ToString();
LedgerEntrySet& lesActive = mEngine->getNodes();
uint256 uTipIndex = uBookBase;
const uint256 uBookEnd = Ledger::getQualityNext(uBookBase);
const uint64 uTakeQuality = STAmount::getRate(saTakerGets, saTakerPays);
@@ -46,7 +47,6 @@ TER OfferCreateTransactor::takeOffers(
const uint160 uTakerGetsAccountID = saTakerGets.getIssuer();
TER terResult = temUNCERTAIN;
boost::unordered_set<uint256> usOfferUnfundedFound; // Offers found unfunded.
boost::unordered_set<uint256> usOfferUnfundedBecame; // Offers that became unfunded.
boost::unordered_set<uint160> usAccountTouched; // Accounts touched.
@@ -58,7 +58,7 @@ TER OfferCreateTransactor::takeOffers(
{
SLE::pointer sleOfferDir;
uint64 uTipQuality = 0;
STAmount saTakerFunds = mEngine->getNodes().accountFunds(uTakerAccountID, saTakerPays);
STAmount saTakerFunds = lesActive.accountFunds(uTakerAccountID, saTakerPays);
STAmount saSubTakerPays = saTakerPays-saTakerPaid; // How much more to spend.
STAmount saSubTakerGets = saTakerGets-saTakerGot; // How much more is wanted.
@@ -131,7 +131,7 @@ TER OfferCreateTransactor::takeOffers(
unsigned int uBookEntry;
uint256 uOfferIndex;
mEngine->getNodes().dirFirst(uTipIndex, sleBookNode, uBookEntry, uOfferIndex);
lesActive.dirFirst(uTipIndex, sleBookNode, uBookEntry, uOfferIndex);
SLE::pointer sleOffer = mEngine->entryCache(ltOFFER, uOfferIndex);
@@ -153,7 +153,7 @@ TER OfferCreateTransactor::takeOffers(
// Would take own offer. Consider old offer expired. Delete it.
cLog(lsINFO) << "takeOffers: encountered taker's own old offer";
usOfferUnfundedFound.insert(uOfferIndex);
usOfferUnfundedBecame.insert(uOfferIndex);
}
else if (!saOfferGets.isPositive() || !saOfferPays.isPositive())
{
@@ -169,7 +169,7 @@ TER OfferCreateTransactor::takeOffers(
cLog(lsINFO) << "takeOffers: saOfferPays=" << saOfferPays.getFullText();
STAmount saOfferFunds = mEngine->getNodes().accountFunds(uOfferOwnerID, saOfferPays);
STAmount saOfferFunds = lesActive.accountFunds(uOfferOwnerID, saOfferPays);
SLE::pointer sleOfferAccount; // Owner of offer.
if (!saOfferFunds.isPositive()) // Includes zero.
@@ -210,8 +210,8 @@ TER OfferCreateTransactor::takeOffers(
cLog(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText();
bool bOfferDelete = STAmount::applyOffer(
mEngine->getNodes().rippleTransferRate(uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID),
mEngine->getNodes().rippleTransferRate(uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID),
lesActive.rippleTransferRate(uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID),
lesActive.rippleTransferRate(uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID),
saOfferRate,
saOfferFunds,
saTakerFunds,
@@ -274,10 +274,10 @@ TER OfferCreateTransactor::takeOffers(
{
// Distribute funds. The sends charge appropriate fees which are implied by offer.
terResult = mEngine->getNodes().accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); // Offer owner pays taker.
terResult = lesActive.accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); // Offer owner pays taker.
if (tesSUCCESS == terResult)
terResult = mEngine->getNodes().accountSend(uTakerAccountID, uOfferOwnerID, saSubTakerPaid); // Taker pays offer owner.
terResult = lesActive.accountSend(uTakerAccountID, uOfferOwnerID, saSubTakerPaid); // Taker pays offer owner.
// Reduce amount considered paid by taker's rate (not actual cost).
STAmount saTakerCould = saTakerPays - saTakerPaid; // Taker could pay.
@@ -304,20 +304,6 @@ TER OfferCreateTransactor::takeOffers(
cLog(lsINFO) << "takeOffers: " << transToken(terResult);
// On storing meta data, delete offers that were found unfunded to prevent encountering them in future.
if (tesSUCCESS == terResult)
{
BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedFound)
{
cLog(lsINFO) << "takeOffers: found unfunded: " << uOfferIndex.ToString();
terResult = mEngine->getNodes().offerDelete(uOfferIndex);
if (tesSUCCESS != terResult)
break;
}
}
if (tesSUCCESS == terResult)
{
// On success, delete offers that became unfunded.
@@ -325,7 +311,7 @@ TER OfferCreateTransactor::takeOffers(
{
cLog(lsINFO) << "takeOffers: became unfunded: " << uOfferIndex.ToString();
terResult = mEngine->getNodes().offerDelete(uOfferIndex);
terResult = lesActive.offerDelete(uOfferIndex);
if (tesSUCCESS != terResult)
break;
}
@@ -369,6 +355,12 @@ TER OfferCreateTransactor::doApply()
uint64 uOwnerNode;
uint64 uBookNode;
LedgerEntrySet& lesActive = mEngine->getNodes();
LedgerEntrySet lesCheckpoint = lesActive; // Checkpoint with just fees paid.
lesActive.bumpSeq(); // Begin ledger variance.
SLE::pointer sleCreator = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(mTxnAccountID));
if (uTxFlags & tfOfferCreateMask)
{
cLog(lsINFO) << "OfferCreate: Malformed transaction: Invalid flags set.";
@@ -417,7 +409,7 @@ TER OfferCreateTransactor::doApply()
terResult = temBAD_ISSUER;
}
else if (!mEngine->getNodes().accountFunds(mTxnAccountID, saTakerGets).isPositive())
else if (!lesActive.accountFunds(mTxnAccountID, saTakerGets).isPositive())
{
cLog(lsWARNING) << "OfferCreate: delay: Offers must be at least partially funded.";
@@ -458,7 +450,7 @@ TER OfferCreateTransactor::doApply()
bPassive,
uTakeBookBase,
mTxnAccountID,
mTxnAccount,
sleCreator,
saTakerGets, // Reverse as we are the taker for taking.
saTakerPays,
saPaid, // How much would have spent at full price.
@@ -482,7 +474,7 @@ TER OfferCreateTransactor::doApply()
cLog(lsWARNING) << "OfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText();
cLog(lsWARNING) << "OfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText();
cLog(lsWARNING) << "OfferCreate: takeOffers: mTxnAccountID=" << RippleAddress::createHumanAccountID(mTxnAccountID);
cLog(lsWARNING) << "OfferCreate: takeOffers: FUNDS=" << mEngine->getNodes().accountFunds(mTxnAccountID, saTakerGets).getFullText();
cLog(lsWARNING) << "OfferCreate: takeOffers: FUNDS=" << lesActive.accountFunds(mTxnAccountID, saTakerGets).getFullText();
// cLog(lsWARNING) << "OfferCreate: takeOffers: uPaysIssuerID=" << RippleAddress::createHumanAccountID(uPaysIssuerID);
// cLog(lsWARNING) << "OfferCreate: takeOffers: uGetsIssuerID=" << RippleAddress::createHumanAccountID(uGetsIssuerID);
@@ -500,19 +492,19 @@ TER OfferCreateTransactor::doApply()
else if (bFillOrKill && (saTakerPays || saTakerGets))
{
// Fill or kill and have leftovers.
terResult = tecKILL;
lesActive.swapWith(lesCheckpoint); // Restore with just fees paid.
}
else if (
!saTakerPays // Wants nothing more.
|| !saTakerGets // Offering nothing more.
|| bImmediateOrCancel // Do not persist.
|| !mEngine->getNodes().accountFunds(mTxnAccountID, saTakerGets).isPositive() // Not funded.
|| bImmediateOrCancel // Do not persist.
|| !lesActive.accountFunds(mTxnAccountID, saTakerGets).isPositive() // Not funded.
|| bUnfunded) // Consider unfunded.
{
// Complete as is.
nothing();
}
else if (mPriorBalance.getNValue() < mEngine->getLedger()->getReserve(mTxnAccount->getFieldU32(sfOwnerCount)+1))
else if (mPriorBalance.getNValue() < mEngine->getLedger()->getReserve(sleCreator->getFieldU32(sfOwnerCount)+1))
{
if (bOpenLedger) // Ledger is not final, can vote no.
{
@@ -541,14 +533,14 @@ TER OfferCreateTransactor::doApply()
% saTakerGets.getFullText());
// Add offer to owner's directory.
terResult = mEngine->getNodes().dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex,
terResult = lesActive.dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex,
boost::bind(&Ledger::qualityDirDescriber, _1, saTakerPays.getCurrency(), uPaysIssuerID,
saTakerGets.getCurrency(), uGetsIssuerID, uRate));
if (tesSUCCESS == terResult)
{
mEngine->getNodes().ownerCountAdjust(mTxnAccountID, 1, mTxnAccount); // Update owner count.
lesActive.ownerCountAdjust(mTxnAccountID, 1, sleCreator); // Update owner count.
uint256 uBookBase = Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID);
@@ -562,7 +554,7 @@ TER OfferCreateTransactor::doApply()
uDirectory = Ledger::getQualityIndex(uBookBase, uRate); // Use original rate.
// Add offer to order book.
terResult = mEngine->getNodes().dirAdd(uBookNode, uDirectory, uLedgerIndex,
terResult = lesActive.dirAdd(uBookNode, uDirectory, uLedgerIndex,
boost::bind(&Ledger::qualityDirDescriber, _1, saTakerPays.getCurrency(), uPaysIssuerID,
saTakerGets.getCurrency(), uGetsIssuerID, uRate));
}
@@ -599,6 +591,20 @@ TER OfferCreateTransactor::doApply()
}
}
// On storing meta data, delete offers that were found unfunded to prevent encountering them in future.
if (tesSUCCESS == terResult)
{
BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedFound)
{
cLog(lsINFO) << "takeOffers: found unfunded: " << uOfferIndex.ToString();
terResult = lesActive.offerDelete(uOfferIndex);
if (tesSUCCESS != terResult)
break;
}
}
tLog(tesSUCCESS != terResult, lsINFO) << boost::str(boost::format("OfferCreate: final terResult=%s") % transToken(terResult));
if (isTesSuccess(terResult))

View File

@@ -5,6 +5,7 @@
class OfferCreateTransactor : public Transactor
{
protected:
TER takeOffers(
const bool bOpenLedger,
const bool bPassive,
@@ -17,6 +18,8 @@ class OfferCreateTransactor : public Transactor
STAmount& saTakerGot,
bool& bUnfunded);
boost::unordered_set<uint256> usOfferUnfundedFound; // Offers found unfunded.
public:
OfferCreateTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : Transactor(txn,params,engine) {}
TER doApply();

View File

@@ -34,6 +34,8 @@ Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx,
mActive(2),
mCluster(false),
mPeerId(peerID),
mPrivate(false),
mLoad(""),
mSocketSsl(io_service, ctx),
mActivityTimer(io_service)
{
@@ -77,6 +79,7 @@ void Peer::handleWrite(const boost::system::error_code& error, size_t bytes_tran
void Peer::setIpPort(const std::string& strIP, int iPort)
{
mIpPort = make_pair(strIP, iPort);
mLoad.rename(strIP);
cLog(lsDEBUG) << "Peer: Set: "
<< ADDRESS(this) << "> "

View File

@@ -63,12 +63,13 @@ int iAdminGet(const Json::Value& jvRequest, const std::string& strRemoteIp)
return iRole;
}
RPCHandler::RPCHandler(NetworkOPs* netOps)
RPCHandler::RPCHandler(NetworkOPs* netOps, LoadSource &ls) : mLoadSource(ls)
{
mNetOps = netOps;
}
RPCHandler::RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub) : mInfoSub(infoSub)
RPCHandler::RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub, LoadSource& ls)
: mInfoSub(infoSub), mLoadSource(ls)
{
mNetOps = netOps;
}
@@ -885,7 +886,6 @@ Json::Value RPCHandler::doAccountLines(Json::Value jvRequest)
if (!lpLedger)
return jvResult;
if (!jvRequest.isMember("account"))
return rpcError(rpcINVALID_PARAMS);
@@ -1153,10 +1153,14 @@ Json::Value RPCHandler::doRandom(Json::Value jvRequest)
// - From a trusted server, allows clients to use path without manipulation.
Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest)
{
Json::Value jvResult(Json::objectValue);
RippleAddress raSrc;
RippleAddress raDst;
STAmount saDstAmount;
Ledger::pointer lpLedger;
Json::Value jvResult = lookupLedger(jvRequest, lpLedger);
if (!lpLedger)
return jvResult;
if (theApp->getJobQueue().getJobCountGE(jtCLIENT) > 200)
{
@@ -1201,7 +1205,6 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest)
}
else
{
Ledger::pointer lpCurrent = mNetOps->getCurrentLedger();
Json::Value jvSrcCurrencies;
if (jvRequest.isMember("source_currencies"))
@@ -1210,7 +1213,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest)
}
else
{
boost::unordered_set<uint160> usCurrencies = usAccountSourceCurrencies(raSrc, lpCurrent);
boost::unordered_set<uint160> usCurrencies = usAccountSourceCurrencies(raSrc, lpLedger);
// Add XRP as a source currency.
// YYY Only bother if they are above reserve.
@@ -1228,7 +1231,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest)
}
}
Ledger::pointer lSnapShot = boost::make_shared<Ledger>(boost::ref(*lpCurrent), false);
Ledger::pointer lSnapShot = boost::make_shared<Ledger>(boost::ref(*lpLedger), false);
LedgerEntrySet lesSnapshot(lSnapShot);
ScopedUnlock su(theApp->getMasterLock()); // As long as we have a locked copy of the ledger, we can unlock.
@@ -2020,7 +2023,7 @@ Json::Value RPCHandler::doGetCounts(Json::Value jvRequest)
int s = upTime();
textTime(uptime, s, "year", 365*24*60*60);
textTime(uptime, s, "day", 24*60*60);
textTime(uptime, s, "hour", 24*60);
textTime(uptime, s, "hour", 60*60);
textTime(uptime, s, "minute", 60);
textTime(uptime, s, "second", 1);
ret["uptime"] = uptime;

View File

@@ -18,6 +18,7 @@ class RPCHandler
NetworkOPs* mNetOps;
InfoSub::pointer mInfoSub;
int mRole;
LoadSource& mLoadSource;
typedef Json::Value (RPCHandler::*doFuncPtr)(Json::Value params);
enum {
@@ -113,8 +114,8 @@ public:
enum { GUEST, USER, ADMIN, FORBID };
RPCHandler(NetworkOPs* netOps);
RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub);
RPCHandler(NetworkOPs* netOps, LoadSource&);
RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub, LoadSource&);
Json::Value doCommand(const Json::Value& jvRequest, int role);
Json::Value doRpcCommand(const std::string& strCommand, Json::Value& jvParams, int iRole);

View File

@@ -24,7 +24,7 @@ SETUP_LOG();
#endif
RPCServer::RPCServer(boost::asio::io_service& io_service , NetworkOPs* nopNetwork)
: mNetOps(nopNetwork), mSocket(io_service)
: mNetOps(nopNetwork), mLoadSource("rpc"), mSocket(io_service)
{
mRole = RPCHandler::GUEST;
}
@@ -51,7 +51,7 @@ void RPCServer::handle_read_req(const boost::system::error_code& e)
if (!HTTPAuthorized(mHTTPRequest.peekHeaders()))
mReplyStr = HTTPReply(403, "Forbidden");
else
mReplyStr = handleRequest(req);
mReplyStr = handleRequest(req, mLoadSource);
boost::asio::async_write(mSocket, boost::asio::buffer(mReplyStr),
boost::bind(&RPCServer::handle_write, shared_from_this(), boost::asio::placeholders::error));
@@ -110,7 +110,7 @@ void RPCServer::handle_read_line(const boost::system::error_code& e)
}
}
std::string RPCServer::handleRequest(const std::string& requestStr)
std::string RPCServer::handleRequest(const std::string& requestStr, LoadSource& ls)
{
cLog(lsTRACE) << "handleRequest " << requestStr;
@@ -154,7 +154,7 @@ std::string RPCServer::handleRequest(const std::string& requestStr)
return HTTPReply(403, "Forbidden");
}
RPCHandler mRPCHandler(mNetOps);
RPCHandler mRPCHandler(mNetOps, mLoadSource);
cLog(lsTRACE) << valParams;
Json::Value result = mRPCHandler.doRpcCommand(strMethod, valParams, mRole);

View File

@@ -13,6 +13,7 @@
#include "NetworkOPs.h"
#include "SerializedLedger.h"
#include "RPCHandler.h"
#include "LoadManager.h"
class RPCServer : public boost::enable_shared_from_this<RPCServer>
{
@@ -23,6 +24,7 @@ public:
private:
NetworkOPs* mNetOps;
LoadSource mLoadSource;
boost::asio::ip::tcp::socket mSocket;
@@ -44,7 +46,7 @@ private:
void handle_read_line(const boost::system::error_code& ec);
void handle_read_req(const boost::system::error_code& ec);
std::string handleRequest(const std::string& requestStr);
std::string handleRequest(const std::string& requestStr, LoadSource& ls);
public:
static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps)

View File

@@ -1,7 +1,7 @@
// TODO:
// - Do automatic bridging via XRP.
//
// OPTIMIZE: When calculating path increment, note if increment consumes all liquidity. No need to revesit path in the future if
// OPTIMIZE: When calculating path increment, note if increment consumes all liquidity. No need to revisit path in the future if
// all liquidity is used.
//
@@ -270,7 +270,7 @@ TER PathState::pushNode(
// Insert intermediary issuer account if needed.
terResult = pushImply(
ACCOUNT_XRP, // Rippling, but offer's don't have an account.
ACCOUNT_XRP, // Rippling, but offers don't have an account.
pnPrv.uCurrencyID,
pnPrv.uIssuerID);
}
@@ -384,7 +384,7 @@ void PathState::setExpanded(
if (tesSUCCESS == terStatus
&& !!uOutCurrencyID // Next is not XRP
&& uOutIssuerID != uReceiverID // Out issuer is not reciever
&& uOutIssuerID != uReceiverID // Out issuer is not receiver
&& (pnPrv.uCurrencyID != uOutCurrencyID // Previous will be an offer.
|| pnPrv.uAccountID != uOutIssuerID)) // Need the implied issuer.
{
@@ -427,12 +427,7 @@ void PathState::setExpanded(
{
const PaymentNode& pnCur = vpnNodes[uNode];
if (!!pnCur.uAccountID)
{
// Source is a ripple line
nothing();
}
else if (!umForward.insert(std::make_pair(boost::make_tuple(pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uNode)).second)
if (!umForward.insert(std::make_pair(boost::make_tuple(pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uNode)).second)
{
// Failed to insert. Have a loop.
cLog(lsDEBUG) << boost::str(boost::format("PathState: loop detected: %s")
@@ -472,7 +467,7 @@ void PathState::setExpanded(
// Optimization:
// - An XRP output implies an offer node or destination node is next.
// - A change in currency implies an offer node.
// - A change in issuer...
// - A change in issuer...
void PathState::setCanonical(
const PathState& psExpanded
)
@@ -496,7 +491,7 @@ void PathState::setCanonical(
uint160 uCurrencyID = uMaxCurrencyID;
uint160 uIssuerID = uMaxIssuerID;
// Node 0 is a composit of the sending account and saInAct.
// Node 0 is a composite of the sending account and saInAct.
++uNode; // skip node 0
// Last node is implied: Always skip last node
@@ -829,8 +824,8 @@ TER RippleCalc::calcNodeAdvance(
uDirectEnd = Ledger::getQualityNext(uDirectTip);
sleDirectDir = lesActive.entryCache(ltDIR_NODE, uDirectTip);
bDirectAdvance = !sleDirectDir;
bDirectDirDirty = true;
bDirectDirDirty = !!sleDirectDir; // Associated vars are dirty, if found it.
bDirectAdvance = !sleDirectDir; // Advance, if didn't find it. Normal not to be unable to lookup firstdirectory. Maybe even skip this lookup.
cLog(lsTRACE) << boost::str(boost::format("calcNodeAdvance: Initialize node: uDirectTip=%s uDirectEnd=%s bDirectAdvance=%d") % uDirectTip % uDirectEnd % bDirectAdvance);
}
@@ -879,6 +874,7 @@ TER RippleCalc::calcNodeAdvance(
{
if (bFundsDirty)
{
// We were called again probably merely to update structure variables.
saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
@@ -897,22 +893,27 @@ TER RippleCalc::calcNodeAdvance(
{
// Failed to find an entry in directory.
uOfferIndex = 0;
// Do another cur directory iff bMultiQuality
if (bMultiQuality)
{
// We are allowed to process multiple qualities if this is the only path.
cLog(lsTRACE) << boost::str(boost::format("calcNodeAdvance: next quality"));
bDirectAdvance = true;
bDirectAdvance = true; // Process next quality.
}
else if (!bReverse)
{
cLog(lsWARNING) << boost::str(boost::format("calcNodeAdvance: unreachable: ran out of offers"));
assert(false); // Can't run out of offers in forward direction.
terResult = tefEXCEPTION;
terResult = tefEXCEPTION;
}
else
bEntryAdvance = false;
{
// Ran off end of offers.
bEntryAdvance = false; // Done.
uOfferIndex = 0; // Report nore more entries.
}
}
else
{
@@ -932,20 +933,38 @@ TER RippleCalc::calcNodeAdvance(
cLog(lsTRACE) << "calcNodeAdvance: expired offer";
assert(musUnfundedFound.find(uOfferIndex) != musUnfundedFound.end()); // Verify reverse found it too.
bEntryAdvance = true;
// Just skip it. It will be deleted.
// bEntryAdvance = true; // Already set
continue;
}
else if (!saTakerPays.isPositive() || !saTakerGets.isPositive())
{
// Offer is has bad amounts.
cLog(lsWARNING) << boost::str(boost::format("calcNodeAdvance: NON-POSITIVE: saTakerPays=%s saTakerGets=%s")
% saTakerPays % saTakerGets);
// Offer has bad amounts. Offers should never have a bad amounts.
// assert(musUnfundedFound.find(uOfferIndex) != musUnfundedFound.end()); // Verify reverse found it too.
bEntryAdvance = true;
if (musUnfundedFound.find(uOfferIndex) != musUnfundedFound.end())
{
// An internal error, offer was found failed to place this in musUnfundedFound.
cLog(lsWARNING) << boost::str(boost::format("calcNodeAdvance: PAST INTERNAL ERROR: OFFER NON-POSITIVE: saTakerPays=%s saTakerGets=%s")
% saTakerPays % saTakerGets);
// Just skip it. It will be deleted.
// bEntryAdvance = true; // Already set
}
else
{
// Reverse should have previously put bad offer in list.
// An internal error previously left a bad offer.
cLog(lsWARNING) << boost::str(boost::format("calcNodeAdvance: INTERNAL ERROR: OFFER NON-POSITIVE: saTakerPays=%s saTakerGets=%s")
% saTakerPays % saTakerGets);
//assert(false);
// Don't process at all, things are in an unexpected state for this transactions.
terResult = tefEXCEPTION;
}
continue;
}
bEntryAdvance = false;
// Allowed to access source from this node?
// XXX This can get called multiple times for same source in a row, caching result would be nice.
// XXX Going forward could we fund something with a worse quality which was previously skipped? Might need to check
@@ -953,6 +972,8 @@ TER RippleCalc::calcNodeAdvance(
curIssuerNodeConstIterator itForward = psCur.umForward.find(asLine);
const bool bFoundForward = itForward != psCur.umForward.end();
// Only a allow a source to be used once, in the first node encountered from initial path scan.
// This prevents conflicting uses of the same balance when going reverse vs forward.
if (bFoundForward && itForward->second != uNode)
{
// Temporarily unfunded. Another node uses this source, ignore in this offer.
@@ -962,21 +983,12 @@ TER RippleCalc::calcNodeAdvance(
continue;
}
curIssuerNodeConstIterator itPast = mumSource.find(asLine);
bool bFoundPast = itPast != mumSource.end();
if (bFoundPast && itPast->second != uNode)
{
// Temporarily unfunded. Another node uses this source, ignore in this offer.
cLog(lsTRACE) << "calcNodeAdvance: temporarily unfunded offer (past)";
bEntryAdvance = true;
continue;
}
// This is overly strict. For contributions to past. We should only count source if actually used.
curIssuerNodeConstIterator itReverse = psCur.umReverse.find(asLine);
bool bFoundReverse = itReverse != psCur.umReverse.end();
// For this quality increment, only allow a source to be used from a single node, in the first node encountered from applying offers
// in reverse.
if (bFoundReverse && itReverse->second != uNode)
{
// Temporarily unfunded. Another node uses this source, ignore in this offer.
@@ -986,7 +998,23 @@ TER RippleCalc::calcNodeAdvance(
continue;
}
saOfferFunds = lesActive.accountFunds(uOfrOwnerID, saTakerGets); // Funds left.
curIssuerNodeConstIterator itPast = mumSource.find(asLine);
bool bFoundPast = itPast != mumSource.end();
// Determine if used in past.
// XXX Restriction seems like a misunderstanding.
if (bFoundPast && itPast->second != uNode)
{
// Temporarily unfunded. Another node uses this source, ignore in this offer.
cLog(lsTRACE) << "calcNodeAdvance: temporarily unfunded offer (past)";
bEntryAdvance = true;
continue;
}
// Only the current node is allowed to use the source.
saOfferFunds = lesActive.accountFunds(uOfrOwnerID, saTakerGets); // Funds held.
if (!saOfferFunds.isPositive())
{
@@ -995,9 +1023,17 @@ TER RippleCalc::calcNodeAdvance(
if (bReverse && !bFoundReverse && !bFoundPast)
{
// Never mentioned before: found unfunded.
// Never mentioned before, clearly just: found unfunded.
// That is, even if this offer fails due to fill or kill still do deletions.
musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion.
}
else
{
// Moving forward, don't need to check again.
// Or source was used this reverse
// Or source was previously used
// XXX
}
// YYY Could verify offer is correct place for unfundeds.
bEntryAdvance = true;
@@ -1301,9 +1337,16 @@ TER RippleCalc::calcNodeDeliverFwd(
saInAct.zero(saInReq);
saInFees.zero(saInReq);
int loopCount = 0;
while (tesSUCCESS == terResult
&& saInAct + saInFees != saInReq) // Did not deliver all funds.
{
if (++loopCount > 40)
{
cLog(lsWARNING) << "max loops cndf";
return mOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING;
}
// Determine values for pass to adjust saInAct, saInFees, and saCurDeliverAct
terResult = calcNodeAdvance(uNode, psCur, bMultiQuality, false); // If needed, advance to next funded offer.
@@ -2427,7 +2470,7 @@ void RippleCalc::pathNext(PathState::ref psrCur, const bool bMultiQuality, const
assert(psrCur->vpnNodes.size() >= 2);
lesCurrent = lesCheckpoint; // Restore from checkpoint.
lesCurrent.bumpSeq(); // Begin ledger varance.
lesCurrent.bumpSeq(); // Begin ledger variance.
psrCur->terStatus = calcNodeRev(uLast, *psrCur, bMultiQuality);
@@ -2437,7 +2480,7 @@ void RippleCalc::pathNext(PathState::ref psrCur, const bool bMultiQuality, const
{
// Do forward.
lesCurrent = lesCheckpoint; // Restore from checkpoint.
lesCurrent.bumpSeq(); // Begin ledger varance.
lesCurrent.bumpSeq(); // Begin ledger variance.
psrCur->terStatus = calcNodeFwd(0, *psrCur, bMultiQuality);
}
@@ -2895,7 +2938,7 @@ void TransactionEngine::calcOfferBridgeNext(
{
// Offer fully funded.
// Account transfering funds in to offer always pays inbound fees.
// Account transferring funds in to offer always pays inbound fees.
saOfferIn = saOfferGets; // XXX Add in fees?
@@ -2934,26 +2977,26 @@ void TransactionEngine::calcOfferBridgeNext(
// - reverse: prv is maximum to pay in (including fee) - cur is what is wanted: generally, minimizing prv
// - forward: prv is actual amount to pay in (including fee) - cur is what is wanted: generally, minimizing cur
// Value in is may be rippled or credited from limbo. Value out is put in limbo.
// If next is an offer, the amount needed is in cur reedem.
// If next is an offer, the amount needed is in cur redeem.
// XXX What about account mentioned multiple times via offers?
void TransactionEngine::calcNodeOffer(
bool bForward,
bool bMultiQuality, // True, if this is the only active path: we can do multiple qualities in this pass.
const uint160& uPrvAccountID, // If 0, then funds from previous offer's limbo
const uint160& uPrvAccountID, // If 0, then funds from previous offers limbo
const uint160& uPrvCurrencyID,
const uint160& uPrvIssuerID,
const uint160& uCurCurrencyID,
const uint160& uCurIssuerID,
const STAmount& uPrvRedeemReq, // --> In limit.
STAmount& uPrvRedeemAct, // <-> In limit achived.
STAmount& uPrvRedeemAct, // <-> In limit achieved.
const STAmount& uCurRedeemReq, // --> Out limit. Driver when uCurIssuerID == uNxtIssuerID (offer would redeem to next)
STAmount& uCurRedeemAct, // <-> Out limit achived.
STAmount& uCurRedeemAct, // <-> Out limit achieved.
const STAmount& uCurIssueReq, // --> In limit.
STAmount& uCurIssueAct, // <-> In limit achived.
STAmount& uCurIssueAct, // <-> In limit achieved.
const STAmount& uCurIssueReq, // --> Out limit. Driver when uCurIssueReq != uNxtIssuerID (offer would effectively issue or transfer to next)
STAmount& uCurIssueAct, // <-> Out limit achived.
STAmount& uCurIssueAct, // <-> Out limit achieved.
STAmount& saPay,
STAmount& saGot
@@ -3007,13 +3050,13 @@ void TransactionEngine::calcNodeOffer(
bool bRedeeming = false;
bool bIssuing = false;
// The price varies as we change between issuing and transfering, so unless bMultiQuality, we must stick with a mode once it
// The price varies as we change between issuing and transferring, so unless bMultiQuality, we must stick with a mode once it
// is determined.
if (bBridge && (bInNext || bOutNext))
{
// Bridging and need to calculate next bridge rate.
// A bridge can consist of multiple offers. As offer's are consumed, the effective rate changes.
// A bridge can consist of multiple offers. As offers are consumed, the effective rate changes.
if (bInNext)
{

View File

@@ -123,7 +123,6 @@ enum TER // aka TransactionEngineResult
tecUNFUNDED_OFFER = 103,
tecUNFUNDED_PAYMENT = 104,
tecFAILED_PROCESSING = 105,
tecKILL = 106, // tesSUCCESS is not retryable.
tecDIR_FULL = 121,
tecINSUF_RESERVE_LINE = 122,
tecINSUF_RESERVE_OFFER = 123,

View File

@@ -14,6 +14,7 @@
#include "CallRPC.h"
#include "InstanceCounter.h"
#include "Log.h"
#include "LoadManager.h"
#include "RPCErr.h"
DEFINE_INSTANCE(WebSocketConnection);
@@ -45,6 +46,7 @@ protected:
weak_connection_ptr mConnection;
NetworkOPs& mNetwork;
std::string mRemoteIP;
LoadSource mLoadSource;
boost::asio::deadline_timer mPingTimer;
bool mPinged;
@@ -56,9 +58,9 @@ public:
WSConnection(WSServerHandler<endpoint_type>* wshpHandler, const connection_ptr& cpConnection)
: mHandler(wshpHandler), mConnection(cpConnection), mNetwork(theApp->getOPs()),
mPingTimer(cpConnection->get_io_service()), mPinged(false)
mRemoteIP(cpConnection->get_socket().lowest_layer().remote_endpoint().address().to_string()),
mLoadSource(mRemoteIP), mPingTimer(cpConnection->get_io_service()), mPinged(false)
{
mRemoteIP = cpConnection->get_socket().lowest_layer().remote_endpoint().address().to_string();
cLog(lsDEBUG) << "Websocket connection from " << mRemoteIP;
setPingTimer();
}
@@ -103,7 +105,8 @@ public:
return jvResult;
}
RPCHandler mRPCHandler(&mNetwork, boost::shared_polymorphic_downcast<InfoSub>(this->shared_from_this()));
RPCHandler mRPCHandler(&mNetwork,
boost::shared_polymorphic_downcast<InfoSub>(this->shared_from_this()), mLoadSource);
Json::Value jvResult(Json::objectValue);
int iRole = mHandler->getPublic()

View File

@@ -43,7 +43,8 @@ void startServer()
if (!theConfig.QUIET)
std::cerr << "Startup RPC: " << jvCommand << std::endl;
RPCHandler rhHandler(&theApp->getOPs());
LoadSource ls(true);
RPCHandler rhHandler(&theApp->getOPs(), ls);
Json::Value jvResult = rhHandler.doCommand(jvCommand, RPCHandler::ADMIN);
@@ -92,6 +93,7 @@ void printHelp(const po::options_description& desc)
cerr << " peers" << endl;
cerr << " random" << endl;
cerr << " ripple ..." << endl;
cerr << " ripple_path_find <json> [<ledger>]" << endl;
// cerr << " send <seed> <paying_account> <account_id> <amount> [<currency>] [<send_max>] [<send_currency>]" << endl;
cerr << " stop" << endl;
cerr << " tx <id>" << endl;