mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-26 00:20:41 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin into new_pathfinding
This commit is contained in:
@@ -196,11 +196,18 @@ uint64 SqliteDatabase::getBigInt(int colIndex)
|
||||
return(sqlite3_column_int64(mCurrentStmt, colIndex));
|
||||
}
|
||||
|
||||
int SqliteDatabase::getKBUsed()
|
||||
int SqliteDatabase::getKBUsedAll()
|
||||
{
|
||||
return static_cast<int>(sqlite3_memory_used() / 1024);
|
||||
}
|
||||
|
||||
int SqliteDatabase::getKBUsedDB()
|
||||
{
|
||||
int cur = 0, hiw = 0;
|
||||
sqlite3_db_status(mConnection, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiw, 0);
|
||||
return cur / 1024;
|
||||
}
|
||||
|
||||
static int SqliteWALHook(void *s, sqlite3* dbCon, const char *dbName, int walSize)
|
||||
{
|
||||
(reinterpret_cast<SqliteDatabase*>(s))->doHook(dbName, walSize);
|
||||
|
||||
@@ -58,7 +58,8 @@ public:
|
||||
void runWal();
|
||||
void doHook(const char *db, int walSize);
|
||||
|
||||
int getKBUsed();
|
||||
int getKBUsedDB();
|
||||
int getKBUsedAll();
|
||||
};
|
||||
|
||||
class SqliteStatement
|
||||
|
||||
@@ -89,7 +89,8 @@ public:
|
||||
|
||||
virtual bool setupCheckpointing(JobQueue*) { return false; }
|
||||
virtual SqliteDatabase* getSqliteDB() { return NULL; }
|
||||
virtual int getKBUsed() { return -1; }
|
||||
virtual int getKBUsedAll() { return -1; }
|
||||
virtual int getKBUsedDB() { return -1; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,12 +32,14 @@ static void canonicalizeRound(bool isNative, uint64& value, int& offset, bool ro
|
||||
{
|
||||
if (offset < 0)
|
||||
{
|
||||
int loops = 0;
|
||||
while (offset < -1)
|
||||
{
|
||||
value /= 10;
|
||||
++offset;
|
||||
++loops;
|
||||
}
|
||||
value += 10; // add before last divide
|
||||
value += (loops >= 2) ? 9 : 10; // add before last divide
|
||||
value /= 10;
|
||||
++offset;
|
||||
}
|
||||
@@ -294,6 +296,10 @@ BOOST_AUTO_TEST_SUITE(amountRound)
|
||||
|
||||
BOOST_AUTO_TEST_CASE( amountRound_test )
|
||||
{
|
||||
uint64 value = 25000000000000000ull;
|
||||
int offset = -14;
|
||||
canonicalizeRound(false, value, offset, true);
|
||||
|
||||
STAmount one(CURRENCY_ONE, ACCOUNT_ONE, 1);
|
||||
STAmount two(CURRENCY_ONE, ACCOUNT_ONE, 2);
|
||||
STAmount three(CURRENCY_ONE, ACCOUNT_ONE, 3);
|
||||
|
||||
@@ -24,8 +24,11 @@ LogPartition TaggedCachePartition("TaggedCache");
|
||||
LogPartition AutoSocketPartition("AutoSocket");
|
||||
Application* theApp = NULL;
|
||||
|
||||
int DatabaseCon::sCount = 0;
|
||||
|
||||
DatabaseCon::DatabaseCon(const std::string& strName, const char *initStrings[], int initCount)
|
||||
{
|
||||
++sCount;
|
||||
boost::filesystem::path pPath = (theConfig.RUN_STANDALONE && (theConfig.START_UP != Config::LOAD))
|
||||
? "" // Use temporary files.
|
||||
: (theConfig.DATA_DIR / strName); // Use regular db files.
|
||||
@@ -63,6 +66,7 @@ bool Instance::running = true;
|
||||
void Application::stop()
|
||||
{
|
||||
cLog(lsINFO) << "Received shutdown request";
|
||||
StopSustain();
|
||||
mShutdown = true;
|
||||
mIOService.stop();
|
||||
mHashedObjectStore.bulkWrite();
|
||||
@@ -88,6 +92,12 @@ void sigIntHandler(int)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void runAux(boost::asio::io_service& svc)
|
||||
{
|
||||
NameThread("aux");
|
||||
svc.run();
|
||||
}
|
||||
|
||||
void Application::setup()
|
||||
{
|
||||
mJobQueue.setThreadCount();
|
||||
@@ -115,7 +125,7 @@ void Application::setup()
|
||||
LogPartition::setSeverity(lsDEBUG);
|
||||
}
|
||||
|
||||
boost::thread(boost::bind(&boost::asio::io_service::run, &mAuxService)).detach();
|
||||
boost::thread(boost::bind(runAux, boost::ref(mAuxService))).detach();
|
||||
|
||||
if (!theConfig.RUN_STANDALONE)
|
||||
mSNTPClient.init(theConfig.SNTP_SERVERS);
|
||||
@@ -178,6 +188,13 @@ void Application::setup()
|
||||
mLedgerMaster.tune(theConfig.getSize(siLedgerSize), theConfig.getSize(siLedgerAge));
|
||||
mLedgerMaster.setMinValidations(theConfig.VALIDATION_QUORUM);
|
||||
|
||||
theApp->getHashNodeDB()->getDB()->executeSQL(boost::str(boost::format("PRAGMA cache_size=-%d;") %
|
||||
(theConfig.getSize(siHashNodeDBCache) * 1024)));
|
||||
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(boost::format("PRAGMA cache_size=-%d;") %
|
||||
(theConfig.getSize(siTxnDBCache) * 1024)));
|
||||
theApp->getTxnDB()->getDB()->executeSQL(boost::str(boost::format("PRAGMA cache_size=-%d;") %
|
||||
(theConfig.getSize(siLgrDBCache) * 1024)));
|
||||
|
||||
//
|
||||
// Allow peer connections.
|
||||
//
|
||||
|
||||
@@ -36,12 +36,14 @@ class DatabaseCon
|
||||
protected:
|
||||
Database* mDatabase;
|
||||
boost::recursive_mutex mLock;
|
||||
static int sCount;
|
||||
|
||||
public:
|
||||
DatabaseCon(const std::string& name, const char *initString[], int countInit);
|
||||
~DatabaseCon();
|
||||
Database* getDB() { return mDatabase; }
|
||||
boost::recursive_mutex& getDBLock() { return mLock; }
|
||||
Database* getDB() { return mDatabase; }
|
||||
boost::recursive_mutex& getDBLock() { return mLock; }
|
||||
static int getCount() { return sCount; }
|
||||
};
|
||||
|
||||
class Application
|
||||
|
||||
@@ -65,19 +65,11 @@ std::string EncodeBase64(const std::string& s)
|
||||
// TODO New routine for parsing ledger parameters, other routines should standardize on this.
|
||||
static bool jvParseLedger(Json::Value& jvRequest, const std::string& strLedger)
|
||||
{
|
||||
if (strLedger == "closed")
|
||||
if (strLedger == "current" || strLedger == "closed" || strLedger == "validated")
|
||||
{
|
||||
jvRequest["ledger_index"] = -1;
|
||||
jvRequest["ledger_index"] = strLedger;
|
||||
}
|
||||
else if (strLedger == "current")
|
||||
{
|
||||
jvRequest["ledger_index"] = -2;
|
||||
}
|
||||
else if (strLedger == "validated")
|
||||
{
|
||||
jvRequest["ledger_index"] = -3;
|
||||
}
|
||||
else if (strLedger.length() > 12)
|
||||
else if (strLedger.length() == 64)
|
||||
{
|
||||
// YYY Could confirm this is a uint256.
|
||||
jvRequest["ledger_hash"] = strLedger;
|
||||
@@ -143,7 +135,7 @@ Json::Value RPCParser::parseInternal(const Json::Value& jvParams)
|
||||
}
|
||||
|
||||
// account_info <account>|<nickname>|<account_public_key>
|
||||
// account_info <seed>|<pass_phrase>|<key> [<index>]
|
||||
// account_info <seed>|<pass_phrase>|<key> [[<index>] <ledger>]
|
||||
Json::Value RPCParser::parseAccountInfo(const Json::Value& jvParams)
|
||||
{
|
||||
Json::Value jvRequest(Json::objectValue);
|
||||
@@ -159,6 +151,9 @@ Json::Value RPCParser::parseAccountInfo(const Json::Value& jvParams)
|
||||
jvRequest["ident"] = strIdent;
|
||||
jvRequest["account_index"] = iIndex;
|
||||
|
||||
if (jvParams.size() == 3 && !jvParseLedger(jvRequest, jvParams[2u].asString()))
|
||||
return rpcError(rpcLGR_IDX_MALFORMED);
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
@@ -333,6 +328,25 @@ Json::Value RPCParser::parseGetCounts(const Json::Value& jvParams)
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
// json <command> <json>
|
||||
Json::Value RPCParser::parseJson(const Json::Value& jvParams)
|
||||
{
|
||||
Json::Reader reader;
|
||||
Json::Value jvRequest;
|
||||
|
||||
cLog(lsTRACE) << "RPC method: " << jvParams[0u];
|
||||
cLog(lsTRACE) << "RPC json: " << jvParams[1u];
|
||||
|
||||
if (reader.parse(jvParams[1u].asString(), jvRequest))
|
||||
{
|
||||
jvRequest["method"] = jvParams[0u];
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
}
|
||||
|
||||
// ledger [id|index|current|closed|validated] [full]
|
||||
Json::Value RPCParser::parseLedger(const Json::Value& jvParams)
|
||||
{
|
||||
@@ -343,20 +357,7 @@ Json::Value RPCParser::parseLedger(const Json::Value& jvParams)
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
std::string strLedger = jvParams[0u].asString();
|
||||
|
||||
if (strLedger == "current" || strLedger == "closed" || strLedger == "validated")
|
||||
{
|
||||
jvRequest["ledger_index"] = strLedger;
|
||||
}
|
||||
else if (strLedger.length() > 12)
|
||||
{
|
||||
jvRequest["ledger_hash"] = strLedger;
|
||||
}
|
||||
else
|
||||
{
|
||||
jvRequest["ledger_index"] = lexical_cast_s<uint32>(strLedger);
|
||||
}
|
||||
jvParseLedger(jvRequest, jvParams[0u].asString());
|
||||
|
||||
if (2 == jvParams.size() && jvParams[1u].asString() == "full")
|
||||
{
|
||||
@@ -373,7 +374,7 @@ Json::Value RPCParser::parseLedgerId(const Json::Value& jvParams)
|
||||
|
||||
std::string strLedger = jvParams[0u].asString();
|
||||
|
||||
if (strLedger.length() > 32)
|
||||
if (strLedger.length() == 32)
|
||||
{
|
||||
jvRequest["ledger_hash"] = strLedger;
|
||||
}
|
||||
@@ -641,7 +642,7 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
|
||||
// Request-response methods
|
||||
// - Returns an error, or the request.
|
||||
// - To modify the method, provide a new method in the request.
|
||||
{ "account_info", &RPCParser::parseAccountInfo, 1, 2 },
|
||||
{ "account_info", &RPCParser::parseAccountInfo, 1, 3 },
|
||||
{ "account_lines", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_offers", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_tx", &RPCParser::parseAccountTransactions, 2, 4 },
|
||||
@@ -649,6 +650,7 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
|
||||
{ "connect", &RPCParser::parseConnect, 1, 2 },
|
||||
{ "consensus_info", &RPCParser::parseAsIs, 0, 0 },
|
||||
{ "get_counts", &RPCParser::parseGetCounts, 0, 1 },
|
||||
{ "json", &RPCParser::parseJson, 2, 2 },
|
||||
{ "ledger", &RPCParser::parseLedger, 0, 2 },
|
||||
{ "ledger_accept", &RPCParser::parseAsIs, 0, 0 },
|
||||
{ "ledger_closed", &RPCParser::parseAsIs, 0, 0 },
|
||||
|
||||
@@ -23,9 +23,10 @@ protected:
|
||||
#endif
|
||||
Json::Value parseEvented(const Json::Value& jvParams);
|
||||
Json::Value parseGetCounts(const Json::Value& jvParams);
|
||||
Json::Value parseInternal(const Json::Value& jvParams);
|
||||
Json::Value parseJson(const Json::Value& jvParams);
|
||||
Json::Value parseLedger(const Json::Value& jvParams);
|
||||
Json::Value parseLedgerId(const Json::Value& jvParams);
|
||||
Json::Value parseInternal(const Json::Value& jvParams);
|
||||
#if ENABLE_INSECURE
|
||||
Json::Value parseLogin(const Json::Value& jvParams);
|
||||
#endif
|
||||
|
||||
@@ -486,7 +486,7 @@ void Config::load()
|
||||
|
||||
int Config::getSize(SizedItemName item)
|
||||
{
|
||||
SizedItem sizeTable[] = {
|
||||
SizedItem sizeTable[] = { // tiny small medium large huge
|
||||
{ siSweepInterval, { 10, 30, 60, 90, 90 } },
|
||||
{ siLedgerFetch, { 2, 2, 3, 4, 5 } },
|
||||
{ siValidationsSize, { 256, 256, 512, 1024, 1024 } },
|
||||
@@ -496,8 +496,11 @@ int Config::getSize(SizedItemName item)
|
||||
{ siLedgerSize, { 32, 64, 128, 1024, 0 } },
|
||||
{ siLedgerAge, { 30, 60, 120, 300, 600 } },
|
||||
{ siLineCacheSize, { 8192, 32768, 131072, 1048576, 0 } },
|
||||
{ siLineCacheAge, { 500, 600, 1800, 3600, 7200 } }
|
||||
};
|
||||
{ siLineCacheAge, { 500, 600, 1800, 3600, 7200 } },
|
||||
{ siHashNodeDBCache, { 24, 48, 64, 128, 256 } },
|
||||
{ siTxnDBCache, { 4, 8, 32, 64, 128 } },
|
||||
{ siLgrDBCache, { 4, 8, 32, 64, 128 } }
|
||||
};
|
||||
|
||||
for (int i = 0; i < (sizeof(sizeTable) / sizeof(SizedItem)); ++i)
|
||||
{
|
||||
|
||||
@@ -64,7 +64,10 @@ enum SizedItemName
|
||||
siLedgerAge,
|
||||
siLedgerFetch,
|
||||
siLineCacheSize,
|
||||
siLineCacheAge
|
||||
siLineCacheAge,
|
||||
siHashNodeDBCache,
|
||||
siTxnDBCache,
|
||||
siLgrDBCache
|
||||
};
|
||||
|
||||
struct SizedItem
|
||||
|
||||
@@ -319,7 +319,7 @@ Peer::pointer ConnectionPool::peerConnect(const std::string& strIp, int iPort)
|
||||
if (ppResult)
|
||||
{
|
||||
ppResult->connect(strIp, iPort);
|
||||
cLog(lsTRACE) << "Pool: Connecting: " << ADDRESS_SHARED(ppResult) << ": " << strIp << " " << iPort;
|
||||
cLog(lsDEBUG) << "Pool: Connecting: " << strIp << " " << iPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -24,6 +24,8 @@ const char *TxnDBInit[] = {
|
||||
Account CHARACTER(64), \
|
||||
LedgerSeq BIGINT UNSIGNED \
|
||||
);",
|
||||
"CREATE INDEX AcctTxIDIndex ON \
|
||||
AccountTransactions(TransID);",
|
||||
"CREATE INDEX AcctTxIndex ON \
|
||||
AccountTransactions(Account, LedgerSeq, TransID);",
|
||||
"CREATE INDEX AcctLgrIndex ON \
|
||||
|
||||
@@ -266,6 +266,7 @@ void JobQueue::threadEntry()
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
while (1)
|
||||
{
|
||||
NameThread("waiting");
|
||||
while (mJobSet.empty() && !mShuttingDown)
|
||||
mJobCond.wait(sl);
|
||||
|
||||
@@ -286,6 +287,7 @@ void JobQueue::threadEntry()
|
||||
|
||||
++(mJobCounts[type].second);
|
||||
sl.unlock();
|
||||
NameThread(Job::toString(type));
|
||||
cLog(lsTRACE) << "Doing " << Job::toString(type) << " job";
|
||||
job.doJob();
|
||||
} // must destroy job without holding lock
|
||||
|
||||
@@ -500,10 +500,8 @@ void Ledger::saveAcceptedLedger(Job&, bool fromConsensus)
|
||||
mCloseResolution % mCloseFlags % mAccountHash.GetHex() % mTransHash.GetHex()));
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!fromConsensus)
|
||||
if (!fromConsensus && (theConfig.NODE_SIZE < 2)) // tiny or small
|
||||
dropCache();
|
||||
#endif
|
||||
|
||||
if (theApp->getJobQueue().getJobCountTotal(jtPUBOLDLEDGER) < 2)
|
||||
theApp->getLedgerMaster().resumeAcquiring();
|
||||
@@ -844,14 +842,11 @@ Json::Value Ledger::getJson(int options)
|
||||
|
||||
if (mCloseTime != 0)
|
||||
{
|
||||
ledger["close_time"] = mCloseTime;
|
||||
ledger["close_time_human"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime));
|
||||
ledger["close_time_resolution"] = mCloseResolution;
|
||||
if ((mCloseFlags & sLCF_NoConsensusTime) != 0)
|
||||
ledger["close_time_estimate"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime));
|
||||
else
|
||||
{
|
||||
ledger["close_time"] = mCloseTime;
|
||||
ledger["close_time_human"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime));
|
||||
ledger["close_time_resolution"] = mCloseResolution;
|
||||
}
|
||||
ledger["close_time_estimated"] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include "Log.h"
|
||||
#include "SHAMapSync.h"
|
||||
|
||||
#define TX_ACQUIRE_TIMEOUT 250
|
||||
|
||||
#define LEDGER_TOTAL_PASSES 8
|
||||
#define LEDGER_RETRY_PASSES 5
|
||||
|
||||
@@ -28,159 +26,6 @@ typedef std::map<uint256, LCTransaction::pointer>::value_type u256_lct_pair;
|
||||
|
||||
SETUP_LOG();
|
||||
DECLARE_INSTANCE(LedgerConsensus);
|
||||
DECLARE_INSTANCE(TransactionAcquire);
|
||||
|
||||
TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false)
|
||||
{
|
||||
mMap = boost::make_shared<SHAMap>(smtTRANSACTION, hash);
|
||||
}
|
||||
|
||||
void TransactionAcquire::done()
|
||||
{
|
||||
if (mFailed)
|
||||
{
|
||||
cLog(lsWARNING) << "Failed to acquire TX set " << mHash;
|
||||
theApp->getOPs().mapComplete(mHash, SHAMap::pointer());
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "Acquired TX set " << mHash;
|
||||
mMap->setImmutable();
|
||||
theApp->getOPs().mapComplete(mHash, mMap);
|
||||
}
|
||||
theApp->getMasterLedgerAcquire().dropLedger(mHash);
|
||||
}
|
||||
|
||||
void TransactionAcquire::onTimer(bool progress)
|
||||
{
|
||||
if (!getPeerCount())
|
||||
{ // out of peers
|
||||
cLog(lsWARNING) << "Out of peers for TX set " << getHash();
|
||||
|
||||
bool found = false;
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
{
|
||||
if (peer->hasTxSet(getHash()))
|
||||
{
|
||||
found = true;
|
||||
peerHas(peer);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
peerHas(peer);
|
||||
}
|
||||
}
|
||||
else if (!progress)
|
||||
trigger(Peer::pointer());
|
||||
}
|
||||
|
||||
boost::weak_ptr<PeerSet> TransactionAcquire::pmDowncast()
|
||||
{
|
||||
return boost::shared_polymorphic_downcast<PeerSet>(shared_from_this());
|
||||
}
|
||||
|
||||
void TransactionAcquire::trigger(Peer::ref peer)
|
||||
{
|
||||
if (mComplete || mFailed)
|
||||
{
|
||||
cLog(lsINFO) << "complete or failed";
|
||||
return;
|
||||
}
|
||||
if (!mHaveRoot)
|
||||
{
|
||||
cLog(lsTRACE) << "TransactionAcquire::trigger " << (peer ? "havePeer" : "noPeer") << " no root";
|
||||
ripple::TMGetLedger tmGL;
|
||||
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
|
||||
tmGL.set_itype(ripple::liTS_CANDIDATE);
|
||||
if (getTimeouts() != 0)
|
||||
tmGL.set_querytype(ripple::qtINDIRECT);
|
||||
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<SHAMapNode> nodeIDs;
|
||||
std::vector<uint256> nodeHashes;
|
||||
ConsensusTransSetSF sf;
|
||||
mMap->getMissingNodes(nodeIDs, nodeHashes, 256, &sf);
|
||||
if (nodeIDs.empty())
|
||||
{
|
||||
if (mMap->isValid())
|
||||
mComplete = true;
|
||||
else
|
||||
mFailed = true;
|
||||
done();
|
||||
return;
|
||||
}
|
||||
ripple::TMGetLedger tmGL;
|
||||
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
|
||||
tmGL.set_itype(ripple::liTS_CANDIDATE);
|
||||
if (getTimeouts() != 0)
|
||||
tmGL.set_querytype(ripple::qtINDIRECT);
|
||||
BOOST_FOREACH(SHAMapNode& it, nodeIDs)
|
||||
*(tmGL.add_nodeids()) = it.getRawString();
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
}
|
||||
|
||||
SMAddNode TransactionAcquire::takeNodes(const std::list<SHAMapNode>& nodeIDs,
|
||||
const std::list< std::vector<unsigned char> >& data, Peer::ref peer)
|
||||
{
|
||||
if (mComplete)
|
||||
{
|
||||
cLog(lsTRACE) << "TX set complete";
|
||||
return SMAddNode();
|
||||
}
|
||||
if (mFailed)
|
||||
{
|
||||
cLog(lsTRACE) << "TX set failed";
|
||||
return SMAddNode();
|
||||
}
|
||||
try
|
||||
{
|
||||
if (nodeIDs.empty())
|
||||
return SMAddNode::invalid();
|
||||
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
|
||||
std::list< std::vector<unsigned char> >::const_iterator nodeDatait = data.begin();
|
||||
ConsensusTransSetSF sf;
|
||||
while (nodeIDit != nodeIDs.end())
|
||||
{
|
||||
if (nodeIDit->isRoot())
|
||||
{
|
||||
if (mHaveRoot)
|
||||
{
|
||||
cLog(lsWARNING) << "Got root TXS node, already have it";
|
||||
return SMAddNode();
|
||||
}
|
||||
if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE, NULL))
|
||||
{
|
||||
cLog(lsWARNING) << "TX acquire got bad root node";
|
||||
return SMAddNode::invalid();
|
||||
}
|
||||
else
|
||||
mHaveRoot = true;
|
||||
}
|
||||
else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &sf))
|
||||
{
|
||||
cLog(lsWARNING) << "TX acquire got bad non-root node";
|
||||
return SMAddNode::invalid();
|
||||
}
|
||||
++nodeIDit;
|
||||
++nodeDatait;
|
||||
}
|
||||
trigger(peer);
|
||||
progress();
|
||||
return SMAddNode::useful();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cLog(lsERROR) << "Peer sends us junky transaction node data";
|
||||
return SMAddNode::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
void LCTransaction::setVote(const uint160& peer, bool votesYes)
|
||||
{ // Track a peer's yes/no vote on a particular disputed transaction
|
||||
@@ -356,7 +201,7 @@ void LedgerConsensus::checkOurValidation()
|
||||
v->setTrusted();
|
||||
v->sign(signingHash, mValPrivate);
|
||||
theApp->isNew(signingHash);
|
||||
theApp->getValidations().addValidation(v);
|
||||
theApp->getValidations().addValidation(v, "localMissing");
|
||||
std::vector<unsigned char> validation = v->getSigned();
|
||||
ripple::TMValidation val;
|
||||
val.set_validation(&validation[0], validation.size());
|
||||
@@ -1337,7 +1182,7 @@ void LedgerConsensus::accept(SHAMap::ref set, LoadEvent::pointer)
|
||||
v->sign(signingHash, mValPrivate);
|
||||
v->setTrusted();
|
||||
theApp->isNew(signingHash); // suppress it if we receive it
|
||||
theApp->getValidations().addValidation(v);
|
||||
theApp->getValidations().addValidation(v, "local");
|
||||
theApp->getOPs().setLastValidation(v);
|
||||
std::vector<unsigned char> validation = v->getSigned();
|
||||
ripple::TMValidation val;
|
||||
|
||||
@@ -289,6 +289,9 @@ bool LedgerMaster::shouldAcquire(uint32 currentLedger, uint32 ledgerHistory, uin
|
||||
|
||||
void LedgerMaster::resumeAcquiring()
|
||||
{
|
||||
if (theApp->getOPs().isNeedNetworkLedger())
|
||||
return;
|
||||
|
||||
boost::recursive_mutex::scoped_lock ml(mLock);
|
||||
|
||||
if (mMissingLedger && mMissingLedger->isDone())
|
||||
@@ -355,6 +358,9 @@ void LedgerMaster::setFullLedger(Ledger::pointer ledger)
|
||||
cLog(lsDEBUG) << "Ledger " << ledger->getLedgerSeq() << " accepted :" << ledger->getHash();
|
||||
assert(ledger->peekAccountStateMap()->getHash().isNonZero());
|
||||
|
||||
if (theApp->getOPs().isNeedNetworkLedger())
|
||||
return;
|
||||
|
||||
boost::recursive_mutex::scoped_lock ml(mLock);
|
||||
|
||||
mCompleteLedgers.setValue(ledger->getLedgerSeq());
|
||||
|
||||
@@ -317,6 +317,7 @@ int LoadManager::getUptime()
|
||||
|
||||
void LoadManager::threadEntry()
|
||||
{
|
||||
NameThread("loadmgr");
|
||||
boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time();
|
||||
while (1)
|
||||
{
|
||||
|
||||
@@ -1068,7 +1068,7 @@ std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
|
||||
str(boost::format("SELECT AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta FROM "
|
||||
"AccountTransactions INNER JOIN Transactions ON Transactions.TransID = AccountTransactions.TransID "
|
||||
"WHERE Account = '%s' AND AccountTransactions.LedgerSeq <= '%u' AND AccountTransactions.LedgerSeq >= '%u' "
|
||||
"ORDER BY AccountTransactions.LedgerSeq DESC LIMIT 200;")
|
||||
"ORDER BY AccountTransactions.LedgerSeq,AccountTransactions.TransID DESC LIMIT 200;")
|
||||
% account.humanAccountID() % maxLedger % minLedger);
|
||||
|
||||
{
|
||||
@@ -1105,7 +1105,7 @@ std::vector<NetworkOPs::txnMetaLedgerType> NetworkOPs::getAccountTxsB(
|
||||
std::string sql = str(boost::format("SELECT AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta FROM "
|
||||
"AccountTransactions INNER JOIN Transactions ON Transactions.TransID = AccountTransactions.TransID "
|
||||
"WHERE Account = '%s' AND AccountTransactions.LedgerSeq <= '%u' AND AccountTransactions.LedgerSeq >= '%u' "
|
||||
"ORDER BY AccountTransactions.LedgerSeq DESC LIMIT 500;")
|
||||
"ORDER BY AccountTransactions.LedgerSeq,AccountTransactions.TransID DESC LIMIT 500;")
|
||||
% account.humanAccountID() % maxLedger % minLedger);
|
||||
|
||||
{
|
||||
@@ -1164,10 +1164,10 @@ std::vector<RippleAddress>
|
||||
return accounts;
|
||||
}
|
||||
|
||||
bool NetworkOPs::recvValidation(SerializedValidation::ref val)
|
||||
bool NetworkOPs::recvValidation(SerializedValidation::ref val, const std::string& source)
|
||||
{
|
||||
cLog(lsDEBUG) << "recvValidation " << val->getLedgerHash();
|
||||
return theApp->getValidations().addValidation(val);
|
||||
cLog(lsDEBUG) << "recvValidation " << val->getLedgerHash() << " from " << source;
|
||||
return theApp->getValidations().addValidation(val, source);
|
||||
}
|
||||
|
||||
Json::Value NetworkOPs::getConsensusInfo()
|
||||
@@ -1665,18 +1665,20 @@ void NetworkOPs::unsubAccountChanges(InfoSub* isrListener)
|
||||
// <-- bool: true=added, false=already there
|
||||
bool NetworkOPs::subLedger(InfoSub::ref isrListener, Json::Value& jvResult)
|
||||
{
|
||||
Ledger::pointer lpClosed = getClosedLedger();
|
||||
Ledger::pointer lpClosed = getValidatedLedger();
|
||||
if (lpClosed)
|
||||
{
|
||||
jvResult["ledger_index"] = lpClosed->getLedgerSeq();
|
||||
jvResult["ledger_hash"] = lpClosed->getHash().ToString();
|
||||
jvResult["ledger_time"] = Json::Value::UInt(lpClosed->getCloseTimeNC());
|
||||
|
||||
jvResult["ledger_index"] = lpClosed->getLedgerSeq();
|
||||
jvResult["ledger_hash"] = lpClosed->getHash().ToString();
|
||||
jvResult["ledger_time"] = Json::Value::UInt(lpClosed->getCloseTimeNC());
|
||||
jvResult["fee_ref"] = Json::UInt(lpClosed->getReferenceFeeUnits());
|
||||
jvResult["fee_base"] = Json::UInt(lpClosed->getBaseFee());
|
||||
jvResult["reserve_base"] = Json::UInt(lpClosed->getReserve(0));
|
||||
jvResult["reserve_inc"] = Json::UInt(lpClosed->getReserveInc());
|
||||
}
|
||||
|
||||
jvResult["fee_ref"] = Json::UInt(lpClosed->getReferenceFeeUnits());
|
||||
jvResult["fee_base"] = Json::UInt(lpClosed->getBaseFee());
|
||||
jvResult["reserve_base"] = Json::UInt(lpClosed->getReserve(0));
|
||||
jvResult["reserve_inc"] = Json::UInt(lpClosed->getReserveInc());
|
||||
|
||||
if ((mMode == omFULL) || (mMode == omTRACKING))
|
||||
if (((mMode == omFULL) || (mMode == omTRACKING)) && !isNeedNetworkLedger())
|
||||
jvResult["validated_ledgers"] = theApp->getLedgerMaster().getCompleteLedgers();
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
|
||||
@@ -253,7 +253,7 @@ public:
|
||||
RippleAddress nodePublic, uint256 checkLedger, bool sigGood);
|
||||
SMAddNode gotTXData(const boost::shared_ptr<Peer>& peer, const uint256& hash,
|
||||
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
|
||||
bool recvValidation(SerializedValidation::ref val);
|
||||
bool recvValidation(SerializedValidation::ref val, const std::string& source);
|
||||
void takePosition(int seq, SHAMap::ref position);
|
||||
SHAMap::pointer getTXMap(const uint256& hash);
|
||||
bool hasTXSet(const boost::shared_ptr<Peer>& peer, const uint256& set, ripple::TxSetStatus status);
|
||||
|
||||
@@ -7,6 +7,80 @@
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
// Make sure an offer is still valid. If not, mark it unfunded.
|
||||
bool OfferCreateTransactor::bValidOffer(
|
||||
SLE::ref sleOfferDir,
|
||||
const uint256& uOfferIndex,
|
||||
const uint160& uOfferOwnerID,
|
||||
const STAmount& saOfferPays,
|
||||
const STAmount& saOfferGets,
|
||||
const uint160& uTakerAccountID,
|
||||
boost::unordered_set<uint256>& usOfferUnfundedFound,
|
||||
boost::unordered_set<uint256>& usOfferUnfundedBecame,
|
||||
boost::unordered_set<uint160>& usAccountTouched,
|
||||
STAmount& saOfferFunds) { // <--
|
||||
bool bValid;
|
||||
|
||||
if (sleOfferDir->isFieldPresent(sfExpiration) && sleOfferDir->getFieldU32(sfExpiration) <= mEngine->getLedger()->getParentCloseTimeNC())
|
||||
{
|
||||
// Offer is expired. Expired offers are considered unfunded. Delete it.
|
||||
cLog(lsINFO) << "bValidOffer: encountered expired offer";
|
||||
|
||||
usOfferUnfundedFound.insert(uOfferIndex);
|
||||
|
||||
bValid = false;
|
||||
}
|
||||
else if (uOfferOwnerID == uTakerAccountID)
|
||||
{
|
||||
// Would take own offer. Consider old offer expired. Delete it.
|
||||
cLog(lsINFO) << "bValidOffer: encountered taker's own old offer";
|
||||
|
||||
usOfferUnfundedFound.insert(uOfferIndex);
|
||||
|
||||
bValid = false;
|
||||
}
|
||||
else if (!saOfferGets.isPositive() || !saOfferPays.isPositive())
|
||||
{
|
||||
// Offer has bad amounts. Consider offer expired. Delete it.
|
||||
cLog(lsWARNING) << boost::str(boost::format("bValidOffer: BAD OFFER: saOfferPays=%s saOfferGets=%s")
|
||||
% saOfferPays % saOfferGets);
|
||||
|
||||
usOfferUnfundedFound.insert(uOfferIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "bValidOffer: saOfferPays=" << saOfferPays.getFullText();
|
||||
|
||||
saOfferFunds = mEngine->getNodes().accountFunds(uOfferOwnerID, saOfferPays);
|
||||
|
||||
if (!saOfferFunds.isPositive())
|
||||
{
|
||||
// Offer is unfunded, possibly due to previous balance action.
|
||||
cLog(lsINFO) << "bValidOffer: offer unfunded: delete";
|
||||
|
||||
boost::unordered_set<uint160>::iterator account = usAccountTouched.find(uOfferOwnerID);
|
||||
if (account != usAccountTouched.end())
|
||||
{
|
||||
// Previously touched account.
|
||||
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Never touched source account.
|
||||
usOfferUnfundedFound.insert(uOfferIndex); // Delete found unfunded offer when possible.
|
||||
}
|
||||
|
||||
bValid = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bValid;
|
||||
}
|
||||
|
||||
// Take as much as possible. Adjusts account balances. Charges fees on top to taker.
|
||||
// --> uBookBase: The order book to take against.
|
||||
// --> saTakerPays: What the taker offers (w/ issuer)
|
||||
@@ -28,7 +102,7 @@ TER OfferCreateTransactor::takeOffers(
|
||||
bool& bUnfunded)
|
||||
{
|
||||
// The book has the most elements. Take the perspective of the book.
|
||||
// Book is ordered for taker: taker pays / taker gets, < is better
|
||||
// Book is ordered for taker: taker pays / taker gets (smaller is better)
|
||||
|
||||
// The order is for the other books currencys for get and pays are opposites.
|
||||
// We want the same ratio for the respective currencies.
|
||||
@@ -141,162 +215,121 @@ TER OfferCreateTransactor::takeOffers(
|
||||
STAmount saOfferPays = sleOffer->getFieldAmount(sfTakerGets);
|
||||
STAmount saOfferGets = sleOffer->getFieldAmount(sfTakerPays);
|
||||
|
||||
if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getFieldU32(sfExpiration) <= mEngine->getLedger()->getParentCloseTimeNC())
|
||||
{
|
||||
// Offer is expired. Expired offers are considered unfunded. Delete it.
|
||||
cLog(lsINFO) << "takeOffers: encountered expired offer";
|
||||
STAmount saOfferFunds; // Funds of offer owner to payout.
|
||||
bool bValid;
|
||||
|
||||
usOfferUnfundedFound.insert(uOfferIndex);
|
||||
}
|
||||
else if (uOfferOwnerID == uTakerAccountID)
|
||||
{
|
||||
// Would take own offer. Consider old offer expired. Delete it.
|
||||
cLog(lsINFO) << "takeOffers: encountered taker's own old offer";
|
||||
bValid = bValidOffer(
|
||||
sleOfferDir, uOfferIndex, uOfferOwnerID, saOfferPays, saOfferGets,
|
||||
uTakerAccountID,
|
||||
usOfferUnfundedFound, usOfferUnfundedBecame, usAccountTouched,
|
||||
saOfferFunds);
|
||||
|
||||
usOfferUnfundedBecame.insert(uOfferIndex);
|
||||
}
|
||||
else if (!saOfferGets.isPositive() || !saOfferPays.isPositive())
|
||||
{
|
||||
// Offer has bad amounts. Consider offer expired. Delete it.
|
||||
cLog(lsWARNING) << boost::str(boost::format("takeOffers: BAD OFFER: saOfferPays=%s saOfferGets=%s")
|
||||
% saOfferPays % saOfferGets);
|
||||
if (bValid) {
|
||||
STAmount saSubTakerPaid;
|
||||
STAmount saSubTakerGot;
|
||||
STAmount saTakerIssuerFee;
|
||||
STAmount saOfferIssuerFee;
|
||||
STAmount saOfferRate = STAmount::setRate(uTipQuality);
|
||||
|
||||
usOfferUnfundedFound.insert(uOfferIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get offer funds available.
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerFunds: " << saTakerFunds.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferFunds: " << saOfferFunds.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferPays: " << saOfferPays.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferRate: " << saOfferRate.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerPays: " << saSubTakerPays.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGets: " << saSubTakerGets.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText();
|
||||
|
||||
cLog(lsINFO) << "takeOffers: saOfferPays=" << saOfferPays.getFullText();
|
||||
bool bOfferDelete = STAmount::applyOffer(
|
||||
lesActive.rippleTransferRate(uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID),
|
||||
lesActive.rippleTransferRate(uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID),
|
||||
saOfferRate,
|
||||
saOfferFunds,
|
||||
saTakerFunds,
|
||||
saOfferPays,
|
||||
saOfferGets,
|
||||
saSubTakerPays,
|
||||
saSubTakerGets,
|
||||
saSubTakerPaid,
|
||||
saSubTakerGot,
|
||||
saTakerIssuerFee,
|
||||
saOfferIssuerFee);
|
||||
|
||||
STAmount saOfferFunds = lesActive.accountFunds(uOfferOwnerID, saOfferPays);
|
||||
SLE::pointer sleOfferAccount; // Owner of offer.
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText();
|
||||
|
||||
if (!saOfferFunds.isPositive()) // Includes zero.
|
||||
// Adjust offer
|
||||
|
||||
// Offer owner will pay less. Subtract what taker just got.
|
||||
sleOffer->setFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot);
|
||||
|
||||
// Offer owner will get less. Subtract what owner just paid.
|
||||
sleOffer->setFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid);
|
||||
|
||||
mEngine->entryModify(sleOffer);
|
||||
|
||||
if (bOfferDelete)
|
||||
{
|
||||
// Offer is unfunded, possibly due to previous balance action.
|
||||
cLog(lsINFO) << "takeOffers: offer unfunded: delete";
|
||||
// Offer now fully claimed or now unfunded.
|
||||
cLog(lsINFO) << "takeOffers: Offer claimed: Delete.";
|
||||
|
||||
boost::unordered_set<uint160>::iterator account = usAccountTouched.find(uOfferOwnerID);
|
||||
if (account != usAccountTouched.end())
|
||||
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
|
||||
|
||||
// Offer owner's account is no longer pristine.
|
||||
usAccountTouched.insert(uOfferOwnerID);
|
||||
}
|
||||
else if (saSubTakerGot)
|
||||
{
|
||||
cLog(lsINFO) << "takeOffers: Offer partial claim.";
|
||||
|
||||
if (!saOfferPays.isPositive() || !saOfferGets.isPositive())
|
||||
{
|
||||
// Previously touched account.
|
||||
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Never touched source account.
|
||||
usOfferUnfundedFound.insert(uOfferIndex); // Delete found unfunded offer when possible.
|
||||
cLog(lsWARNING) << "takeOffers: ILLEGAL OFFER RESULT.";
|
||||
bUnfunded = true;
|
||||
terResult = bOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
STAmount saSubTakerPaid;
|
||||
STAmount saSubTakerGot;
|
||||
STAmount saTakerIssuerFee;
|
||||
STAmount saOfferIssuerFee;
|
||||
STAmount saOfferRate = STAmount::setRate(uTipQuality);
|
||||
// Taker got nothing, probably due to rounding. Consider taker unfunded.
|
||||
cLog(lsINFO) << "takeOffers: No claim.";
|
||||
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerFunds: " << saTakerFunds.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferFunds: " << saOfferFunds.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferPays: " << saOfferPays.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saOfferRate: " << saOfferRate.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerPays: " << saSubTakerPays.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGets: " << saSubTakerGets.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText();
|
||||
bUnfunded = true;
|
||||
terResult = tesSUCCESS; // Done.
|
||||
}
|
||||
|
||||
bool bOfferDelete = STAmount::applyOffer(
|
||||
lesActive.rippleTransferRate(uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID),
|
||||
lesActive.rippleTransferRate(uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID),
|
||||
saOfferRate,
|
||||
saOfferFunds,
|
||||
saTakerFunds,
|
||||
saOfferPays,
|
||||
saOfferGets,
|
||||
saSubTakerPays,
|
||||
saSubTakerGets,
|
||||
saSubTakerPaid,
|
||||
saSubTakerGot,
|
||||
saTakerIssuerFee,
|
||||
saOfferIssuerFee);
|
||||
assert(uTakerGetsAccountID == saSubTakerGot.getIssuer());
|
||||
assert(uTakerPaysAccountID == saSubTakerPaid.getIssuer());
|
||||
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText();
|
||||
if (!bUnfunded)
|
||||
{
|
||||
// Distribute funds. The sends charge appropriate fees which are implied by offer.
|
||||
|
||||
terResult = lesActive.accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); // Offer owner pays taker.
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
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.
|
||||
if (saTakerFunds < saTakerCould)
|
||||
saTakerCould = saTakerFunds;
|
||||
|
||||
STAmount saTakerUsed = STAmount::multiply(saSubTakerGot, saTakerRate, saTakerPays);
|
||||
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerCould: " << saTakerCould.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerRate: " << saTakerRate.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerUsed: " << saTakerUsed.getFullText();
|
||||
|
||||
// Adjust offer
|
||||
saTakerPaid += std::min(saTakerCould, saTakerUsed);
|
||||
saTakerGot += saSubTakerGot;
|
||||
|
||||
// Offer owner will pay less. Subtract what taker just got.
|
||||
sleOffer->setFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot);
|
||||
|
||||
// Offer owner will get less. Subtract what owner just paid.
|
||||
sleOffer->setFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid);
|
||||
|
||||
mEngine->entryModify(sleOffer);
|
||||
|
||||
if (bOfferDelete)
|
||||
{
|
||||
// Offer now fully claimed or now unfunded.
|
||||
cLog(lsINFO) << "takeOffers: Offer claimed: Delete.";
|
||||
|
||||
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
|
||||
|
||||
// Offer owner's account is no longer pristine.
|
||||
usAccountTouched.insert(uOfferOwnerID);
|
||||
}
|
||||
else if (saSubTakerGot)
|
||||
{
|
||||
cLog(lsINFO) << "takeOffers: Offer partial claim.";
|
||||
|
||||
if (!saOfferPays.isPositive() || !saOfferGets.isPositive())
|
||||
{
|
||||
cLog(lsWARNING) << "takeOffers: ILLEGAL OFFER RESULT.";
|
||||
bUnfunded = true;
|
||||
terResult = bOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Taker got nothing, probably due to rounding. Consider taker unfunded.
|
||||
cLog(lsINFO) << "takeOffers: No claim.";
|
||||
|
||||
bUnfunded = true;
|
||||
terResult = tesSUCCESS; // Done.
|
||||
}
|
||||
|
||||
assert(uTakerGetsAccountID == saSubTakerGot.getIssuer());
|
||||
assert(uTakerPaysAccountID == saSubTakerPaid.getIssuer());
|
||||
|
||||
if (!bUnfunded)
|
||||
{
|
||||
// Distribute funds. The sends charge appropriate fees which are implied by offer.
|
||||
|
||||
terResult = lesActive.accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); // Offer owner pays taker.
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
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.
|
||||
if (saTakerFunds < saTakerCould)
|
||||
saTakerCould = saTakerFunds;
|
||||
|
||||
STAmount saTakerUsed = STAmount::multiply(saSubTakerGot, saTakerRate, saTakerPays);
|
||||
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerCould: " << saTakerCould.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerRate: " << saTakerRate.getFullText();
|
||||
cLog(lsINFO) << "takeOffers: applyOffer: saTakerUsed: " << saTakerUsed.getFullText();
|
||||
|
||||
saTakerPaid += std::min(saTakerCould, saTakerUsed);
|
||||
saTakerGot += saSubTakerGot;
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
terResult = temUNCERTAIN;
|
||||
}
|
||||
if (tesSUCCESS == terResult)
|
||||
terResult = temUNCERTAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,6 +459,17 @@ TER OfferCreateTransactor::doApply()
|
||||
|
||||
terResult = terNO_ACCOUNT;
|
||||
}
|
||||
else if (isSetBit(sleTakerPays->getFieldU32(sfFlags), lsfRequireAuth)) {
|
||||
SLE::pointer sleRippleState = mEngine->entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uPaysIssuerID, uPaysCurrency));
|
||||
bool bHigh = mTxnAccountID > uPaysIssuerID;
|
||||
|
||||
if (!sleRippleState
|
||||
|| !isSetBit(sleRippleState->getFieldU32(sfFlags), (bHigh ? lsfHighAuth : lsfLowAuth))) {
|
||||
cLog(lsWARNING) << "OfferCreate: delay: can't receive IOUs from issuer without auth.";
|
||||
|
||||
terResult = terNO_AUTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STAmount saPaid;
|
||||
|
||||
@@ -6,6 +6,18 @@
|
||||
class OfferCreateTransactor : public Transactor
|
||||
{
|
||||
protected:
|
||||
bool bValidOffer(
|
||||
SLE::ref sleOfferDir,
|
||||
const uint256& uOffer,
|
||||
const uint160& uOfferOwnerID,
|
||||
const STAmount& saOfferPays,
|
||||
const STAmount& saOfferGets,
|
||||
const uint160& uTakerAccountID,
|
||||
boost::unordered_set<uint256>& usOfferUnfundedFound,
|
||||
boost::unordered_set<uint256>& usOfferUnfundedBecame,
|
||||
boost::unordered_set<uint160>& usAccountTouched,
|
||||
STAmount& saOfferFunds);
|
||||
|
||||
TER takeOffers(
|
||||
const bool bOpenLedger,
|
||||
const bool bPassive,
|
||||
|
||||
@@ -714,9 +714,9 @@ boost::unordered_set<uint160> usAccountSourceCurrencies(const RippleAddress& raA
|
||||
STAmount saBalance = rspEntry->getBalance();
|
||||
|
||||
// Filter out non
|
||||
if (saBalance.isPositive() // Have IOUs to send.
|
||||
|| (rspEntry->getLimitPeer() // Peer extends credit.
|
||||
&& -saBalance < rspEntry->getLimitPeer())) // Credit left.
|
||||
if (saBalance.isPositive() // Have IOUs to send.
|
||||
|| (rspEntry->getLimitPeer() // Peer extends credit.
|
||||
&& ((-saBalance) < rspEntry->getLimitPeer()))) // Credit left.
|
||||
{
|
||||
usCurrencies.insert(saBalance.getCurrency());
|
||||
}
|
||||
|
||||
@@ -95,6 +95,8 @@ void Peer::detach(const char *rsn, bool onIOStrand)
|
||||
if (!mDetaching)
|
||||
{
|
||||
mDetaching = true; // Race is ok.
|
||||
|
||||
tLog(mCluster, lsWARNING) << "Cluster peer detach \"" << mNodeName << "\": " << rsn;
|
||||
/*
|
||||
cLog(lsDEBUG) << "Peer: Detach: "
|
||||
<< ADDRESS(this) << "> "
|
||||
@@ -384,7 +386,15 @@ void Peer::handleReadHeader(const boost::system::error_code& error)
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "Peer: Header: Error: " << ADDRESS(this) << ": " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
if (mCluster)
|
||||
{
|
||||
cLog(lsINFO) << "Peer: Cluster connection lost to \"" << mNodeName << "\": " <<
|
||||
error.category().name() << ": " << error.message() << ": " << error;
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "Peer: Header: Error: " << getIP() << ": " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
}
|
||||
detach("hrh2", true);
|
||||
}
|
||||
}
|
||||
@@ -397,7 +407,15 @@ void Peer::handleReadBody(const boost::system::error_code& error)
|
||||
}
|
||||
else if (error)
|
||||
{
|
||||
cLog(lsINFO) << "Peer: Body: Error: " << ADDRESS(this) << ": " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
if (mCluster)
|
||||
{
|
||||
cLog(lsINFO) << "Peer: Cluster connection lost to \"" << mNodeName << "\": " <<
|
||||
error.category().name() << ": " << error.message() << ": " << error;
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "Peer: Body: Error: " << getIP() << ": " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
}
|
||||
boost::recursive_mutex::scoped_lock sl(theApp->getMasterLock());
|
||||
detach("hrb", true);
|
||||
return;
|
||||
@@ -734,6 +752,8 @@ void Peer::recvHello(ripple::TMHello& packet)
|
||||
{
|
||||
mCluster = true;
|
||||
mLoad.setPrivileged();
|
||||
cLog(lsINFO) << "Cluster connection to \"" << (mNodeName.empty() ? getIP() : mNodeName)
|
||||
<< "\" established";
|
||||
}
|
||||
if (isOutbound())
|
||||
mLoad.setOutbound();
|
||||
@@ -1036,8 +1056,16 @@ static void checkValidation(Job&, SerializedValidation::pointer val, uint256 sig
|
||||
return;
|
||||
}
|
||||
|
||||
std::string source;
|
||||
Peer::pointer lp = peer.lock();
|
||||
if (lp)
|
||||
source = lp->getDisplayName();
|
||||
else
|
||||
source = "unknown";
|
||||
|
||||
std::set<uint64> peers;
|
||||
if (theApp->getOPs().recvValidation(val) && theApp->getSuppression().swapSet(signingHash, peers, SF_RELAYED))
|
||||
if (theApp->getOPs().recvValidation(val, source) &&
|
||||
theApp->getSuppression().swapSet(signingHash, peers, SF_RELAYED))
|
||||
{
|
||||
PackedMessage::pointer message = boost::make_shared<PackedMessage>(*packet, ripple::mtVALIDATION);
|
||||
theApp->getConnectionPool().relayMessageBut(peers, message);
|
||||
@@ -1394,8 +1422,7 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
if (!map)
|
||||
{
|
||||
if (packet.has_querytype() && !packet.has_requestcookie())
|
||||
{ // FIXME: Don't relay requests for older ledgers we would acquire
|
||||
// (if we don't have them, we can't get them)
|
||||
{
|
||||
cLog(lsDEBUG) << "Trying to route TX set request";
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
std::vector<Peer::pointer> usablePeers;
|
||||
@@ -1622,7 +1649,7 @@ void Peer::recvLedger(const boost::shared_ptr<ripple::TMLedgerData>& packet_ptr)
|
||||
if (target)
|
||||
{
|
||||
packet.clear_requestcookie();
|
||||
target->sendPacket(boost::make_shared<PackedMessage>(packet, ripple::mtLEDGER_DATA), true);
|
||||
target->sendPacket(boost::make_shared<PackedMessage>(packet, ripple::mtLEDGER_DATA), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -117,6 +117,7 @@ public:
|
||||
//bool operator == (const Peer& other);
|
||||
|
||||
std::string& getIP() { return mIpPort.first; }
|
||||
std::string getDisplayName() { return mCluster ? mNodeName : mIpPort.first; }
|
||||
int getPort() { return mIpPort.second; }
|
||||
|
||||
void setIpPort(const std::string& strIP, int iPort);
|
||||
|
||||
@@ -2021,9 +2021,19 @@ Json::Value RPCHandler::doGetCounts(Json::Value jvRequest, int& cost)
|
||||
BOOST_FOREACH(InstanceType::InstanceCount& it, count)
|
||||
ret[it.first] = it.second;
|
||||
|
||||
int dbKB = theApp->getLedgerDB()->getDB()->getKBUsed();
|
||||
int dbKB = theApp->getLedgerDB()->getDB()->getKBUsedAll();
|
||||
if (dbKB > 0)
|
||||
ret["dbKB"] = dbKB;
|
||||
ret["dbKBTotal"] = dbKB;
|
||||
|
||||
dbKB = theApp->getLedgerDB()->getDB()->getKBUsedDB();
|
||||
if (dbKB > 0)
|
||||
ret["dbKBLedger"] = dbKB;
|
||||
dbKB = theApp->getHashNodeDB()->getDB()->getKBUsedDB();
|
||||
if (dbKB > 0)
|
||||
ret["dbKBHashNode"] = dbKB;
|
||||
dbKB = theApp->getTxnDB()->getDB()->getKBUsedDB();
|
||||
if (dbKB > 0)
|
||||
ret["dbKBTransaction"] = dbKB;
|
||||
|
||||
std::string uptime;
|
||||
int s = upTime();
|
||||
|
||||
@@ -114,7 +114,7 @@ TER PathState::pushImply(
|
||||
|
||||
// Append a node and insert before it any implied nodes.
|
||||
// Offers may go back to back.
|
||||
// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_LINE, tecPATH_DRY
|
||||
// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_ACCOUNT, terNO_AUTH, terNO_LINE, tecPATH_DRY
|
||||
TER PathState::pushNode(
|
||||
const int iType,
|
||||
const uint160& uAccountID,
|
||||
@@ -231,11 +231,30 @@ TER PathState::pushNode(
|
||||
<< STAmount::createHumanCurrency(pnCur.uCurrencyID)
|
||||
<< "." ;
|
||||
|
||||
STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID);
|
||||
SLE::pointer sleBck = lesEntries.entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(pnBck.uAccountID));
|
||||
bool bHigh = pnBck.uAccountID > pnCur.uAccountID;
|
||||
|
||||
if (!saOwed.isPositive() && -saOwed >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID))
|
||||
if (!sleBck)
|
||||
{
|
||||
terResult = tecPATH_DRY;
|
||||
cLog(lsWARNING) << "pushNode: delay: can't receive IOUs from non-existent issuer: " << RippleAddress::createHumanAccountID(pnBck.uAccountID);
|
||||
|
||||
terResult = terNO_ACCOUNT;
|
||||
}
|
||||
else if (isSetBit(sleBck->getFieldU32(sfFlags), lsfRequireAuth)
|
||||
&& !isSetBit(sleRippleState->getFieldU32(sfFlags), (bHigh ? lsfHighAuth : lsfLowAuth))) {
|
||||
cLog(lsWARNING) << "pushNode: delay: can't receive IOUs from issuer without auth.";
|
||||
|
||||
terResult = terNO_AUTH;
|
||||
}
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID);
|
||||
|
||||
if (!saOwed.isPositive() && -saOwed >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID))
|
||||
{
|
||||
terResult = tecPATH_DRY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,7 +306,7 @@ TER PathState::pushNode(
|
||||
|
||||
// Set to an expanded path.
|
||||
//
|
||||
// terStatus = tesSUCCESS, temBAD_PATH, terNO_LINE, or temBAD_PATH_LOOP
|
||||
// terStatus = tesSUCCESS, temBAD_PATH, terNO_LINE, terNO_ACCOUNT, terNO_AUTH, or temBAD_PATH_LOOP
|
||||
void PathState::setExpanded(
|
||||
const LedgerEntrySet& lesSource,
|
||||
const STPath& spSourcePath,
|
||||
@@ -689,6 +708,7 @@ void RippleCalc::setCanonical(STPathSet& spsDst, const std::vector<PathState::po
|
||||
// cLog(lsDEBUG) << boost::str(boost::format("SET: setCanonical< %d") % spsDst.size());
|
||||
}
|
||||
|
||||
// This is for debugging not end users. Output names can be changed without warning.
|
||||
Json::Value PathState::getJson() const
|
||||
{
|
||||
Json::Value jvPathState(Json::objectValue);
|
||||
@@ -769,7 +789,7 @@ Json::Value PathState::getJson() const
|
||||
|
||||
// If needed, advance to next funded offer.
|
||||
// - Automatically advances to first offer.
|
||||
// - Set bEntryAdvance to advance to next entry.
|
||||
// --> bEntryAdvance: true, to advance to next entry. false, recalculate.
|
||||
// <-- uOfferIndex : 0=end of list.
|
||||
TER RippleCalc::calcNodeAdvance(
|
||||
const unsigned int uNode, // 0 < uNode < uLast
|
||||
@@ -1062,8 +1082,8 @@ TER RippleCalc::calcNodeAdvance(
|
||||
}
|
||||
|
||||
// Between offer nodes, the fee charged may vary. Therefore, process one inbound offer at a time. Propagate the inbound offer's
|
||||
// requirements to the previous node. The previous node adjusts the amount output and the amount spent on fees. Continue process
|
||||
// till request is satisified while we the rate does not increase past the initial rate.
|
||||
// requirements to the previous node. The previous node adjusts the amount output and the amount spent on fees. Continue
|
||||
// processing until the request is satisified as long as the rate does not increase past the initial rate.
|
||||
TER RippleCalc::calcNodeDeliverRev(
|
||||
const unsigned int uNode, // 0 < uNode < uLast
|
||||
PathState& psCur,
|
||||
@@ -1152,6 +1172,9 @@ TER RippleCalc::calcNodeDeliverRev(
|
||||
else if (saOutFeeRate < saRateMax)
|
||||
{
|
||||
// Reducing rate. Additional offers will only considered for this increment if they are at least this good.
|
||||
// At this point, the overall rate is reducing, while the overall rate is not saOutFeeRate, it would be wrong to add
|
||||
// anthing with a rate above saOutFeeRate.
|
||||
// The rate would be reduced if the current offer was from the issuer and the previous offer wasn't.
|
||||
|
||||
saRateMax = saOutFeeRate;
|
||||
|
||||
@@ -1163,7 +1186,8 @@ TER RippleCalc::calcNodeDeliverRev(
|
||||
STAmount saOutPass = std::min(std::min(saOfferFunds, saTakerGets), saOutReq-saOutAct); // Offer maximum out - assuming no out fees.
|
||||
// Amount charged to the offer owner.
|
||||
// The fee goes to issuer. The fee is paid by offer owner and not passed as a cost to taker.
|
||||
STAmount saOutPlusFees = STAmount::multiply(saOutPass, saOutFeeRate); // Offer out with fees.
|
||||
// Round down: prefer liquidity rather than microscopic fees.
|
||||
STAmount saOutPlusFees = STAmount::mulRound(saOutPass, saOutFeeRate, false); // Offer out with fees.
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: saOutReq=%s saOutAct=%s saTakerGets=%s saOutPass=%s saOutPlusFees=%s saOfferFunds=%s")
|
||||
% saOutReq
|
||||
@@ -1178,7 +1202,8 @@ TER RippleCalc::calcNodeDeliverRev(
|
||||
// Offer owner can not cover all fees, compute saOutPass based on saOfferFunds.
|
||||
|
||||
saOutPlusFees = saOfferFunds;
|
||||
saOutPass = STAmount::divide(saOutPlusFees, saOutFeeRate);
|
||||
// Round up: prefer liquidity rather than microscopic fees.
|
||||
saOutPass = STAmount::divRound(saOutPlusFees, saOutFeeRate, true);
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Total exceeds fees: saOutPass=%s saOutPlusFees=%s saOfferFunds=%s")
|
||||
% saOutPass
|
||||
@@ -1188,8 +1213,7 @@ TER RippleCalc::calcNodeDeliverRev(
|
||||
|
||||
// Compute portion of input needed to cover actual output.
|
||||
|
||||
// XXX This needs to round up!
|
||||
STAmount saInPassReq = STAmount::multiply(saOutPass, saOfrRate, saTakerPays);
|
||||
STAmount saInPassReq = STAmount::mulRound(saOutPass, saOfrRate, saTakerPays, true);
|
||||
STAmount saInPassAct;
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: saInPassReq=%s saOfrRate=%s saOutPass=%s saOutPlusFees=%s")
|
||||
@@ -1198,8 +1222,16 @@ TER RippleCalc::calcNodeDeliverRev(
|
||||
% saOutPass
|
||||
% saOutPlusFees);
|
||||
|
||||
if (!saInPassReq)
|
||||
{
|
||||
// After rounding did not want anything.
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: micro offer is unfunded."));
|
||||
|
||||
bEntryAdvance = true;
|
||||
continue;
|
||||
}
|
||||
// Find out input amount actually available at current rate.
|
||||
if (!!uPrvAccountID)
|
||||
else if (!!uPrvAccountID)
|
||||
{
|
||||
// account --> OFFER --> ?
|
||||
// Due to node expansion, previous is guaranteed to be the issuer.
|
||||
@@ -1236,8 +1268,9 @@ TER RippleCalc::calcNodeDeliverRev(
|
||||
if (saInPassAct != saInPassReq)
|
||||
{
|
||||
// Adjust output to conform to limited input.
|
||||
saOutPass = STAmount::divide(saInPassAct, saOfrRate, saTakerGets);
|
||||
saOutPlusFees = STAmount::multiply(saOutPass, saOutFeeRate);
|
||||
// XXX Verify it is impossible for these to be larger than available funds.
|
||||
saOutPass = STAmount::divRound(saInPassAct, saOfrRate, saTakerGets, true);
|
||||
saOutPlusFees = STAmount::mulRound(saOutPass, saOutFeeRate, true);
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: adjusted: saOutPass=%s saOutPlusFees=%s")
|
||||
% saOutPass
|
||||
@@ -1281,15 +1314,16 @@ TER RippleCalc::calcNodeDeliverRev(
|
||||
// Offer became unfunded.
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: offer became unfunded."));
|
||||
|
||||
bEntryAdvance = true;
|
||||
bEntryAdvance = true; // XXX When don't we want to set advance?
|
||||
}
|
||||
|
||||
saOutAct += saOutPass;
|
||||
saPrvDlvReq += saInPassAct;
|
||||
}
|
||||
|
||||
// XXX Perhaps need to check if partial is okay to relax this?
|
||||
if (tesSUCCESS == terResult && !saOutAct)
|
||||
terResult = tecPATH_DRY;
|
||||
terResult = tecPATH_DRY; // Unable to meet request, consider path dry.
|
||||
|
||||
return terResult;
|
||||
}
|
||||
@@ -1371,12 +1405,12 @@ TER RippleCalc::calcNodeDeliverFwd(
|
||||
|
||||
// First calculate assuming no output fees: saInPassAct, saInPassFees, saOutPassAct
|
||||
|
||||
STAmount saOutFunded = std::min(saOfferFunds, saTakerGets); // Offer maximum out - If there are no out fees.
|
||||
STAmount saInFunded = STAmount::multiply(saOutFunded, saOfrRate, saTakerPays); // Offer maximum in - Limited by by payout.
|
||||
STAmount saInTotal = STAmount::multiply(saInFunded, saInTransRate); // Offer maximum in with fees.
|
||||
STAmount saInSum = std::min(saInTotal, saInReq-saInAct-saInFees); // In limited by remaining.
|
||||
STAmount saInPassAct = STAmount::divide(saInSum, saInFeeRate); // In without fees.
|
||||
STAmount saOutPassMax = STAmount::divide(saInPassAct, saOfrRate, saTakerGets); // Out limited by in remaining.
|
||||
STAmount saOutFunded = std::min(saOfferFunds, saTakerGets); // Offer maximum out - If there are no out fees.
|
||||
STAmount saInFunded = STAmount::mulRound(saOutFunded, saOfrRate, saTakerPays, true); // Offer maximum in - Limited by by payout.
|
||||
STAmount saInTotal = STAmount::mulRound(saInFunded, saInTransRate, true); // Offer maximum in with fees.
|
||||
STAmount saInSum = std::min(saInTotal, saInReq-saInAct-saInFees); // In limited by remaining.
|
||||
STAmount saInPassAct = STAmount::divRound(saInSum, saInFeeRate, true); // In without fees.
|
||||
STAmount saOutPassMax = STAmount::divRound(saInPassAct, saOfrRate, saTakerGets, true); // Out limited by in remaining.
|
||||
|
||||
STAmount saInPassFeesMax = saInSum-saInPassAct;
|
||||
|
||||
@@ -1469,8 +1503,8 @@ TER RippleCalc::calcNodeDeliverFwd(
|
||||
{
|
||||
// Fraction of output amount.
|
||||
// Output fees are paid by offer owner and not passed to previous.
|
||||
saInPassAct = STAmount::multiply(saOutPassAct, saOfrRate, saInReq);
|
||||
saInPassFees = std::min(saInPassFeesMax, STAmount::multiply(saInPassAct, saInFeeRate));
|
||||
saInPassAct = STAmount::mulRound(saOutPassAct, saOfrRate, saInReq, true);
|
||||
saInPassFees = std::min(saInPassFeesMax, STAmount::mulRound(saInPassAct, saInFeeRate, true));
|
||||
}
|
||||
|
||||
// Do outbound debiting.
|
||||
@@ -1622,7 +1656,7 @@ TER RippleCalc::calcNodeOfferFwd(
|
||||
|
||||
}
|
||||
|
||||
// Compute how much might flow for the node for the pass. Don not actually adjust balances.
|
||||
// Compute how much might flow for the node for the pass. Does not actually adjust balances.
|
||||
// uQualityIn -> uQualityOut
|
||||
// saPrvReq -> saCurReq
|
||||
// sqPrvAct -> saCurAct
|
||||
@@ -1698,7 +1732,7 @@ void RippleCalc::calcNodeRipple(
|
||||
const uint160 uCurIssuerID = saCur.getIssuer();
|
||||
// const uint160 uPrvIssuerID = saPrv.getIssuer();
|
||||
|
||||
STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID);
|
||||
STAmount saCurIn = STAmount::divRound(STAmount::mulRound(saCur, uQualityOut, uCurrencyID, uCurIssuerID, true), uQualityIn, uCurrencyID, uCurIssuerID, true);
|
||||
|
||||
cLog(lsTRACE) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText());
|
||||
if (bPrvUnlimited || saCurIn <= saPrv)
|
||||
@@ -1711,7 +1745,7 @@ void RippleCalc::calcNodeRipple(
|
||||
else
|
||||
{
|
||||
// A part of cur. All of prv. (cur as driver)
|
||||
STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID, uCurIssuerID), uQualityOut, uCurrencyID, uCurIssuerID);
|
||||
STAmount saCurOut = STAmount::divRound(STAmount::mulRound(saPrv, uQualityIn, uCurrencyID, uCurIssuerID, true), uQualityOut, uCurrencyID, uCurIssuerID, true);
|
||||
cLog(lsTRACE) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText());
|
||||
|
||||
saCurAct += saCurOut;
|
||||
@@ -2209,7 +2243,7 @@ TER RippleCalc::calcNodeAccountFwd(
|
||||
|
||||
STAmount saIssueCrd = uQualityIn >= QUALITY_ONE
|
||||
? saPrvIssueReq // No fee.
|
||||
: STAmount::multiply(saPrvIssueReq, STAmount(CURRENCY_ONE, ACCOUNT_ONE, uQualityIn, -9)); // Amount to credit.
|
||||
: STAmount::mulRound(saPrvIssueReq, STAmount(CURRENCY_ONE, ACCOUNT_ONE, uQualityIn, -9), false); // Amount to credit.
|
||||
|
||||
// Amount to credit. Credit for less than received as a surcharge.
|
||||
saCurReceive = saPrvRedeemReq+saIssueCrd;
|
||||
|
||||
@@ -12,17 +12,11 @@ class ConsensusTransSetSF : public SHAMapSyncFilter
|
||||
{ // sync filter for transaction sets during consensus building
|
||||
public:
|
||||
ConsensusTransSetSF() { ; }
|
||||
|
||||
virtual void gotNode(const SHAMapNode& id, const uint256& nodeHash,
|
||||
const std::vector<unsigned char>& nodeData, SHAMapTreeNode::TNType)
|
||||
{
|
||||
// WRITEME: If 'isLeaf' is true, this is a transaction
|
||||
theApp->getTempNodeCache().store(nodeHash, nodeData);
|
||||
}
|
||||
virtual bool haveNode(const SHAMapNode& id, const uint256& nodeHash, std::vector<unsigned char>& nodeData)
|
||||
{
|
||||
// WRITEME: We could check our own map, we could check transaction tables
|
||||
return theApp->getTempNodeCache().retrieve(nodeHash, nodeData);
|
||||
}
|
||||
const std::vector<unsigned char>& nodeData, SHAMapTreeNode::TNType);
|
||||
|
||||
virtual bool haveNode(const SHAMapNode& id, const uint256& nodeHash, std::vector<unsigned char>& nodeData);
|
||||
};
|
||||
|
||||
// This class is only needed on add functions
|
||||
|
||||
@@ -442,7 +442,7 @@ public:
|
||||
static STAmount divRound(const STAmount& v1, const STAmount& v2, const STAmount& saUnit, bool roundUp)
|
||||
{ return divRound(v1, v2, saUnit.getCurrency(), saUnit.getIssuer(), roundUp); }
|
||||
static STAmount divRound(const STAmount& v1, const STAmount& v2, bool roundUp)
|
||||
{ return divRound(v1, v2, v2.getCurrency(), v2.getIssuer(), roundUp); }
|
||||
{ return divRound(v1, v2, v1.getCurrency(), v1.getIssuer(), roundUp); }
|
||||
|
||||
// Someone is offering X for Y, what is the rate?
|
||||
// Rate: smaller is better, the taker wants the most out: in/out
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
bool checkSign() const;
|
||||
void updateID() { mTransactionID=mTransaction->getTransactionID(); }
|
||||
|
||||
SerializedTransaction::pointer getSTransaction() { return mTransaction; }
|
||||
SerializedTransaction::ref getSTransaction() { return mTransaction; }
|
||||
|
||||
const uint256& getID() const { return mTransactionID; }
|
||||
const RippleAddress& getFromAccount() const { return mAccountFrom; }
|
||||
|
||||
219
src/cpp/ripple/TransactionAcquire.cpp
Normal file
219
src/cpp/ripple/TransactionAcquire.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
#include "LedgerConsensus.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "../json/writer.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "NetworkOPs.h"
|
||||
#include "SerializedValidation.h"
|
||||
#include "Log.h"
|
||||
#include "SHAMapSync.h"
|
||||
#include "HashPrefixes.h"
|
||||
|
||||
#define TX_ACQUIRE_TIMEOUT 250
|
||||
|
||||
typedef std::map<uint160, LedgerProposal::pointer>::value_type u160_prop_pair;
|
||||
typedef std::map<uint256, LCTransaction::pointer>::value_type u256_lct_pair;
|
||||
|
||||
SETUP_LOG();
|
||||
DECLARE_INSTANCE(TransactionAcquire);
|
||||
|
||||
TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false)
|
||||
{
|
||||
mMap = boost::make_shared<SHAMap>(smtTRANSACTION, hash);
|
||||
}
|
||||
|
||||
void TransactionAcquire::done()
|
||||
{
|
||||
if (mFailed)
|
||||
{
|
||||
cLog(lsWARNING) << "Failed to acquire TX set " << mHash;
|
||||
theApp->getOPs().mapComplete(mHash, SHAMap::pointer());
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "Acquired TX set " << mHash;
|
||||
mMap->setImmutable();
|
||||
theApp->getOPs().mapComplete(mHash, mMap);
|
||||
}
|
||||
theApp->getMasterLedgerAcquire().dropLedger(mHash);
|
||||
}
|
||||
|
||||
void TransactionAcquire::onTimer(bool progress)
|
||||
{
|
||||
if (!getPeerCount())
|
||||
{ // out of peers
|
||||
cLog(lsWARNING) << "Out of peers for TX set " << getHash();
|
||||
|
||||
bool found = false;
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
{
|
||||
if (peer->hasTxSet(getHash()))
|
||||
{
|
||||
found = true;
|
||||
peerHas(peer);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
peerHas(peer);
|
||||
}
|
||||
}
|
||||
else if (!progress)
|
||||
trigger(Peer::pointer());
|
||||
}
|
||||
|
||||
boost::weak_ptr<PeerSet> TransactionAcquire::pmDowncast()
|
||||
{
|
||||
return boost::shared_polymorphic_downcast<PeerSet>(shared_from_this());
|
||||
}
|
||||
|
||||
void TransactionAcquire::trigger(Peer::ref peer)
|
||||
{
|
||||
if (mComplete || mFailed)
|
||||
{
|
||||
cLog(lsINFO) << "complete or failed";
|
||||
return;
|
||||
}
|
||||
if (!mHaveRoot)
|
||||
{
|
||||
cLog(lsTRACE) << "TransactionAcquire::trigger " << (peer ? "havePeer" : "noPeer") << " no root";
|
||||
ripple::TMGetLedger tmGL;
|
||||
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
|
||||
tmGL.set_itype(ripple::liTS_CANDIDATE);
|
||||
if (getTimeouts() != 0)
|
||||
tmGL.set_querytype(ripple::qtINDIRECT);
|
||||
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<SHAMapNode> nodeIDs;
|
||||
std::vector<uint256> nodeHashes;
|
||||
ConsensusTransSetSF sf;
|
||||
mMap->getMissingNodes(nodeIDs, nodeHashes, 256, &sf);
|
||||
if (nodeIDs.empty())
|
||||
{
|
||||
if (mMap->isValid())
|
||||
mComplete = true;
|
||||
else
|
||||
mFailed = true;
|
||||
done();
|
||||
return;
|
||||
}
|
||||
ripple::TMGetLedger tmGL;
|
||||
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
|
||||
tmGL.set_itype(ripple::liTS_CANDIDATE);
|
||||
if (getTimeouts() != 0)
|
||||
tmGL.set_querytype(ripple::qtINDIRECT);
|
||||
BOOST_FOREACH(SHAMapNode& it, nodeIDs)
|
||||
*(tmGL.add_nodeids()) = it.getRawString();
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
}
|
||||
|
||||
SMAddNode TransactionAcquire::takeNodes(const std::list<SHAMapNode>& nodeIDs,
|
||||
const std::list< std::vector<unsigned char> >& data, Peer::ref peer)
|
||||
{
|
||||
if (mComplete)
|
||||
{
|
||||
cLog(lsTRACE) << "TX set complete";
|
||||
return SMAddNode();
|
||||
}
|
||||
if (mFailed)
|
||||
{
|
||||
cLog(lsTRACE) << "TX set failed";
|
||||
return SMAddNode();
|
||||
}
|
||||
try
|
||||
{
|
||||
if (nodeIDs.empty())
|
||||
return SMAddNode::invalid();
|
||||
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
|
||||
std::list< std::vector<unsigned char> >::const_iterator nodeDatait = data.begin();
|
||||
ConsensusTransSetSF sf;
|
||||
while (nodeIDit != nodeIDs.end())
|
||||
{
|
||||
if (nodeIDit->isRoot())
|
||||
{
|
||||
if (mHaveRoot)
|
||||
{
|
||||
cLog(lsWARNING) << "Got root TXS node, already have it";
|
||||
return SMAddNode();
|
||||
}
|
||||
if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE, NULL))
|
||||
{
|
||||
cLog(lsWARNING) << "TX acquire got bad root node";
|
||||
return SMAddNode::invalid();
|
||||
}
|
||||
else
|
||||
mHaveRoot = true;
|
||||
}
|
||||
else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &sf))
|
||||
{
|
||||
cLog(lsWARNING) << "TX acquire got bad non-root node";
|
||||
return SMAddNode::invalid();
|
||||
}
|
||||
++nodeIDit;
|
||||
++nodeDatait;
|
||||
}
|
||||
trigger(peer);
|
||||
progress();
|
||||
return SMAddNode::useful();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cLog(lsERROR) << "Peer sends us junky transaction node data";
|
||||
return SMAddNode::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsensusTransSetSF::gotNode(const SHAMapNode& id, const uint256& nodeHash,
|
||||
const std::vector<unsigned char>& nodeData, SHAMapTreeNode::TNType type)
|
||||
{
|
||||
theApp->getTempNodeCache().store(nodeHash, nodeData);
|
||||
if ((type == SHAMapTreeNode::tnTRANSACTION_NM) && (nodeData.size() > 16))
|
||||
{ // this is a transaction, and we didn't have it
|
||||
cLog(lsDEBUG) << "Node on our acquiring TX set is TXN we don't have";
|
||||
try
|
||||
{
|
||||
Serializer s(nodeData.begin() + 4, nodeData.end()); // skip prefix
|
||||
SerializerIterator sit(s);
|
||||
SerializedTransaction::pointer stx = boost::make_shared<SerializedTransaction>(boost::ref(sit));
|
||||
assert(stx->getTransactionID() == nodeHash);
|
||||
theApp->getJobQueue().addJob(jtTRANSACTION, "TXS->TXN",
|
||||
BIND_TYPE(&NetworkOPs::submitTransaction, &theApp->getOPs(), P_1, stx, NetworkOPs::stCallback()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cLog(lsWARNING) << "Fetched invalid transaction in proposed set";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ConsensusTransSetSF::haveNode(const SHAMapNode& id, const uint256& nodeHash,
|
||||
std::vector<unsigned char>& nodeData)
|
||||
{
|
||||
if (theApp->getTempNodeCache().retrieve(nodeHash, nodeData))
|
||||
return true;
|
||||
|
||||
Transaction::pointer txn = Transaction::load(nodeHash);
|
||||
if (txn)
|
||||
{ // this is a transaction, and we have it
|
||||
cLog(lsDEBUG) << "Node in our acquiring TX set is TXN we have";
|
||||
Serializer s;
|
||||
s.add32(sHP_TransactionID);
|
||||
txn->getSTransaction()->add(s, true);
|
||||
assert(s.getSHA512Half() == nodeHash);
|
||||
nodeData = s.peekData();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -82,6 +82,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman)
|
||||
{ terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." },
|
||||
{ terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." },
|
||||
{ terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." },
|
||||
{ terNO_AUTH, "terNO_AUTH", "Not authorized to hold IOUs." },
|
||||
{ terNO_LINE, "terNO_LINE", "No such line." },
|
||||
{ terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction." },
|
||||
{ terOWNERS, "terOWNERS", "Non-zero owner count." },
|
||||
|
||||
@@ -95,6 +95,7 @@ enum TER // aka TransactionEngineResult
|
||||
terFUNDS_SPENT, // This is a free transaction, therefore don't burden network.
|
||||
terINSUF_FEE_B, // Can't pay fee, therefore don't burden network.
|
||||
terNO_ACCOUNT, // Can't pay fee, therefore don't burden network.
|
||||
terNO_AUTH, // Not authorized to hold IOUs.
|
||||
terNO_LINE, // Internal flag.
|
||||
terOWNERS, // Can't succeed with non-zero owner count.
|
||||
terPRE_SEQ, // Can't pay fee, no point in forwarding, therefore don't burden network.
|
||||
|
||||
@@ -34,7 +34,7 @@ VSpointer ValidationCollection::findSet(const uint256& ledgerHash)
|
||||
return mValidations.fetch(ledgerHash);
|
||||
}
|
||||
|
||||
bool ValidationCollection::addValidation(SerializedValidation::ref val)
|
||||
bool ValidationCollection::addValidation(SerializedValidation::ref val, const std::string& source)
|
||||
{
|
||||
RippleAddress signer = val->getSignerPublic();
|
||||
bool isCurrent = false;
|
||||
@@ -52,7 +52,8 @@ bool ValidationCollection::addValidation(SerializedValidation::ref val)
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "Node " << signer.humanNodePublic() << " not in UNL";
|
||||
cLog(lsDEBUG) << "Node " << signer.humanNodePublic() << " not in UNL st=" << val->getSignTime() <<
|
||||
", hash=" << val->getLedgerHash() << ", shash=" << val->getSigningHash() << " src=" << source;
|
||||
}
|
||||
|
||||
uint256 hash = val->getLedgerHash();
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
ValidationCollection() : mValidations("Validations", 128, 600), mWriting(false)
|
||||
{ mStaleValidations.reserve(512); }
|
||||
|
||||
bool addValidation(SerializedValidation::ref);
|
||||
bool addValidation(SerializedValidation::ref, const std::string& source);
|
||||
ValidationSet getValidations(const uint256& ledger);
|
||||
void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted);
|
||||
void getValidationTypes(const uint256& ledger, int& full, int& partial);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#define SERVER_VERSION_MAJOR 0
|
||||
#define SERVER_VERSION_MINOR 8
|
||||
#define SERVER_VERSION_SUB "-a"
|
||||
#define SERVER_VERSION_SUB "-b"
|
||||
#define SERVER_NAME "Ripple"
|
||||
|
||||
#define SV_STRINGIZE(x) SV_STRINGIZE2(x)
|
||||
|
||||
@@ -48,6 +48,7 @@ static DH* handleTmpDh(SSL* ssl, int is_export, int iKeyLength)
|
||||
|
||||
void WSDoor::startListening()
|
||||
{
|
||||
NameThread("websocket");
|
||||
// Generate a single SSL context for use by all connections.
|
||||
boost::shared_ptr<boost::asio::ssl::context> mCtx;
|
||||
mCtx = boost::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
|
||||
|
||||
@@ -84,6 +84,7 @@ void printHelp(const po::options_description& desc)
|
||||
cerr << " data_store <key> <value>" << endl;
|
||||
#endif
|
||||
cerr << " get_counts" << endl;
|
||||
cerr << " json <method> <json>" << endl;
|
||||
cerr << " ledger [<id>|current|closed|validated] [full]" << endl;
|
||||
cerr << " ledger_accept" << endl;
|
||||
cerr << " ledger_closed" << endl;
|
||||
@@ -127,6 +128,7 @@ void printHelp(const po::options_description& desc)
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
NameThread("main");
|
||||
int iResult = 0;
|
||||
po::variables_map vm; // Map of options.
|
||||
|
||||
@@ -148,6 +150,7 @@ int main(int argc, char* argv[])
|
||||
("ledger", po::value<std::string>(), "Load the specified ledger and start from .")
|
||||
("start", "Start from a fresh Ledger.")
|
||||
("net", "Get the initial ledger from the network.")
|
||||
("fg", "Run in the foreground.")
|
||||
;
|
||||
|
||||
// Interpret positional arguments as --parameters.
|
||||
@@ -185,6 +188,14 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (HaveSustain() &&
|
||||
!vm.count("parameters") && !vm.count("fg") && !vm.count("standalone") && !vm.count("unittest"))
|
||||
{
|
||||
std::string logMe = DoSustain();
|
||||
if (!logMe.empty())
|
||||
Log(lsWARNING) << logMe;
|
||||
}
|
||||
|
||||
if (vm.count("quiet"))
|
||||
Log::setMinSeverity(lsFATAL, true);
|
||||
else if (vm.count("verbose"))
|
||||
@@ -248,11 +259,13 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
// No arguments. Run server.
|
||||
setupServer();
|
||||
NameThread("io");
|
||||
startServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Have a RPC command.
|
||||
NameThread("rpc");
|
||||
std::vector<std::string> vCmd = vm["parameters"].as<std::vector<std::string> >();
|
||||
|
||||
iResult = commandLineRPC(vCmd);
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#include "utils.h"
|
||||
#include "uint256.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/types.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
@@ -9,6 +15,9 @@
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "uint256.h"
|
||||
|
||||
void getRand(unsigned char *buf, int num)
|
||||
{
|
||||
if (RAND_bytes(buf, num) != 1)
|
||||
@@ -333,6 +342,112 @@ uint32_t be32toh(uint32_t value)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef PR_SET_NAME
|
||||
#define HAVE_NAME_THREAD
|
||||
extern void NameThread(const char* n)
|
||||
{
|
||||
static std::string pName;
|
||||
|
||||
if (pName.empty())
|
||||
{
|
||||
std::ifstream cLine("/proc/self/cmdline", std::ios::in);
|
||||
cLine >> pName;
|
||||
if (pName.empty())
|
||||
pName = "rippled";
|
||||
else
|
||||
{
|
||||
size_t zero = pName.find_first_of('\0');
|
||||
if ((zero != std::string::npos) && (zero != 0))
|
||||
pName = pName.substr(0, zero);
|
||||
size_t slash = pName.find_last_of('/');
|
||||
if (slash != std::string::npos)
|
||||
pName = pName.substr(slash + 1);
|
||||
}
|
||||
pName += " ";
|
||||
}
|
||||
|
||||
prctl(PR_SET_NAME, (pName + n).c_str(), 0, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_NAME_THREAD
|
||||
extern void NameThread(const char*)
|
||||
{ ; }
|
||||
#endif
|
||||
|
||||
#ifdef __unix__
|
||||
|
||||
static pid_t pManager = static_cast<pid_t>(0);
|
||||
static pid_t pChild = static_cast<pid_t>(0);
|
||||
|
||||
static void pass_signal(int a)
|
||||
{
|
||||
kill(pChild, a);
|
||||
}
|
||||
|
||||
static void stop_manager(int)
|
||||
{
|
||||
kill(pChild, SIGINT);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
bool HaveSustain()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string StopSustain()
|
||||
{
|
||||
if (getppid() != pManager)
|
||||
return std::string();
|
||||
kill(pManager, SIGHUP);
|
||||
return "Terminating monitor";
|
||||
}
|
||||
|
||||
std::string DoSustain()
|
||||
{
|
||||
int childCount = 0;
|
||||
pManager = getpid();
|
||||
signal(SIGINT, stop_manager);
|
||||
signal(SIGHUP, stop_manager);
|
||||
signal(SIGUSR1, pass_signal);
|
||||
signal(SIGUSR2, pass_signal);
|
||||
while (1)
|
||||
{
|
||||
++childCount;
|
||||
pChild = fork();
|
||||
if (pChild == -1)
|
||||
_exit(0);
|
||||
if (pChild == 0)
|
||||
{
|
||||
NameThread("main");
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGHUP, SIG_DFL);
|
||||
signal(SIGUSR1, SIG_DFL);
|
||||
signal(SIGUSR2, SIG_DFL);
|
||||
return str(boost::format("Launching child %d") % childCount);;
|
||||
}
|
||||
NameThread(boost::str(boost::format("#%d") % childCount).c_str());
|
||||
do
|
||||
{
|
||||
int i;
|
||||
sleep(10);
|
||||
waitpid(-1, &i, 0);
|
||||
}
|
||||
while (kill(pChild, 0) == 0);
|
||||
rename("core", boost::str(boost::format("core.%d") % static_cast<int>(pChild)).c_str());
|
||||
rename("debug.log", boost::str(boost::format("debug.log.%d") % static_cast<int>(pChild)).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool HaveSustain() { return false; }
|
||||
std::string DoSustain() { return std::string; }
|
||||
std::string StopSustain() { return std::string; }
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( Utils)
|
||||
|
||||
BOOST_AUTO_TEST_CASE( ParseUrl )
|
||||
|
||||
@@ -286,6 +286,12 @@ template<typename T, typename U> T range_check_cast(const U& value, const T& min
|
||||
|
||||
bool parseUrl(const std::string& strUrl, std::string& strScheme, std::string& strDomain, int& iPort, std::string& strPath);
|
||||
|
||||
extern void NameThread(const char *);
|
||||
|
||||
extern bool HaveSustain();
|
||||
extern std::string StopSustain();
|
||||
extern std::string DoSustain();
|
||||
|
||||
#if (!defined(FORCE_NO_C11X) && (__cplusplus > 201100L)) || defined(FORCE_C11X)
|
||||
|
||||
#define C11X
|
||||
|
||||
Reference in New Issue
Block a user