mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
@@ -436,7 +436,7 @@ Amount.prototype.parse_native = function(j) {
|
||||
var m;
|
||||
|
||||
if ('string' === typeof j)
|
||||
m = j.match(/^(-?)(\d+)(\.\d{1,6})?$/);
|
||||
m = j.match(/^(-?)(\d+)(\.\d{0,6})?$/);
|
||||
|
||||
if (m) {
|
||||
if (undefined === m[3]) {
|
||||
@@ -445,7 +445,7 @@ Amount.prototype.parse_native = function(j) {
|
||||
this.value = new BigInteger(m[2]);
|
||||
}
|
||||
else {
|
||||
// Decimal notation
|
||||
// Float notation
|
||||
|
||||
var int_part = (new BigInteger(m[2])).multiply(exports.consts.bi_xns_unit);
|
||||
var fraction_part = (new BigInteger(m[3])).multiply(new BigInteger(String(Math.pow(10, 1+exports.consts.xns_precision-m[3].length))));
|
||||
|
||||
@@ -216,10 +216,10 @@ Remote.flags = {
|
||||
|
||||
// XXX This needs to be determined from the network.
|
||||
Remote.fees = {
|
||||
'default' : Amount.from_json("100"),
|
||||
'account_create' : Amount.from_json("1000"),
|
||||
'default' : Amount.from_json("10"),
|
||||
'account_create' : Amount.from_json("1000000000"),
|
||||
'nickname_create' : Amount.from_json("1000"),
|
||||
'offer' : Amount.from_json("100"),
|
||||
'offer' : Amount.from_json("10"),
|
||||
};
|
||||
|
||||
// Set the emited state: 'online' or 'offline'
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
<ClCompile Include="src\DeterministicKeys.cpp" />
|
||||
<ClCompile Include="src\ECIES.cpp" />
|
||||
<ClCompile Include="src\FieldNames.cpp" />
|
||||
<ClCompile Include="src\JobQueue.cpp" />
|
||||
<ClCompile Include="src\HashedObject.cpp" />
|
||||
<ClCompile Include="src\HTTPRequest.cpp" />
|
||||
<ClCompile Include="src\HttpsClient.cpp" />
|
||||
@@ -275,8 +276,8 @@
|
||||
<None Include="SConstruct" />
|
||||
<CustomBuild Include="src\ripple.proto">
|
||||
<FileType>Document</FileType>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">d:/code/protoc-2.4.1-win32/protoc -I=..\newcoin --cpp_out=D:\code\newcoin\obj\ ..\newcoin/src/ripple.proto</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">D:\code\newcoin\obj\src\ripple.pb.h</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/code/protoc-2.4.1-win32/protoc -I=..\newcoin --cpp_out=\code\newcoin\obj\ ..\newcoin/src/ripple.proto</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\code\newcoin\obj\src\ripple.pb.h</Outputs>
|
||||
</CustomBuild>
|
||||
<None Include="test\buster.js" />
|
||||
<None Include="test\server.js" />
|
||||
|
||||
@@ -780,7 +780,6 @@ STAmount operator+(const STAmount& v1, const STAmount& v2)
|
||||
if (v1.mIsNative)
|
||||
return STAmount(v1.getFName(), v1.getSNValue() + v2.getSNValue());
|
||||
|
||||
|
||||
int ov1 = v1.mOffset, ov2 = v2.mOffset;
|
||||
int64 vv1 = static_cast<int64>(v1.mValue), vv2 = static_cast<int64>(v2.mValue);
|
||||
if (v1.mIsNegative) vv1 = -vv1;
|
||||
|
||||
@@ -46,6 +46,7 @@ Application::Application() :
|
||||
{
|
||||
RAND_bytes(mNonce256.begin(), mNonce256.size());
|
||||
RAND_bytes(reinterpret_cast<unsigned char *>(&mNonceST), sizeof(mNonceST));
|
||||
mJobQueue.setThreadCount();
|
||||
}
|
||||
|
||||
extern const char *RpcDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[], *NetNodeDBInit[];
|
||||
@@ -54,6 +55,7 @@ extern int RpcDBCount, TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount
|
||||
void Application::stop()
|
||||
{
|
||||
mIOService.stop();
|
||||
mJobQueue.shutdown();
|
||||
mHashedObjectStore.bulkWrite();
|
||||
mValidations.flush();
|
||||
mAuxService.stop();
|
||||
@@ -70,9 +72,10 @@ void Application::run()
|
||||
{
|
||||
assert(mTxnDB == NULL);
|
||||
if (!theConfig.DEBUG_LOGFILE.empty())
|
||||
{ // Let DEBUG messages go to the file but only WARNING or higher to regular output
|
||||
{ // Let DEBUG messages go to the file but only WARNING or higher to regular output (unless verbose)
|
||||
Log::setLogFile(theConfig.DEBUG_LOGFILE);
|
||||
LogPartition::setSeverity(lsDEBUG);
|
||||
if (Log::getMinSeverity() > lsDEBUG)
|
||||
LogPartition::setSeverity(lsDEBUG);
|
||||
}
|
||||
|
||||
boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService));
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Suppression.h"
|
||||
#include "SNTPClient.h"
|
||||
#include "../database/database.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
|
||||
class RPCDoor;
|
||||
@@ -53,6 +54,7 @@ class Application
|
||||
SuppressionTable mSuppressions;
|
||||
HashedObjectStore mHashedObjectStore;
|
||||
SNTPClient mSNTPClient;
|
||||
JobQueue mJobQueue;
|
||||
|
||||
DatabaseCon *mRpcDB, *mTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB;
|
||||
|
||||
@@ -90,6 +92,7 @@ public:
|
||||
NodeCache& getTempNodeCache() { return mTempNodeCache; }
|
||||
HashedObjectStore& getHashedObjectStore() { return mHashedObjectStore; }
|
||||
ValidationCollection& getValidations() { return mValidations; }
|
||||
JobQueue& getJobQueue() { return mJobQueue; }
|
||||
bool isNew(const uint256& s) { return mSuppressions.addSuppression(s); }
|
||||
bool isNew(const uint160& s) { return mSuppressions.addSuppression(s); }
|
||||
bool running() { return mTxnDB != NULL; }
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
#define SECTION_VALIDATORS "validators"
|
||||
#define SECTION_VALIDATORS_SITE "validators_site"
|
||||
|
||||
// Fees are in XNB.
|
||||
#define DEFAULT_FEE_DEFAULT 100
|
||||
#define DEFAULT_FEE_ACCOUNT_CREATE 1000
|
||||
// Fees are in XNS.
|
||||
#define DEFAULT_FEE_DEFAULT 10
|
||||
#define DEFAULT_FEE_ACCOUNT_CREATE 1000*SYSTEM_CURRENCY_PARTS
|
||||
#define DEFAULT_FEE_NICKNAME_CREATE 1000
|
||||
#define DEFAULT_FEE_OFFER DEFAULT_FEE_DEFAULT
|
||||
#define DEFAULT_FEE_OPERATION 1
|
||||
|
||||
@@ -330,6 +330,13 @@ Json::Value ConnectionPool::getPeersJson()
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ConnectionPool::getPeerCount()
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
return mConnectedMap.size();
|
||||
}
|
||||
|
||||
std::vector<Peer::pointer> ConnectionPool::getPeerVector()
|
||||
{
|
||||
std::vector<Peer::pointer> ret;
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
// As client failed connect and be accepted.
|
||||
void peerClosed(Peer::ref peer, const std::string& strIp, int iPort);
|
||||
|
||||
int getPeerCount();
|
||||
Json::Value getPeersJson();
|
||||
std::vector<Peer::pointer> getPeerVector();
|
||||
|
||||
|
||||
@@ -26,6 +26,31 @@ SField sfIndex(STI_HASH256, 258, "index");
|
||||
#undef FIELD
|
||||
#undef TYPE
|
||||
|
||||
static int initFields()
|
||||
{
|
||||
sfHighQualityIn.setMeta(SFM_CHANGE); sfHighQualityOut.setMeta(SFM_CHANGE);
|
||||
sfLowQualityIn.setMeta(SFM_CHANGE); sfLowQualityOut.setMeta(SFM_CHANGE);
|
||||
|
||||
sfLowLimit.setMeta(SFM_ALWAYS); sfHighLimit.setMeta(SFM_ALWAYS);
|
||||
sfTakerPays.setMeta(SFM_ALWAYS); sfTakerGets.setMeta(SFM_ALWAYS);
|
||||
sfQualityIn.setMeta(SFM_ALWAYS); sfQualityOut.setMeta(SFM_ALWAYS);
|
||||
|
||||
sfBalance.setMeta(SFM_ALWAYS);
|
||||
|
||||
sfPublicKey.setMeta(SFM_CHANGE); sfMessageKey.setMeta(SFM_CHANGE);
|
||||
sfSigningPubKey.setMeta(SFM_CHANGE); sfAuthorizedKey.setMeta(SFM_CHANGE);
|
||||
sfSigningAccounts.setMeta(SFM_CHANGE);
|
||||
|
||||
sfWalletLocator.setMeta(SFM_CHANGE);
|
||||
sfNickname.setMeta(SFM_CHANGE);
|
||||
sfAmount.setMeta(SFM_ALWAYS);
|
||||
sfDomain.setMeta(SFM_CHANGE);
|
||||
sfOwner.setMeta(SFM_ALWAYS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const int f = initFields();
|
||||
|
||||
|
||||
SField::SField(SerializedTypeID tid, int fv) : fieldCode(FIELD_CODE(tid, fv)), fieldType(tid), fieldValue(fv)
|
||||
{ // call with the map mutex
|
||||
|
||||
@@ -33,6 +33,14 @@ enum SOE_Flags
|
||||
SOE_OPTIONAL = 1, // optional
|
||||
};
|
||||
|
||||
enum SF_Meta
|
||||
{
|
||||
SFM_NEVER = 0,
|
||||
SFM_CHANGE = 1,
|
||||
SFM_DELETE = 2,
|
||||
SFM_ALWAYS = 3
|
||||
};
|
||||
|
||||
class SField
|
||||
{
|
||||
public:
|
||||
@@ -51,16 +59,17 @@ public:
|
||||
const SerializedTypeID fieldType; // STI_*
|
||||
const int fieldValue; // Code number for protocol
|
||||
std::string fieldName;
|
||||
SF_Meta fieldMeta;
|
||||
|
||||
SField(int fc, SerializedTypeID tid, int fv, const char* fn) :
|
||||
fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn)
|
||||
fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn), fieldMeta(SFM_NEVER)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mapMutex);
|
||||
codeToField[fieldCode] = this;
|
||||
}
|
||||
|
||||
SField(SerializedTypeID tid, int fv, const char *fn) :
|
||||
fieldCode(FIELD_CODE(tid, fv)), fieldType(tid), fieldValue(fv), fieldName(fn)
|
||||
fieldCode(FIELD_CODE(tid, fv)), fieldType(tid), fieldValue(fv), fieldName(fn), fieldMeta(SFM_NEVER)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mapMutex);
|
||||
codeToField[fieldCode] = this;
|
||||
@@ -84,6 +93,11 @@ public:
|
||||
bool isBinary() const { return fieldValue < 256; }
|
||||
bool isDiscardable() const { return fieldValue > 256; }
|
||||
|
||||
SF_Meta getMeta() const { return fieldMeta; }
|
||||
bool shouldMetaDel() const { return (fieldMeta == SFM_DELETE) || (fieldMeta == SFM_ALWAYS); }
|
||||
bool shouldMetaMod() const { return (fieldMeta == SFM_CHANGE) || (fieldMeta == SFM_ALWAYS); }
|
||||
void setMeta(SF_Meta m) { fieldMeta = m; }
|
||||
|
||||
bool operator==(const SField& f) const { return fieldCode == f.fieldCode; }
|
||||
bool operator!=(const SField& f) const { return fieldCode != f.fieldCode; }
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ HashedObjectStore::HashedObjectStore(int cacheSize, int cacheAge) :
|
||||
|
||||
bool HashedObjectStore::store(HashedObjectType type, uint32 index,
|
||||
const std::vector<unsigned char>& data, const uint256& hash)
|
||||
{ // return: false=already in cache, true = added to cache
|
||||
{ // return: false = already in cache, true = added to cache
|
||||
assert(hash == Serializer::getSHA512Half(data));
|
||||
if (!theApp->getHashNodeDB())
|
||||
{
|
||||
@@ -59,15 +59,15 @@ void HashedObjectStore::waitWrite()
|
||||
|
||||
void HashedObjectStore::bulkWrite()
|
||||
{
|
||||
std::vector< boost::shared_ptr<HashedObject> > set;
|
||||
while (1)
|
||||
{
|
||||
set.clear();
|
||||
std::vector< boost::shared_ptr<HashedObject> > set;
|
||||
set.reserve(128);
|
||||
|
||||
{
|
||||
boost::unique_lock<boost::mutex> sl(mWriteMutex);
|
||||
mWriteSet.swap(set);
|
||||
assert(mWriteSet.empty());
|
||||
if (set.empty())
|
||||
{
|
||||
mWritePending = false;
|
||||
|
||||
181
src/JobQueue.cpp
Normal file
181
src/JobQueue.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
const char* Job::toString(JobType t)
|
||||
{
|
||||
switch(t)
|
||||
{
|
||||
case jtINVALID: return "invalid";
|
||||
case jtVALIDATION_ut: return "untrustedValidation";
|
||||
case jtTRANSACTION: return "transaction";
|
||||
case jtPROPOSAL_ut: return "untrustedProposal";
|
||||
case jtVALIDATION_t: return "trustedValidation";
|
||||
case jtPROPOSAL_t: return "trustedProposal";
|
||||
case jtADMIN: return "administration";
|
||||
case jtDEATH: return "jobOfDeath";
|
||||
default: assert(false); return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
bool Job::operator<(const Job& j) const
|
||||
{ // These comparison operators make the jobs sort in priority order in the job set
|
||||
if (mType < j.mType)
|
||||
return true;
|
||||
if (mType > j.mType)
|
||||
return false;
|
||||
return mJobIndex < j.mJobIndex;
|
||||
}
|
||||
|
||||
bool Job::operator<=(const Job& j) const
|
||||
{
|
||||
if (mType < j.mType)
|
||||
return true;
|
||||
if (mType > j.mType)
|
||||
return false;
|
||||
return mJobIndex <= j.mJobIndex;
|
||||
}
|
||||
|
||||
bool Job::operator>(const Job& j) const
|
||||
{
|
||||
if (mType < j.mType)
|
||||
return false;
|
||||
if (mType > j.mType)
|
||||
return true;
|
||||
return mJobIndex > j.mJobIndex;
|
||||
}
|
||||
|
||||
bool Job::operator>=(const Job& j) const
|
||||
{
|
||||
if (mType < j.mType)
|
||||
return false;
|
||||
if (mType > j.mType)
|
||||
return true;
|
||||
return mJobIndex >= j.mJobIndex;
|
||||
}
|
||||
|
||||
void JobQueue::addJob(JobType type, const boost::function<void(Job&)>& jobFunc)
|
||||
{
|
||||
assert(type != jtINVALID);
|
||||
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
assert(mThreadCount != 0); // do not add jobs to a queue with no threads
|
||||
|
||||
mJobSet.insert(Job(type, ++mLastJob, jobFunc));
|
||||
++mJobCounts[type];
|
||||
mJobCond.notify_one();
|
||||
}
|
||||
|
||||
int JobQueue::getJobCount(JobType t)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
|
||||
std::map<JobType, int>::iterator c = mJobCounts.find(t);
|
||||
return (c == mJobCounts.end()) ? 0 : c->second;
|
||||
}
|
||||
|
||||
int JobQueue::getJobCountGE(JobType t)
|
||||
{ // return the number of jobs at this priority level or greater
|
||||
int ret = 0;
|
||||
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
|
||||
typedef std::pair<JobType, int> jt_int_pair;
|
||||
BOOST_FOREACH(const jt_int_pair& it, mJobCounts)
|
||||
if (it.first >= t)
|
||||
ret += it.second;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector< std::pair<JobType, int> > JobQueue::getJobCounts()
|
||||
{ // return all jobs at all priority levels
|
||||
std::vector< std::pair<JobType, int> > ret;
|
||||
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
ret.reserve(mJobCounts.size());
|
||||
|
||||
typedef std::pair<JobType, int> jt_int_pair;
|
||||
BOOST_FOREACH(const jt_int_pair& it, mJobCounts)
|
||||
ret.push_back(it);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void JobQueue::shutdown()
|
||||
{ // shut down the job queue without completing pending jobs
|
||||
cLog(lsINFO) << "Job queue shutting down";
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
mShuttingDown = true;
|
||||
mJobCond.notify_all();
|
||||
while (mThreadCount != 0)
|
||||
mJobCond.wait(sl);
|
||||
}
|
||||
|
||||
void JobQueue::setThreadCount(int c)
|
||||
{ // set the number of thread serving the job queue to precisely this number
|
||||
if (c == 0)
|
||||
{
|
||||
c = boost::thread::hardware_concurrency();
|
||||
if (c < 2)
|
||||
c = 2;
|
||||
cLog(lsINFO) << "Auto-tuning to " << c << " validation/transaction/proposal threads";
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
|
||||
while (mJobCounts[jtDEATH] != 0)
|
||||
mJobCond.wait(sl);
|
||||
|
||||
while (mThreadCount < c)
|
||||
{
|
||||
++mThreadCount;
|
||||
boost::thread t(boost::bind(&JobQueue::threadEntry, this));
|
||||
t.detach();
|
||||
}
|
||||
while (mThreadCount > c)
|
||||
{
|
||||
if (mJobCounts[jtDEATH] != 0)
|
||||
mJobCond.wait(sl);
|
||||
else
|
||||
{
|
||||
mJobSet.insert(Job(jtDEATH, 0));
|
||||
++mJobCounts[jtDEATH];
|
||||
}
|
||||
}
|
||||
mJobCond.notify_one(); // in case we sucked up someone else's signal
|
||||
}
|
||||
|
||||
void JobQueue::threadEntry()
|
||||
{ // do jobs until asked to stop
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
while (1)
|
||||
{
|
||||
while (mJobSet.empty() && !mShuttingDown)
|
||||
mJobCond.wait(sl);
|
||||
|
||||
if (mShuttingDown)
|
||||
break;
|
||||
|
||||
std::set<Job>::iterator it = mJobSet.begin();
|
||||
Job job(*it);
|
||||
mJobSet.erase(it);
|
||||
--mJobCounts[job.getType()];
|
||||
|
||||
if (job.getType() == jtDEATH)
|
||||
break;
|
||||
|
||||
sl.unlock();
|
||||
cLog(lsDEBUG) << "Doing " << Job::toString(job.getType()) << " job";
|
||||
job.doJob();
|
||||
sl.lock();
|
||||
}
|
||||
--mThreadCount;
|
||||
mJobCond.notify_all();
|
||||
}
|
||||
83
src/JobQueue.h
Normal file
83
src/JobQueue.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef JOB_QUEUE__H
|
||||
#define JOB_QUEUE__H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// Note that this queue should only be used for CPU-bound jobs
|
||||
// It is primarily intended for signature checking
|
||||
|
||||
enum JobType
|
||||
{ // must be in priority order, low to high
|
||||
jtINVALID,
|
||||
jtVALIDATION_ut,
|
||||
jtTRANSACTION,
|
||||
jtPROPOSAL_ut,
|
||||
jtVALIDATION_t,
|
||||
jtPROPOSAL_t,
|
||||
jtADMIN,
|
||||
jtDEATH, // job of death, used internally
|
||||
};
|
||||
|
||||
class Job
|
||||
{
|
||||
protected:
|
||||
JobType mType;
|
||||
uint64 mJobIndex;
|
||||
boost::function<void(Job&)> mJob;
|
||||
|
||||
public:
|
||||
Job() : mType(jtINVALID), mJobIndex(0) { ; }
|
||||
Job(JobType type, uint64 index) : mType(type), mJobIndex(index) { ; }
|
||||
|
||||
Job(JobType type, uint64 index, const boost::function<void(Job&)>& job)
|
||||
: mType(type), mJobIndex(index), mJob(job) { ; }
|
||||
|
||||
JobType getType() const { return mType; }
|
||||
void doJob(void) { mJob(*this); }
|
||||
|
||||
bool operator<(const Job& j) const;
|
||||
bool operator>(const Job& j) const;
|
||||
bool operator<=(const Job& j) const;
|
||||
bool operator>=(const Job& j) const;
|
||||
|
||||
static const char* toString(JobType);
|
||||
};
|
||||
|
||||
class JobQueue
|
||||
{
|
||||
protected:
|
||||
boost::mutex mJobLock;
|
||||
boost::condition_variable mJobCond;
|
||||
|
||||
uint64 mLastJob;
|
||||
std::set<Job> mJobSet;
|
||||
std::map<JobType, int> mJobCounts;
|
||||
int mThreadCount;
|
||||
bool mShuttingDown;
|
||||
|
||||
|
||||
void threadEntry(void);
|
||||
|
||||
public:
|
||||
|
||||
JobQueue() : mLastJob(0), mThreadCount(0), mShuttingDown(false) { ; }
|
||||
|
||||
void addJob(JobType type, const boost::function<void(Job&)>& job);
|
||||
|
||||
int getJobCount(JobType t); // Jobs at this priority
|
||||
int getJobCountGE(JobType t); // All jobs at or greater than this priority
|
||||
std::vector< std::pair<JobType, int> > getJobCounts();
|
||||
|
||||
void shutdown();
|
||||
void setThreadCount(int c = 0);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -339,7 +339,7 @@ uint256 Ledger::getHash()
|
||||
|
||||
void Ledger::saveAcceptedLedger(bool fromConsensus)
|
||||
{ // can be called in a different thread
|
||||
cLog(lsTRACE) << "saveAcceptedLedger " << (fromConsensus ? "fromConsensus" : "fromAcquire") << getLedgerSeq();
|
||||
cLog(lsTRACE) << "saveAcceptedLedger " << (fromConsensus ? "fromConsensus " : "fromAcquire ") << getLedgerSeq();
|
||||
static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers where LedgerSeq = %d;");
|
||||
static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;");
|
||||
static boost::format AcctTransExists("SELECT LedgerSeq FROM AccountTransactions WHERE TransId = '%s';");
|
||||
@@ -430,11 +430,16 @@ void Ledger::saveAcceptedLedger(bool fromConsensus)
|
||||
}
|
||||
|
||||
if (!fromConsensus)
|
||||
{
|
||||
decPendingSaves();
|
||||
return;
|
||||
}
|
||||
|
||||
theApp->getMasterLedger().setFullLedger(shared_from_this());
|
||||
|
||||
theApp->getOPs().pubLedger(shared_from_this());
|
||||
|
||||
theApp->getMasterLedger().setFullLedger(shared_from_this());
|
||||
decPendingSaves();
|
||||
}
|
||||
|
||||
Ledger::pointer Ledger::getSQL(const std::string& sql)
|
||||
@@ -451,7 +456,10 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
|
||||
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
|
||||
|
||||
if (!db->executeSQL(sql) || !db->startIterRows())
|
||||
return Ledger::pointer();
|
||||
{
|
||||
cLog(lsDEBUG) << "No ledger for query: " << sql;
|
||||
return Ledger::pointer();
|
||||
}
|
||||
|
||||
db->getStr("LedgerHash", hash);
|
||||
ledgerHash.SetHex(hash);
|
||||
@@ -471,8 +479,8 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
|
||||
}
|
||||
|
||||
Log(lsTRACE) << "Constructing ledger " << ledgerSeq << " from SQL";
|
||||
Ledger::pointer ret = Ledger::pointer(new Ledger(prevHash, transHash, accountHash, totCoins,
|
||||
closingTime, prevClosingTime, closeFlags, closeResolution, ledgerSeq));
|
||||
Ledger::pointer ret = boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins,
|
||||
closingTime, prevClosingTime, closeFlags, closeResolution, ledgerSeq);
|
||||
if (ret->getHash() != ledgerHash)
|
||||
{
|
||||
if (sLog(lsERROR))
|
||||
@@ -877,6 +885,41 @@ uint256 Ledger::getAccountRootIndex(const uint160& uAccountID)
|
||||
return s.getSHA512Half();
|
||||
}
|
||||
|
||||
uint256 Ledger::getLedgerHashIndex()
|
||||
{ // get the index of the node that holds the last 256 ledgers
|
||||
Serializer s(2);
|
||||
s.add16(spaceHashes);
|
||||
return s.getSHA512Half();
|
||||
}
|
||||
|
||||
uint256 Ledger::getLedgerHashIndex(uint32 desiredLedgerIndex)
|
||||
{ // get the index of the node that holds the set of 256 ledgers that includes this ledger's hash
|
||||
// (or the first ledger after it if it's not a multiple of 256)
|
||||
Serializer s(6);
|
||||
s.add16(spaceHashes);
|
||||
s.add32(desiredLedgerIndex >> 16);
|
||||
return s.getSHA512Half();
|
||||
}
|
||||
|
||||
int Ledger::getLedgerHashOffset(uint32 ledgerIndex)
|
||||
{ // get the offset for this ledger's hash (or the first one after it) in the every-256-ledger table
|
||||
return (ledgerIndex >> 8) % 256;
|
||||
}
|
||||
|
||||
int Ledger::getLedgerHashOffset(uint32 desiredLedgerIndex, uint32 currentLedgerIndex)
|
||||
{ // get the offset for this ledger's hash in the every-ledger table, -1 if not in it
|
||||
if (desiredLedgerIndex >= currentLedgerIndex)
|
||||
return -1;
|
||||
|
||||
if (currentLedgerIndex < 256)
|
||||
return desiredLedgerIndex;
|
||||
|
||||
if (desiredLedgerIndex < (currentLedgerIndex - 256))
|
||||
return -1;
|
||||
|
||||
return currentLedgerIndex - desiredLedgerIndex - 1;
|
||||
}
|
||||
|
||||
uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
|
||||
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID)
|
||||
{
|
||||
@@ -1018,4 +1061,31 @@ bool Ledger::assertSane()
|
||||
return false;
|
||||
}
|
||||
|
||||
int Ledger::sPendingSaves = 0;
|
||||
boost::recursive_mutex Ledger::sPendingSaveLock;
|
||||
|
||||
int Ledger::getPendingSaves()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(sPendingSaveLock);
|
||||
return sPendingSaves;
|
||||
}
|
||||
|
||||
void Ledger::pendSave(bool fromConsensus)
|
||||
{
|
||||
if (!fromConsensus && !theApp->isNew(getHash()))
|
||||
return;
|
||||
|
||||
boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, shared_from_this(), fromConsensus));
|
||||
thread.detach();
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(sPendingSaveLock);
|
||||
++sPendingSaves;
|
||||
}
|
||||
|
||||
void Ledger::decPendingSaves()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(sPendingSaveLock);
|
||||
--sPendingSaves;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
16
src/Ledger.h
16
src/Ledger.h
@@ -78,12 +78,19 @@ private:
|
||||
|
||||
mutable boost::recursive_mutex mLock;
|
||||
|
||||
static int sPendingSaves;
|
||||
static boost::recursive_mutex sPendingSaveLock;
|
||||
|
||||
Ledger(const Ledger&); // no implementation
|
||||
Ledger& operator=(const Ledger&); // no implementation
|
||||
|
||||
protected:
|
||||
SLE::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID, LedgerEntryType let);
|
||||
|
||||
static void incPendingSaves();
|
||||
static void decPendingSaves();
|
||||
void saveAcceptedLedger(bool fromConsensus);
|
||||
|
||||
public:
|
||||
Ledger(const RippleAddress& masterID, uint64 startAmount); // used for the starting bootstrap ledger
|
||||
|
||||
@@ -101,6 +108,7 @@ public:
|
||||
|
||||
static Ledger::pointer getSQL(const std::string& sqlStatement);
|
||||
static Ledger::pointer getLastFullLedger();
|
||||
static int getPendingSaves();
|
||||
|
||||
void updateHash();
|
||||
void setClosed() { mClosed = true; }
|
||||
@@ -157,9 +165,9 @@ public:
|
||||
SLE::pointer getAccountRoot(const RippleAddress& naAccountID);
|
||||
|
||||
// database functions
|
||||
void saveAcceptedLedger(bool fromConsensus);
|
||||
static Ledger::pointer loadByIndex(uint32 ledgerIndex);
|
||||
static Ledger::pointer loadByHash(const uint256& ledgerHash);
|
||||
void pendSave(bool fromConsensus);
|
||||
|
||||
// next/prev function
|
||||
SLE::pointer getSLE(const uint256& uHash);
|
||||
@@ -170,6 +178,12 @@ public:
|
||||
uint256 getPrevLedgerIndex(const uint256& uHash); // last node <hash
|
||||
uint256 getPrevLedgerIndex(const uint256& uHash, const uint256& uBegin); // last node <hash, >begin
|
||||
|
||||
// Ledger hash table function
|
||||
static uint256 getLedgerHashIndex();
|
||||
static uint256 getLedgerHashIndex(uint32 desiredLedgerIndex);
|
||||
static int getLedgerHashOffset(uint32 desiredLedgerIndex);
|
||||
static int getLedgerHashOffset(uint32 desiredLedgerIndex, uint32 currentLedgerIndex);
|
||||
|
||||
// index calculation functions
|
||||
static uint256 getAccountRootIndex(const uint160& uAccountID);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
// #define LA_DEBUG
|
||||
#define LA_DEBUG
|
||||
#define LEDGER_ACQUIRE_TIMEOUT 750
|
||||
#define TRUST_NETWORK
|
||||
|
||||
@@ -74,7 +74,7 @@ void PeerSet::invokeOnTimer()
|
||||
if (!mProgress)
|
||||
{
|
||||
++mTimeouts;
|
||||
cLog(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash;
|
||||
cLog(lsWARNING) << "Timeout(" << mTimeouts << ") pc=" << mPeers.size() << " acquiring " << mHash;
|
||||
}
|
||||
else
|
||||
mProgress = false;
|
||||
@@ -144,7 +144,33 @@ void LedgerAcquire::onTimer()
|
||||
setFailed();
|
||||
done();
|
||||
}
|
||||
else trigger(Peer::pointer(), true);
|
||||
else
|
||||
{
|
||||
if (!getPeerCount())
|
||||
addPeers();
|
||||
trigger(Peer::pointer(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerAcquire::addPeers()
|
||||
{
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
|
||||
bool found = false;
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
{
|
||||
if (peer->hasLedger(getHash()))
|
||||
{
|
||||
found = true;
|
||||
peerHas(peer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
peerHas(peer);
|
||||
}
|
||||
}
|
||||
|
||||
boost::weak_ptr<PeerSet> LedgerAcquire::pmDowncast()
|
||||
@@ -189,29 +215,35 @@ void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)>
|
||||
void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
{
|
||||
if (mAborted || mComplete || mFailed)
|
||||
{
|
||||
cLog(lsTRACE) << "Trigger on ledger:" <<
|
||||
(mAborted ? " aborted": "") << (mComplete ? " completed": "") << (mFailed ? " failed" : "");
|
||||
return;
|
||||
#ifdef LA_DEBUG
|
||||
if (peer) cLog(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP();
|
||||
else cLog(lsTRACE) << "Trigger acquiring ledger " << mHash;
|
||||
if (mComplete || mFailed)
|
||||
cLog(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
|
||||
else
|
||||
cLog(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sLog(lsTRACE))
|
||||
{
|
||||
if (peer)
|
||||
cLog(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP();
|
||||
else
|
||||
cLog(lsTRACE) << "Trigger acquiring ledger " << mHash;
|
||||
if (mComplete || mFailed)
|
||||
cLog(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
|
||||
else
|
||||
cLog(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
|
||||
}
|
||||
|
||||
if (!mHaveBase)
|
||||
{
|
||||
ripple::TMGetLedger tmGL;
|
||||
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
|
||||
tmGL.set_itype(ripple::liBASE);
|
||||
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
|
||||
cLog(lsTRACE) << "Sending base request to " << (peer ? "selected peer" : "all peers");
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
|
||||
if (mHaveBase && !mHaveTransactions)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
cLog(lsTRACE) << "need tx";
|
||||
#endif
|
||||
assert(mLedger);
|
||||
if (mLedger->peekTransactionMap()->getHash().isZero())
|
||||
{ // we need the root node
|
||||
@@ -220,6 +252,7 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
tmGL.set_ledgerseq(mLedger->getLedgerSeq());
|
||||
tmGL.set_itype(ripple::liTX_NODE);
|
||||
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
|
||||
cLog(lsTRACE) << "Sending TX root request to " << (peer ? "selected peer" : "all peers");
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
else
|
||||
@@ -246,6 +279,8 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
tmGL.set_itype(ripple::liTX_NODE);
|
||||
BOOST_FOREACH(SHAMapNode& it, nodeIDs)
|
||||
*(tmGL.add_nodeids()) = it.getRawString();
|
||||
cLog(lsTRACE) << "Sending TX node " << nodeIDs.size()
|
||||
<< "request to " << (peer ? "selected peer" : "all peers");
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
}
|
||||
@@ -253,9 +288,6 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
|
||||
if (mHaveBase && !mHaveState)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
cLog(lsTRACE) << "need as";
|
||||
#endif
|
||||
assert(mLedger);
|
||||
if (mLedger->peekAccountStateMap()->getHash().isZero())
|
||||
{ // we need the root node
|
||||
@@ -264,6 +296,7 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
tmGL.set_ledgerseq(mLedger->getLedgerSeq());
|
||||
tmGL.set_itype(ripple::liAS_NODE);
|
||||
*(tmGL.add_nodeids()) = SHAMapNode().getRawString();
|
||||
cLog(lsTRACE) << "Sending AS root request to " << (peer ? "selected peer" : "all peers");
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
else
|
||||
@@ -290,13 +323,18 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
tmGL.set_itype(ripple::liAS_NODE);
|
||||
BOOST_FOREACH(SHAMapNode& it, nodeIDs)
|
||||
*(tmGL.add_nodeids()) = it.getRawString();
|
||||
cLog(lsTRACE) << "Sending AS node " << nodeIDs.size()
|
||||
<< "request to " << (peer ? "selected peer" : "all peers");
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mComplete || mFailed)
|
||||
{
|
||||
cLog(lsDEBUG) << "Done:" << (mComplete ? " complete" : "") << (mFailed ? " failed" : "");
|
||||
done();
|
||||
}
|
||||
else if (timer)
|
||||
resetTimer();
|
||||
}
|
||||
@@ -326,7 +364,8 @@ void PeerSet::sendRequest(const ripple::TMGetLedger& tmGL)
|
||||
{
|
||||
// FIXME: Track last peer sent to and time sent
|
||||
Peer::pointer peer = it->lock();
|
||||
if (peer) peer->sendPacket(packet);
|
||||
if (peer)
|
||||
peer->sendPacket(packet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -486,6 +525,7 @@ LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
|
||||
return ptr;
|
||||
ptr = boost::make_shared<LedgerAcquire>(hash);
|
||||
assert(mLedgers[hash] == ptr);
|
||||
ptr->addPeers();
|
||||
ptr->resetTimer(); // Cannot call in constructor
|
||||
return ptr;
|
||||
}
|
||||
@@ -516,9 +556,6 @@ void LedgerAcquireMaster::dropLedger(const uint256& hash)
|
||||
|
||||
bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref peer)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
cLog(lsTRACE) << "got data for acquiring ledger ";
|
||||
#endif
|
||||
uint256 hash;
|
||||
if (packet.ledgerhash().size() != 32)
|
||||
{
|
||||
@@ -526,37 +563,34 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
return false;
|
||||
}
|
||||
memcpy(hash.begin(), packet.ledgerhash().data(), 32);
|
||||
#ifdef LA_DEBUG
|
||||
cLog(lsTRACE) << hash;
|
||||
#endif
|
||||
cLog(lsTRACE) << "Got data for acquiring ledger: " << hash;
|
||||
|
||||
LedgerAcquire::pointer ledger = find(hash);
|
||||
if (!ledger) return false;
|
||||
if (!ledger)
|
||||
{
|
||||
cLog(lsINFO) << "Got data for ledger we're not acquiring";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packet.type() == ripple::liBASE)
|
||||
{
|
||||
if (packet.nodes_size() < 1)
|
||||
return false;
|
||||
const ripple::TMLedgerNode& node = packet.nodes(0);
|
||||
if (!ledger->takeBase(node.nodedata()))
|
||||
return false;
|
||||
if (packet.nodes_size() == 1)
|
||||
{
|
||||
ledger->trigger(peer, false);
|
||||
return true;
|
||||
cLog(lsWARNING) << "Got empty base data";
|
||||
return false;
|
||||
}
|
||||
if (!ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata())))
|
||||
if (!ledger->takeBase(packet.nodes(0).nodedata()))
|
||||
{
|
||||
cLog(lsWARNING) << "Got unwanted base data";
|
||||
return false;
|
||||
}
|
||||
if ((packet.nodes().size() > 1) && !ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata())))
|
||||
{
|
||||
cLog(lsWARNING) << "Included ASbase invalid";
|
||||
}
|
||||
if (packet.nodes().size() == 2)
|
||||
if ((packet.nodes().size() > 2) && !ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata())))
|
||||
{
|
||||
ledger->trigger(peer, false);
|
||||
return true;
|
||||
}
|
||||
if (!ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata())))
|
||||
{
|
||||
cLog(lsWARNING) << "Invcluded TXbase invalid";
|
||||
cLog(lsWARNING) << "Included TXbase invalid";
|
||||
}
|
||||
ledger->trigger(peer, false);
|
||||
return true;
|
||||
@@ -567,11 +601,16 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
std::list<SHAMapNode> nodeIDs;
|
||||
std::list< std::vector<unsigned char> > nodeData;
|
||||
|
||||
if (packet.nodes().size() <= 0) return false;
|
||||
if (packet.nodes().size() <= 0)
|
||||
{
|
||||
cLog(lsINFO) << "Got request for no nodes";
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < packet.nodes().size(); ++i)
|
||||
{
|
||||
const ripple::TMLedgerNode& node = packet.nodes(i);
|
||||
if (!node.has_nodeid() || !node.has_nodedata()) return false;
|
||||
if (!node.has_nodeid() || !node.has_nodedata())
|
||||
return false;
|
||||
|
||||
nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size()));
|
||||
nodeData.push_back(std::vector<unsigned char>(node.nodedata().begin(), node.nodedata().end()));
|
||||
@@ -586,6 +625,7 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
return ret;
|
||||
}
|
||||
|
||||
cLog(lsWARNING) << "Not sure what ledger data we got";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ public:
|
||||
bool takeAsRootNode(const std::vector<unsigned char>& data);
|
||||
void trigger(Peer::ref, bool timer);
|
||||
bool tryLocal();
|
||||
void addPeers();
|
||||
};
|
||||
|
||||
class LedgerAcquireMaster
|
||||
|
||||
@@ -339,24 +339,6 @@ void LedgerConsensus::handleLCL(const uint256& lclHash)
|
||||
cLog(lsWARNING) << "Need consensus ledger " << mPrevLedgerHash;
|
||||
|
||||
mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash);
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
|
||||
bool found = false;
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
{
|
||||
if (peer->hasLedger(mPrevLedgerHash))
|
||||
{
|
||||
found = true;
|
||||
mAcquiringLedger->peerHas(peer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
mAcquiringLedger->peerHas(peer);
|
||||
}
|
||||
|
||||
mHaveCorrectLCL = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -319,9 +319,11 @@ bool LedgerEntrySet::threadTx(SLE::ref threadTo, Ledger::ref ledger,
|
||||
uint32 prevLgrID;
|
||||
if (!threadTo->thread(mSet.getTxID(), mSet.getLgrSeq(), prevTxID, prevLgrID))
|
||||
return false;
|
||||
if (TransactionMetaSet::thread(mSet.getAffectedNode(threadTo->getIndex(), sfModifiedNode),
|
||||
|
||||
if (prevTxID.isZero() || TransactionMetaSet::thread(mSet.getAffectedNode(threadTo->getIndex(), sfModifiedNode),
|
||||
prevTxID, prevLgrID))
|
||||
return true;
|
||||
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
@@ -336,7 +338,7 @@ bool LedgerEntrySet::threadOwners(SLE::ref node, Ledger::ref ledger,
|
||||
#endif
|
||||
return threadTx(node->getOwner(), ledger, newMods);
|
||||
}
|
||||
else if (node->hasTwoOwners()) // thread to owner's accounts]
|
||||
else if (node->hasTwoOwners()) // thread to owner's accounts
|
||||
{
|
||||
#ifdef META_DEBUG
|
||||
cLog(lsTRACE) << "Thread to two owners";
|
||||
@@ -403,34 +405,26 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
|
||||
assert(origNode);
|
||||
threadOwners(origNode, mLedger, newMod);
|
||||
|
||||
if (origNode->isFieldPresent(sfAmount))
|
||||
{ // node has an amount, covers ripple state nodes
|
||||
STAmount amount = origNode->getFieldAmount(sfAmount);
|
||||
if (amount.isNonZero())
|
||||
mSet.getAffectedNode(it.first).setFieldAmount(sfPreviousBalance, amount);
|
||||
amount = curNode->getFieldAmount(sfAmount);
|
||||
if (amount.isNonZero())
|
||||
mSet.getAffectedNode(it.first).setFieldAmount(sfFinalBalance, amount);
|
||||
|
||||
if (origNode->getType() == ltRIPPLE_STATE)
|
||||
{
|
||||
mSet.getAffectedNode(it.first).setFieldAccount(sfLowID,
|
||||
RippleAddress::createAccountID(origNode->getFieldAmount(sfLowLimit).getIssuer()));
|
||||
mSet.getAffectedNode(it.first).setFieldAccount(sfHighID,
|
||||
RippleAddress::createAccountID(origNode->getFieldAmount(sfHighLimit).getIssuer()));
|
||||
}
|
||||
STObject finals(sfFinalFields);
|
||||
BOOST_FOREACH(const SerializedType& obj, *curNode)
|
||||
{ // search the deleted node for values saved on delete
|
||||
if (obj.getFName().shouldMetaDel() && !obj.isDefault())
|
||||
finals.addObject(obj);
|
||||
}
|
||||
if (!finals.empty())
|
||||
mSet.getAffectedNode(it.first, *type).addObject(finals);
|
||||
}
|
||||
|
||||
if (origNode->getType() == ltOFFER)
|
||||
{ // check for non-zero balances
|
||||
STAmount amount = origNode->getFieldAmount(sfTakerPays);
|
||||
if (amount.isNonZero())
|
||||
mSet.getAffectedNode(it.first).setFieldAmount(sfFinalTakerPays, amount);
|
||||
amount = origNode->getFieldAmount(sfTakerGets);
|
||||
if (amount.isNonZero())
|
||||
mSet.getAffectedNode(it.first).setFieldAmount(sfFinalTakerGets, amount);
|
||||
if ((type == &sfDeletedNode || type == &sfModifiedNode))
|
||||
{
|
||||
STObject mods(sfPreviousFields);
|
||||
BOOST_FOREACH(const SerializedType& obj, *origNode)
|
||||
{ // search the original node for values saved on modify
|
||||
if (obj.getFName().shouldMetaMod() && !obj.isDefault() && !curNode->hasMatchingEntry(obj))
|
||||
mods.addObject(obj);
|
||||
}
|
||||
|
||||
if (!mods.empty())
|
||||
mSet.getAffectedNode(it.first, *type).addObject(mods);
|
||||
}
|
||||
|
||||
if (type == &sfCreatedNode) // if created, thread to owner(s)
|
||||
@@ -444,28 +438,6 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
|
||||
if (curNode->isThreadedType()) // always thread to self
|
||||
threadTx(curNode, mLedger, newMod);
|
||||
}
|
||||
|
||||
if (type == &sfModifiedNode)
|
||||
{
|
||||
assert(origNode);
|
||||
if (origNode->isFieldPresent(sfAmount))
|
||||
{ // node has an amount, covers account root nodes and ripple nodes
|
||||
STAmount amount = origNode->getFieldAmount(sfAmount);
|
||||
if (amount != curNode->getFieldAmount(sfAmount))
|
||||
mSet.getAffectedNode(it.first).setFieldAmount(sfPreviousBalance, amount);
|
||||
}
|
||||
|
||||
if (origNode->getType() == ltOFFER)
|
||||
{
|
||||
STAmount amount = origNode->getFieldAmount(sfTakerPays);
|
||||
if (amount != curNode->getFieldAmount(sfTakerPays))
|
||||
mSet.getAffectedNode(it.first).setFieldAmount(sfPreviousTakerPays, amount);
|
||||
amount = origNode->getFieldAmount(sfTakerGets);
|
||||
if (amount != curNode->getFieldAmount(sfTakerGets))
|
||||
mSet.getAffectedNode(it.first).setFieldAmount(sfPreviousTakerGets, amount);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// add any new modified nodes to the modification set
|
||||
@@ -473,9 +445,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
|
||||
it != end; ++it)
|
||||
entryModify(it->second);
|
||||
|
||||
#ifdef META_DEBUG
|
||||
cLog(lsINFO) << "Metadata:" << mSet.getJson(0);
|
||||
#endif
|
||||
cLog(lsTRACE) << "Metadata:" << mSet.getJson(0);
|
||||
|
||||
mSet.addRaw(s, result);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
std::map<int, LedgerEntryFormat*> LedgerEntryFormat::byType;
|
||||
std::map<std::string, LedgerEntryFormat*> LedgerEntryFormat::byName;
|
||||
|
||||
#define LEF_BASE \
|
||||
<< SOElement(sfLedgerIndex, SOE_OPTIONAL) \
|
||||
<< SOElement(sfLedgerEntryType, SOE_REQUIRED) \
|
||||
<< SOElement(sfFlags, SOE_REQUIRED)
|
||||
#define LEF_BASE \
|
||||
<< SOElement(sfLedgerIndex, SOE_OPTIONAL) \
|
||||
<< SOElement(sfLedgerEntryType, SOE_REQUIRED) \
|
||||
<< SOElement(sfFlags, SOE_REQUIRED)
|
||||
|
||||
#define DECLARE_LEF(name, type) lef = new LedgerEntryFormat(#name, type); (*lef) LEF_BASE
|
||||
|
||||
@@ -16,74 +16,78 @@ static bool LEFInit()
|
||||
LedgerEntryFormat* lef;
|
||||
|
||||
DECLARE_LEF(AccountRoot, ltACCOUNT_ROOT)
|
||||
<< SOElement(sfAccount, SOE_REQUIRED)
|
||||
<< SOElement(sfSequence, SOE_REQUIRED)
|
||||
<< SOElement(sfBalance, SOE_REQUIRED)
|
||||
<< SOElement(sfLastTxnID, SOE_REQUIRED)
|
||||
<< SOElement(sfLastTxnSeq, SOE_REQUIRED)
|
||||
<< SOElement(sfAuthorizedKey, SOE_OPTIONAL)
|
||||
<< SOElement(sfEmailHash, SOE_OPTIONAL)
|
||||
<< SOElement(sfWalletLocator, SOE_OPTIONAL)
|
||||
<< SOElement(sfMessageKey, SOE_OPTIONAL)
|
||||
<< SOElement(sfTransferRate, SOE_OPTIONAL)
|
||||
<< SOElement(sfDomain, SOE_OPTIONAL)
|
||||
<< SOElement(sfPublishHash, SOE_OPTIONAL)
|
||||
<< SOElement(sfPublishSize, SOE_OPTIONAL)
|
||||
<< SOElement(sfAccount, SOE_REQUIRED)
|
||||
<< SOElement(sfSequence, SOE_REQUIRED)
|
||||
<< SOElement(sfBalance, SOE_REQUIRED)
|
||||
<< SOElement(sfPreviousTxnID, SOE_REQUIRED)
|
||||
<< SOElement(sfPreviousTxnLgrSeq, SOE_REQUIRED)
|
||||
<< SOElement(sfAuthorizedKey, SOE_OPTIONAL)
|
||||
<< SOElement(sfEmailHash, SOE_OPTIONAL)
|
||||
<< SOElement(sfWalletLocator, SOE_OPTIONAL)
|
||||
<< SOElement(sfMessageKey, SOE_OPTIONAL)
|
||||
<< SOElement(sfTransferRate, SOE_OPTIONAL)
|
||||
<< SOElement(sfDomain, SOE_OPTIONAL)
|
||||
<< SOElement(sfPublishHash, SOE_OPTIONAL)
|
||||
<< SOElement(sfPublishSize, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
DECLARE_LEF(Contract, ltCONTRACT)
|
||||
<< SOElement(sfAccount, SOE_REQUIRED)
|
||||
<< SOElement(sfBalance, SOE_REQUIRED)
|
||||
<< SOElement(sfLastTxnID, SOE_REQUIRED)
|
||||
<< SOElement(sfLastTxnSeq, SOE_REQUIRED)
|
||||
<< SOElement(sfIssuer, SOE_REQUIRED)
|
||||
<< SOElement(sfOwner, SOE_REQUIRED)
|
||||
<< SOElement(sfExpiration, SOE_REQUIRED)
|
||||
<< SOElement(sfBondAmount, SOE_REQUIRED)
|
||||
<< SOElement(sfCreateCode, SOE_REQUIRED)
|
||||
<< SOElement(sfFundCode, SOE_REQUIRED)
|
||||
<< SOElement(sfRemoveCode, SOE_REQUIRED)
|
||||
<< SOElement(sfExpireCode, SOE_REQUIRED)
|
||||
<< SOElement(sfAccount, SOE_REQUIRED)
|
||||
<< SOElement(sfBalance, SOE_REQUIRED)
|
||||
<< SOElement(sfPreviousTxnID, SOE_REQUIRED)
|
||||
<< SOElement(sfPreviousTxnLgrSeq, SOE_REQUIRED)
|
||||
<< SOElement(sfIssuer, SOE_REQUIRED)
|
||||
<< SOElement(sfOwner, SOE_REQUIRED)
|
||||
<< SOElement(sfExpiration, SOE_REQUIRED)
|
||||
<< SOElement(sfBondAmount, SOE_REQUIRED)
|
||||
<< SOElement(sfCreateCode, SOE_REQUIRED)
|
||||
<< SOElement(sfFundCode, SOE_REQUIRED)
|
||||
<< SOElement(sfRemoveCode, SOE_REQUIRED)
|
||||
<< SOElement(sfExpireCode, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
DECLARE_LEF(DirectoryNode, ltDIR_NODE)
|
||||
<< SOElement(sfIndexes, SOE_REQUIRED)
|
||||
<< SOElement(sfIndexNext, SOE_OPTIONAL)
|
||||
<< SOElement(sfIndexPrevious, SOE_OPTIONAL)
|
||||
<< SOElement(sfIndexes, SOE_REQUIRED)
|
||||
<< SOElement(sfIndexNext, SOE_OPTIONAL)
|
||||
<< SOElement(sfIndexPrevious, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
DECLARE_LEF(GeneratorMap, ltGENERATOR_MAP)
|
||||
<< SOElement(sfGenerator, SOE_REQUIRED)
|
||||
<< SOElement(sfGenerator, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
DECLARE_LEF(Nickname, ltNICKNAME)
|
||||
<< SOElement(sfAccount, SOE_REQUIRED)
|
||||
<< SOElement(sfMinimumOffer, SOE_OPTIONAL)
|
||||
<< SOElement(sfAccount, SOE_REQUIRED)
|
||||
<< SOElement(sfMinimumOffer, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
DECLARE_LEF(Offer, ltOFFER)
|
||||
<< SOElement(sfAccount, SOE_REQUIRED)
|
||||
<< SOElement(sfSequence, SOE_REQUIRED)
|
||||
<< SOElement(sfTakerPays, SOE_REQUIRED)
|
||||
<< SOElement(sfTakerGets, SOE_REQUIRED)
|
||||
<< SOElement(sfBookDirectory, SOE_REQUIRED)
|
||||
<< SOElement(sfBookNode, SOE_REQUIRED)
|
||||
<< SOElement(sfOwnerNode, SOE_REQUIRED)
|
||||
<< SOElement(sfLastTxnID, SOE_REQUIRED)
|
||||
<< SOElement(sfLastTxnSeq, SOE_REQUIRED)
|
||||
<< SOElement(sfExpiration, SOE_OPTIONAL)
|
||||
<< SOElement(sfAccount, SOE_REQUIRED)
|
||||
<< SOElement(sfSequence, SOE_REQUIRED)
|
||||
<< SOElement(sfTakerPays, SOE_REQUIRED)
|
||||
<< SOElement(sfTakerGets, SOE_REQUIRED)
|
||||
<< SOElement(sfBookDirectory, SOE_REQUIRED)
|
||||
<< SOElement(sfBookNode, SOE_REQUIRED)
|
||||
<< SOElement(sfOwnerNode, SOE_REQUIRED)
|
||||
<< SOElement(sfPreviousTxnID, SOE_REQUIRED)
|
||||
<< SOElement(sfPreviousTxnLgrSeq, SOE_REQUIRED)
|
||||
<< SOElement(sfExpiration, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
DECLARE_LEF(RippleState, ltRIPPLE_STATE)
|
||||
<< SOElement(sfBalance, SOE_REQUIRED)
|
||||
<< SOElement(sfLowLimit, SOE_REQUIRED)
|
||||
<< SOElement(sfHighLimit, SOE_REQUIRED)
|
||||
<< SOElement(sfLastTxnID, SOE_REQUIRED)
|
||||
<< SOElement(sfLastTxnSeq, SOE_REQUIRED)
|
||||
<< SOElement(sfLowQualityIn, SOE_OPTIONAL)
|
||||
<< SOElement(sfLowQualityOut, SOE_OPTIONAL)
|
||||
<< SOElement(sfHighQualityIn, SOE_OPTIONAL)
|
||||
<< SOElement(sfHighQualityOut, SOE_OPTIONAL)
|
||||
<< SOElement(sfBalance, SOE_REQUIRED)
|
||||
<< SOElement(sfLowLimit, SOE_REQUIRED)
|
||||
<< SOElement(sfHighLimit, SOE_REQUIRED)
|
||||
<< SOElement(sfPreviousTxnID, SOE_REQUIRED)
|
||||
<< SOElement(sfPreviousTxnLgrSeq, SOE_REQUIRED)
|
||||
<< SOElement(sfLowQualityIn, SOE_OPTIONAL)
|
||||
<< SOElement(sfLowQualityOut, SOE_OPTIONAL)
|
||||
<< SOElement(sfHighQualityIn, SOE_OPTIONAL)
|
||||
<< SOElement(sfHighQualityOut, SOE_OPTIONAL)
|
||||
;
|
||||
|
||||
DECLARE_LEF(LedgerHashes, ltLEDGER_HASHES)
|
||||
<< SOElement(sfHashes, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -14,6 +14,7 @@ enum LedgerEntryType
|
||||
ltNICKNAME = 'n',
|
||||
ltOFFER = 'o',
|
||||
ltCONTRACT = 'c',
|
||||
ltLEDGER_HASHES = 'h',
|
||||
};
|
||||
|
||||
// Used as a prefix for computing ledger indexes (keys).
|
||||
@@ -28,6 +29,7 @@ enum LedgerNameSpace
|
||||
spaceOwnerDir = 'O', // Directory of things owned by an account.
|
||||
spaceBookDir = 'B', // Directory of order books.
|
||||
spaceContract = 'c',
|
||||
spaceHashes = 'h',
|
||||
};
|
||||
|
||||
enum LedgerSpecificFlags
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
|
||||
#include "LedgerHistory.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "LedgerHistory.h"
|
||||
#include "Config.h"
|
||||
#include "Application.h"
|
||||
|
||||
@@ -13,13 +14,13 @@
|
||||
#endif
|
||||
|
||||
#ifndef CACHED_LEDGER_AGE
|
||||
#define CACHED_LEDGER_AGE 600
|
||||
#define CACHED_LEDGER_AGE 900
|
||||
#endif
|
||||
|
||||
// FIXME: Need to clean up ledgers by index, probably should switch to just mapping sequence to hash
|
||||
|
||||
LedgerHistory::LedgerHistory() : mLedgersByHash(CACHED_LEDGER_NUM, CACHED_LEDGER_AGE)
|
||||
{
|
||||
;
|
||||
}
|
||||
{ ; }
|
||||
|
||||
void LedgerHistory::addLedger(Ledger::pointer ledger)
|
||||
{
|
||||
@@ -37,8 +38,7 @@ void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger, bool fromConsensus
|
||||
assert(ledger->isImmutable());
|
||||
mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger));
|
||||
|
||||
boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, ledger, fromConsensus));
|
||||
thread.detach();
|
||||
ledger->pendSave(fromConsensus);
|
||||
}
|
||||
|
||||
Ledger::pointer LedgerHistory::getLedgerBySeq(uint32 index)
|
||||
@@ -50,7 +50,8 @@ Ledger::pointer LedgerHistory::getLedgerBySeq(uint32 index)
|
||||
sl.unlock();
|
||||
|
||||
Ledger::pointer ret(Ledger::loadByIndex(index));
|
||||
if (!ret) return ret;
|
||||
if (!ret)
|
||||
return ret;
|
||||
assert(ret->getLedgerSeq() == index);
|
||||
|
||||
sl.lock();
|
||||
|
||||
@@ -98,6 +98,14 @@ TER LedgerMaster::doTransaction(const SerializedTransaction& txn, TransactionEng
|
||||
void LedgerMaster::acquireMissingLedger(const uint256& ledgerHash, uint32 ledgerSeq)
|
||||
{
|
||||
mMissingLedger = theApp->getMasterLedgerAcquire().findCreate(ledgerHash);
|
||||
if (mMissingLedger->isComplete())
|
||||
{
|
||||
Ledger::pointer lgr = mMissingLedger->getLedger();
|
||||
if (lgr && (lgr->getLedgerSeq() == ledgerSeq))
|
||||
missingAcquireComplete(mMissingLedger);
|
||||
mMissingLedger = LedgerAcquire::pointer();
|
||||
return;
|
||||
}
|
||||
mMissingSeq = ledgerSeq;
|
||||
if (mMissingLedger->setAccept())
|
||||
mMissingLedger->addOnComplete(boost::bind(&LedgerMaster::missingAcquireComplete, this, _1));
|
||||
@@ -107,20 +115,19 @@ void LedgerMaster::missingAcquireComplete(LedgerAcquire::pointer acq)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock ml(mLock);
|
||||
|
||||
if (acq->isFailed())
|
||||
if (acq->isFailed() && (mMissingSeq != 0))
|
||||
{
|
||||
if (mMissingSeq != 0)
|
||||
{
|
||||
cLog(lsWARNING) << "Acquire failed, invalidating following ledger " << mMissingSeq + 1;
|
||||
mCompleteLedgers.clearValue(mMissingSeq + 1);
|
||||
}
|
||||
cLog(lsWARNING) << "Acquire failed for " << mMissingSeq;
|
||||
}
|
||||
|
||||
mMissingLedger = LedgerAcquire::pointer();
|
||||
mMissingSeq = 0;
|
||||
|
||||
if (!acq->isFailed())
|
||||
{
|
||||
setFullLedger(acq->getLedger());
|
||||
acq->getLedger()->pendSave(false);
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerMaster::setFullLedger(Ledger::ref ledger)
|
||||
@@ -139,9 +146,18 @@ void LedgerMaster::setFullLedger(Ledger::ref ledger)
|
||||
}
|
||||
}
|
||||
|
||||
if (mMissingLedger && mMissingLedger->isComplete())
|
||||
mMissingLedger = LedgerAcquire::pointer();
|
||||
|
||||
if (mMissingLedger || !theConfig.FULL_HISTORY)
|
||||
return;
|
||||
|
||||
if (Ledger::getPendingSaves() > 3)
|
||||
{
|
||||
cLog(lsINFO) << "Too many pending ledger saves";
|
||||
return;
|
||||
}
|
||||
|
||||
// see if there's a ledger gap we need to fill
|
||||
if (!mCompleteLedgers.hasValue(ledger->getLedgerSeq() - 1))
|
||||
{
|
||||
@@ -154,11 +170,15 @@ void LedgerMaster::setFullLedger(Ledger::ref ledger)
|
||||
if (prevMissing != RangeSet::RangeSetAbsent)
|
||||
{
|
||||
cLog(lsINFO) << "Ledger " << prevMissing << " is missing";
|
||||
Ledger::pointer nextLedger = getLedgerBySeq(prevMissing);
|
||||
assert(!mCompleteLedgers.hasValue(prevMissing));
|
||||
Ledger::pointer nextLedger = getLedgerBySeq(prevMissing + 1);
|
||||
if (nextLedger)
|
||||
acquireMissingLedger(nextLedger->getParentHash(), nextLedger->getLedgerSeq() - 1);
|
||||
else
|
||||
cLog(lsWARNING) << "We have a ledger gap we can't quite fix";
|
||||
{
|
||||
mCompleteLedgers.clearValue(prevMissing);
|
||||
cLog(lsWARNING) << "We have a gap we can't fix: " << prevMissing + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ public:
|
||||
|
||||
void switchLedgers(Ledger::ref lastClosed, Ledger::ref newCurrent);
|
||||
|
||||
std::string getCompleteLedgers() { return mCompleteLedgers.toString(); }
|
||||
|
||||
Ledger::pointer closeLedger();
|
||||
|
||||
Ledger::pointer getLedgerBySeq(uint32 index)
|
||||
@@ -75,12 +77,11 @@ public:
|
||||
|
||||
Ledger::pointer getLedgerByHash(const uint256& hash)
|
||||
{
|
||||
if (!hash)
|
||||
if (hash.isZero())
|
||||
return mCurrentLedger;
|
||||
|
||||
if (mCurrentLedger && (mCurrentLedger->getHash() == hash))
|
||||
return mCurrentLedger;
|
||||
|
||||
if (mFinalizedLedger && (mFinalizedLedger->getHash() == hash))
|
||||
return mFinalizedLedger;
|
||||
|
||||
|
||||
16
src/Log.cpp
16
src/Log.cpp
@@ -41,14 +41,18 @@ std::vector< std::pair<std::string, std::string> > LogPartition::getSeverities()
|
||||
Log::~Log()
|
||||
{
|
||||
std::string logMsg = boost::posix_time::to_simple_string(boost::posix_time::second_clock::universal_time());
|
||||
if (!mPartitionName.empty())
|
||||
logMsg += " " + mPartitionName + ":";
|
||||
else
|
||||
logMsg += " ";
|
||||
switch (mSeverity)
|
||||
{
|
||||
case lsTRACE: logMsg += " TRAC "; break;
|
||||
case lsDEBUG: logMsg += " DEBG "; break;
|
||||
case lsINFO: logMsg += " INFO "; break;
|
||||
case lsWARNING: logMsg += " WARN "; break;
|
||||
case lsERROR: logMsg += " EROR "; break;
|
||||
case lsFATAL: logMsg += " FATL "; break;
|
||||
case lsTRACE: logMsg += "TRC "; break;
|
||||
case lsDEBUG: logMsg += "DBG "; break;
|
||||
case lsINFO: logMsg += "NFO "; break;
|
||||
case lsWARNING: logMsg += "WRN "; break;
|
||||
case lsERROR: logMsg += "ERR "; break;
|
||||
case lsFATAL: logMsg += "FTL "; break;
|
||||
case lsINVALID: assert(false); return;
|
||||
}
|
||||
logMsg += oss.str();
|
||||
|
||||
18
src/Log.h
18
src/Log.h
@@ -17,10 +17,10 @@
|
||||
#define SETUP_LOG() static LogPartition logPartition(__FILE__)
|
||||
|
||||
// Standard conditional log
|
||||
#define cLog(x) if (!logPartition.doLog(x)) do {} while (0); else Log(x)
|
||||
#define cLog(x) if (!logPartition.doLog(x)) do {} while (0); else Log(x, logPartition)
|
||||
|
||||
// Log only if an additional condition 'c' is true. Condition is not computed if not needed
|
||||
#define tLog(c,x) if (!logPartition.doLog(x) || !(c)) do {} while(0); else Log(x)
|
||||
#define tLog(c,x) if (!logPartition.doLog(x) || !(c)) do {} while(0); else Log(x, logPartition)
|
||||
|
||||
// Check if should log
|
||||
#define sLog(x) (logPartition.doLog(x))
|
||||
@@ -49,10 +49,8 @@ protected:
|
||||
public:
|
||||
LogPartition(const char *name);
|
||||
|
||||
bool doLog(LogSeverity s)
|
||||
{
|
||||
return s >= mMinSeverity;
|
||||
}
|
||||
bool doLog(LogSeverity s) { return s >= mMinSeverity; }
|
||||
const std::string& getName() const { return mName; }
|
||||
|
||||
static bool setSeverity(const std::string& partition, LogSeverity severity);
|
||||
static void setSeverity(LogSeverity severity);
|
||||
@@ -70,8 +68,9 @@ protected:
|
||||
static LogSeverity sMinSeverity;
|
||||
static std::ofstream* outStream;
|
||||
|
||||
mutable std::ostringstream oss;
|
||||
LogSeverity mSeverity;
|
||||
mutable std::ostringstream oss;
|
||||
LogSeverity mSeverity;
|
||||
std::string mPartitionName;
|
||||
|
||||
static boost::filesystem::path *pathToLog;
|
||||
static uint32 logRotateCounter;
|
||||
@@ -80,6 +79,9 @@ public:
|
||||
Log(LogSeverity s) : mSeverity(s)
|
||||
{ ; }
|
||||
|
||||
Log(LogSeverity s, const LogPartition& p) : mSeverity(s), mPartitionName(p.getName())
|
||||
{ ; }
|
||||
|
||||
~Log();
|
||||
|
||||
template<typename T> std::ostream& operator<<(const T& t) const
|
||||
|
||||
@@ -889,6 +889,9 @@ Json::Value NetworkOPs::getServerInfo()
|
||||
if (mNeedNetworkLedger)
|
||||
info["networkLedger"] = "waiting";
|
||||
|
||||
info["completeLedgers"] = theApp->getMasterLedger().getCompleteLedgers();
|
||||
info["peers"] = theApp->getConnectionPool().getPeerCount();
|
||||
|
||||
Json::Value lastClose = Json::objectValue;
|
||||
lastClose["proposers"] = theApp->getOPs().getPreviousProposers();
|
||||
lastClose["convergeTime"] = theApp->getOPs().getPreviousConvergeTime();
|
||||
|
||||
101
src/Peer.cpp
101
src/Peer.cpp
@@ -1,4 +1,3 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
@@ -539,8 +538,8 @@ void Peer::processReadBuffer()
|
||||
|
||||
case ripple::mtVALIDATION:
|
||||
{
|
||||
ripple::TMValidation msg;
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
boost::shared_ptr<ripple::TMValidation> msg = boost::make_shared<ripple::TMValidation>();
|
||||
if (msg->ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvValidation(msg);
|
||||
else
|
||||
cLog(lsWARNING) << "parse error: " << type;
|
||||
@@ -575,6 +574,13 @@ void Peer::processReadBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::punishPeer(const boost::weak_ptr<Peer>& wp, PeerPunish pp)
|
||||
{
|
||||
Peer::pointer p = wp.lock();
|
||||
if (p)
|
||||
p->punishPeer(pp);
|
||||
}
|
||||
|
||||
void Peer::recvHello(ripple::TMHello& packet)
|
||||
{
|
||||
bool bDetach = true;
|
||||
@@ -766,23 +772,50 @@ void Peer::recvHaveTxSet(ripple::TMHaveTransactionSet& packet)
|
||||
punishPeer(PP_UNWANTED_DATA);
|
||||
}
|
||||
|
||||
void Peer::recvValidation(ripple::TMValidation& packet)
|
||||
static void checkValidation(Job&, SerializedValidation::pointer val, uint256 signingHash,
|
||||
bool isTrusted, boost::shared_ptr<ripple::TMValidation> packet, boost::weak_ptr<Peer> peer)
|
||||
{
|
||||
if (packet.validation().size() < 50)
|
||||
#ifndef TRUST_NETWORK
|
||||
try
|
||||
#endif
|
||||
{
|
||||
if (!val->isValid(signingHash))
|
||||
{
|
||||
cLog(lsWARNING) << "Validation is invalid";
|
||||
Peer::punishPeer(peer, PP_UNKNOWN_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (theApp->getOPs().recvValidation(val))
|
||||
{
|
||||
Peer::pointer pp = peer.lock();
|
||||
PackedMessage::pointer message = boost::make_shared<PackedMessage>(*packet, ripple::mtVALIDATION);
|
||||
theApp->getConnectionPool().relayMessage(pp ? pp.get() : NULL, message);
|
||||
}
|
||||
}
|
||||
#ifndef TRUST_NETWORK
|
||||
catch (...)
|
||||
{
|
||||
cLog(lsWARNING) << "Exception processing validation";
|
||||
Peer::punishPeer(peer, PP_UNKNOWN_REQUEST);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Peer::recvValidation(const boost::shared_ptr<ripple::TMValidation>& packet)
|
||||
{
|
||||
if (packet->validation().size() < 50)
|
||||
{
|
||||
cLog(lsWARNING) << "Too small validation from peer";
|
||||
punishPeer(PP_UNKNOWN_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
// OPTIMIZEME: Should just defer validation checking to another thread
|
||||
// checking the signature is expensive (but should do 'isNew' check here)
|
||||
|
||||
#ifndef TRUST_NETWORK
|
||||
try
|
||||
#endif
|
||||
{
|
||||
Serializer s(packet.validation());
|
||||
Serializer s(packet->validation());
|
||||
SerializerIterator sit(s);
|
||||
SerializedValidation::pointer val = boost::make_shared<SerializedValidation>(boost::ref(sit), false);
|
||||
|
||||
@@ -793,18 +826,10 @@ void Peer::recvValidation(ripple::TMValidation& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!val->isValid(signingHash))
|
||||
{
|
||||
cLog(lsWARNING) << "Validation is invalid";
|
||||
punishPeer(PP_UNKNOWN_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (theApp->getOPs().recvValidation(val))
|
||||
{
|
||||
PackedMessage::pointer message = boost::make_shared<PackedMessage>(packet, ripple::mtVALIDATION);
|
||||
theApp->getConnectionPool().relayMessage(this, message);
|
||||
}
|
||||
bool isTrusted = theApp->getUNL().nodeInUNL(val->getSignerPublic());
|
||||
theApp->getJobQueue().addJob(isTrusted ? jtVALIDATION_t : jtVALIDATION_ut,
|
||||
boost::bind(&checkValidation, _1, val, signingHash, isTrusted, packet,
|
||||
boost::weak_ptr<Peer>(shared_from_this())));
|
||||
}
|
||||
#ifndef TRUST_NETWORK
|
||||
catch (...)
|
||||
@@ -993,6 +1018,9 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
ripple::TMLedgerData reply;
|
||||
bool fatLeaves = true, fatRoot = false;
|
||||
|
||||
if (packet.has_requestcookie())
|
||||
reply.set_requestcookie(packet.requestcookie());
|
||||
|
||||
if (packet.itype() == ripple::liTS_CANDIDATE)
|
||||
{ // Request is for a transaction candidate set
|
||||
cLog(lsINFO) << "Received request for TX candidate set data " << getIP();
|
||||
@@ -1034,7 +1062,10 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
tLog(!ledger, lsINFO) << "Don't have ledger " << ledgerhash;
|
||||
}
|
||||
else if (packet.has_ledgerseq())
|
||||
{
|
||||
ledger = theApp->getMasterLedger().getLedgerBySeq(packet.ledgerseq());
|
||||
tLog(!ledger, lsINFO) << "Don't have ledger " << packet.ledgerseq();
|
||||
}
|
||||
else if (packet.has_ltype() && (packet.ltype() == ripple::ltCURRENT))
|
||||
ledger = theApp->getMasterLedger().getCurrentLedger();
|
||||
else if (packet.has_ltype() && (packet.ltype() == ripple::ltCLOSED) )
|
||||
@@ -1053,10 +1084,13 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
if ((!ledger) || (packet.has_ledgerseq() && (packet.ledgerseq() != ledger->getLedgerSeq())))
|
||||
{
|
||||
punishPeer(PP_UNKNOWN_REQUEST);
|
||||
if (ledger)
|
||||
cLog(lsWARNING) << "Ledger has wrong sequence";
|
||||
else
|
||||
cLog(lsWARNING) << "Can't find the ledger they want";
|
||||
if (sLog(lsWARNING))
|
||||
{
|
||||
if (ledger)
|
||||
Log(lsWARNING) << "Ledger has wrong sequence";
|
||||
else
|
||||
Log(lsWARNING) << "Can't find the ledger they want";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1068,12 +1102,11 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
|
||||
if(packet.itype() == ripple::liBASE)
|
||||
{ // they want the ledger base data
|
||||
cLog(lsTRACE) << "Want ledger base data";
|
||||
cLog(lsTRACE) << "They want ledger base data";
|
||||
Serializer nData(128);
|
||||
ledger->addRaw(nData);
|
||||
reply.add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength());
|
||||
|
||||
cLog(lsINFO) << "Ledger root w/map roots request";
|
||||
SHAMap::pointer map = ledger->peekAccountStateMap();
|
||||
if (map && map->getHash().isNonZero())
|
||||
{ // return account state root node if possible
|
||||
@@ -1086,7 +1119,7 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
map = ledger->peekTransactionMap();
|
||||
if (map && map->getHash().isNonZero())
|
||||
{
|
||||
rootNode.resize(0);
|
||||
rootNode.erase();
|
||||
if (map->getRootNode(rootNode, snfWIRE))
|
||||
reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength());
|
||||
}
|
||||
@@ -1099,9 +1132,10 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((packet.itype() == ripple::liTX_NODE) || (packet.itype() == ripple::liAS_NODE))
|
||||
map = (packet.itype() == ripple::liTX_NODE) ?
|
||||
ledger->peekTransactionMap() : ledger->peekAccountStateMap();
|
||||
if (packet.itype() == ripple::liTX_NODE)
|
||||
map = ledger->peekTransactionMap();
|
||||
else if (packet.itype() == ripple::liAS_NODE)
|
||||
map = ledger->peekAccountStateMap();
|
||||
}
|
||||
|
||||
if ((!map) || (packet.nodeids_size() == 0))
|
||||
@@ -1125,7 +1159,6 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
{
|
||||
std::vector<SHAMapNode>::iterator nodeIDIterator;
|
||||
std::list< std::vector<unsigned char> >::iterator rawNodeIterator;
|
||||
int count = 0;
|
||||
for(nodeIDIterator = nodeIDs.begin(), rawNodeIterator = rawNodes.begin();
|
||||
nodeIDIterator != nodeIDs.end(); ++nodeIDIterator, ++rawNodeIterator)
|
||||
{
|
||||
@@ -1134,12 +1167,9 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
ripple::TMLedgerNode* node = reply.add_nodes();
|
||||
node->set_nodeid(nID.getDataPtr(), nID.getLength());
|
||||
node->set_nodedata(&rawNodeIterator->front(), rawNodeIterator->size());
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packet.has_requestcookie())
|
||||
reply.set_requestcookie(packet.requestcookie());
|
||||
PackedMessage::pointer oPacket = boost::make_shared<PackedMessage>(reply, ripple::mtLEDGER_DATA);
|
||||
sendPacket(oPacket);
|
||||
}
|
||||
@@ -1148,6 +1178,7 @@ void Peer::recvLedger(ripple::TMLedgerData& packet)
|
||||
{
|
||||
if (packet.nodes().size() <= 0)
|
||||
{
|
||||
cLog(lsWARNING) << "Ledger data with no nodes";
|
||||
punishPeer(PP_INVALID_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ protected:
|
||||
|
||||
void recvHello(ripple::TMHello& packet);
|
||||
void recvTransaction(ripple::TMTransaction& packet);
|
||||
void recvValidation(ripple::TMValidation& packet);
|
||||
void recvValidation(const boost::shared_ptr<ripple::TMValidation>& packet);
|
||||
void recvGetValidation(ripple::TMGetValidations& packet);
|
||||
void recvContact(ripple::TMContact& packet);
|
||||
void recvGetContacts(ripple::TMGetContacts& packet);
|
||||
@@ -151,6 +151,7 @@ public:
|
||||
void sendGetPeers();
|
||||
|
||||
void punishPeer(PeerPunish pp);
|
||||
static void punishPeer(const boost::weak_ptr<Peer>&, PeerPunish);
|
||||
|
||||
Json::Value getJson();
|
||||
bool isConnected() const { return mHelloed && !mDetaching; }
|
||||
|
||||
@@ -216,7 +216,7 @@ Json::Value RPCHandler::authorize(const uint256& uLedger,
|
||||
{
|
||||
naMasterAccountPublic.setAccountPublic(naMasterGenerator, iIndex);
|
||||
|
||||
Log(lsDEBUG) << "authorize: " << iIndex << " : " << naMasterAccountPublic.humanAccountID() << " : " << naSrcAccountID.humanAccountID();
|
||||
cLog(lsDEBUG) << "authorize: " << iIndex << " : " << naMasterAccountPublic.humanAccountID() << " : " << naSrcAccountID.humanAccountID();
|
||||
|
||||
bFound = naSrcAccountID.getAccountID() == naMasterAccountPublic.getAccountID();
|
||||
if (!bFound)
|
||||
@@ -247,7 +247,7 @@ Json::Value RPCHandler::authorize(const uint256& uLedger,
|
||||
|
||||
if (saSrcBalance < saFee)
|
||||
{
|
||||
Log(lsINFO) << "authorize: Insufficent funds for fees: fee=" << saFee.getText() << " balance=" << saSrcBalance.getText();
|
||||
cLog(lsINFO) << "authorize: Insufficent funds for fees: fee=" << saFee.getText() << " balance=" << saSrcBalance.getText();
|
||||
|
||||
return rpcError(rpcINSUF_FUNDS);
|
||||
}
|
||||
@@ -2410,7 +2410,7 @@ Json::Value RPCHandler::doLogRotate(const Json::Value& params)
|
||||
|
||||
Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& params,int role)
|
||||
{
|
||||
Log(lsTRACE) << "RPC:" << command;
|
||||
cLog(lsTRACE) << "RPC:" << command;
|
||||
|
||||
static struct {
|
||||
const char* pCommand;
|
||||
|
||||
@@ -54,15 +54,18 @@ uint32 RangeSet::getPrev(uint32 v) const
|
||||
|
||||
uint32 RangeSet::prevMissing(uint32 v) const
|
||||
{ // largest number not in the set that is less than the given number
|
||||
cLog(lsTRACE) << "prevMissing(" << v << ") " << toString();
|
||||
for (const_reverse_iterator it = rbegin(); it != rend(); ++it)
|
||||
{
|
||||
if (lower(it) <= v)
|
||||
{
|
||||
if (upper(it) < v)
|
||||
return upper(it) + 1;
|
||||
if ((upper(it) + 1) < v)
|
||||
return upper(it) + 1;
|
||||
if (lower(it) == 0)
|
||||
return RangeSetAbsent;
|
||||
if ((lower(it) - 1) < v)
|
||||
return lower(it) - 1;
|
||||
}
|
||||
}
|
||||
if (v > 0)
|
||||
return v - 1;
|
||||
return RangeSetAbsent;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// YYY OPTIMIZE: When calculating path increment, note if increment consumes all liquidity. No need to revesit path in the future
|
||||
// if all liquidity is used.
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/format.hpp>
|
||||
@@ -685,22 +687,26 @@ TER RippleCalc::calcNodeOfferFwd(
|
||||
|
||||
}
|
||||
|
||||
// Cur is the driver and will be filled exactly.
|
||||
// Compute how much might flow for the node for the pass. Don not actually adjust balances.
|
||||
// uQualityIn -> uQualityOut
|
||||
// saPrvReq -> saCurReq
|
||||
// sqPrvAct -> saCurAct
|
||||
// This is a minimizing routine: moving in reverse it propagates the send limit to the sender, moving forward it propagates the
|
||||
// actual send toward the receiver.
|
||||
// This routine works backwards as it calculates previous wants based on previous credit limits and current wants.
|
||||
// This routine works forwards as it calculates current deliver based on previous delivery limits and current wants.
|
||||
// This routine works backwards:
|
||||
// - cur is the driver: it calculates previous wants based on previous credit limits and current wants.
|
||||
// This routine works forwards:
|
||||
// - prv is the driver: it calculates current deliver based on previous delivery limits and current wants.
|
||||
// This routine is called one or two times for a node in a pass. If called once, it will work and set a rate. If called again,
|
||||
// the new work must not worsen the previous rate.
|
||||
// XXX Deal with uQualityIn or uQualityOut = 0
|
||||
void RippleCalc::calcNodeRipple(
|
||||
const uint32 uQualityIn,
|
||||
const uint32 uQualityOut,
|
||||
const STAmount& saPrvReq, // --> in limit including fees, <0 = unlimited
|
||||
const STAmount& saCurReq, // --> out limit (driver)
|
||||
STAmount& saPrvAct, // <-> in limit including achieved
|
||||
STAmount& saCurAct, // <-> out limit achieved.
|
||||
STAmount& saPrvAct, // <-> in limit including achieved so far: <-- <= -->
|
||||
STAmount& saCurAct, // <-> out limit including achieved : <-- <= -->
|
||||
uint64& uRateMax)
|
||||
{
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeRipple> uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s")
|
||||
@@ -729,13 +735,18 @@ void RippleCalc::calcNodeRipple(
|
||||
// No fee.
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeRipple: No fees"));
|
||||
|
||||
// Only process if we are not worsing previously processed.
|
||||
if (!uRateMax || STAmount::uRateOne <= uRateMax)
|
||||
{
|
||||
// Limit amount to transfer if need.
|
||||
STAmount saTransfer = bPrvUnlimited ? saCur : std::min(saPrv, saCur);
|
||||
|
||||
// In reverse, we want to propagate the limited cur to prv and set actual cur.
|
||||
// In forward, we want to propagate the limited prv to cur and set actual prv.
|
||||
saPrvAct += saTransfer;
|
||||
saCurAct += saTransfer;
|
||||
|
||||
// If no rate limit, set rate limit to avoid combining with something with a worse rate.
|
||||
if (!uRateMax)
|
||||
uRateMax = STAmount::uRateOne;
|
||||
}
|
||||
@@ -788,6 +799,7 @@ void RippleCalc::calcNodeRipple(
|
||||
}
|
||||
|
||||
// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur...
|
||||
// No account adjustments in reverse as we don't know how much is going to actually be pushed through yet.
|
||||
// <-- tesSUCCESS or tepPATH_DRY
|
||||
TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality)
|
||||
{
|
||||
@@ -899,23 +911,36 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
|
||||
if (saPrvRedeemReq) // Previous has IOUs to redeem.
|
||||
{
|
||||
// Redeem at 1:1
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Redeem at 1:1"));
|
||||
|
||||
saCurWantedAct = std::min(saPrvRedeemReq, saCurWantedReq);
|
||||
saPrvRedeemAct = saCurWantedAct;
|
||||
|
||||
uRateMax = STAmount::uRateOne;
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Redeem at 1:1 saPrvRedeemReq=%s (available) saPrvRedeemAct=%s uRateMax=%s")
|
||||
% saPrvRedeemReq.getFullText()
|
||||
% saPrvRedeemAct.getFullText()
|
||||
% STAmount::saFromRate(uRateMax).getText());
|
||||
}
|
||||
else
|
||||
{
|
||||
saPrvRedeemAct.zero(saCurWantedAct);
|
||||
}
|
||||
|
||||
// Calculate issuing.
|
||||
saPrvIssueAct.zero(saCurWantedAct);
|
||||
|
||||
if (saCurWantedReq != saCurWantedAct // Need more.
|
||||
&& saPrvIssueReq) // Will accept IOUs from prevous.
|
||||
{
|
||||
// Rate: quality in : 1.0
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0"));
|
||||
|
||||
// If we previously redeemed and this has a poorer rate, this won't be included the current increment.
|
||||
calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct, uRateMax);
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Issuing: Rate: quality in : 1.0 saPrvIssueAct=%s saCurWantedAct=%s")
|
||||
% saPrvIssueAct.getFullText()
|
||||
% saCurWantedAct.getFullText());
|
||||
}
|
||||
|
||||
if (!saCurWantedAct)
|
||||
@@ -927,15 +952,19 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
|
||||
else
|
||||
{
|
||||
// ^|account --> ACCOUNT --> account
|
||||
saPrvRedeemAct.zero(saCurRedeemReq);
|
||||
saPrvIssueAct.zero(saCurRedeemReq);
|
||||
|
||||
// redeem (part 1) -> redeem
|
||||
if (saCurRedeemReq // Next wants IOUs redeemed.
|
||||
&& saPrvRedeemReq) // Previous has IOUs to redeem.
|
||||
{
|
||||
// Rate : 1.0 : quality out
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out"));
|
||||
|
||||
calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax);
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out saPrvRedeemAct=%s saCurRedeemAct=%s")
|
||||
% saPrvRedeemAct.getFullText()
|
||||
% saCurRedeemAct.getFullText());
|
||||
}
|
||||
|
||||
// issue (part 1) -> redeem
|
||||
@@ -943,9 +972,11 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
|
||||
&& saPrvRedeemAct == saPrvRedeemReq) // Previous has no IOUs to redeem remaining.
|
||||
{
|
||||
// Rate: quality in : quality out
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out"));
|
||||
|
||||
calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax);
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out: saPrvIssueAct=%s saCurRedeemAct=%s")
|
||||
% saPrvIssueAct.getFullText()
|
||||
% saCurRedeemAct.getFullText());
|
||||
}
|
||||
|
||||
// redeem (part 2) -> issue.
|
||||
@@ -954,25 +985,30 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
|
||||
&& saPrvRedeemAct != saPrvRedeemReq) // Did not complete redeeming previous IOUs.
|
||||
{
|
||||
// Rate : 1.0 : transfer_rate
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate"));
|
||||
|
||||
calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax);
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate: saPrvRedeemAct=%s saCurIssueAct=%s")
|
||||
% saPrvRedeemAct.getFullText()
|
||||
% saCurIssueAct.getFullText());
|
||||
}
|
||||
|
||||
// issue (part 2) -> issue
|
||||
if (saCurIssueReq != saCurIssueAct // Need wants more IOUs issued.
|
||||
&& saCurRedeemAct == saCurRedeemReq // Can only issue if completed redeeming.
|
||||
&& saPrvRedeemReq == saPrvRedeemAct) // Previously redeemed all owed IOUs.
|
||||
&& saPrvRedeemReq == saPrvRedeemAct // Previously redeemed all owed IOUs.
|
||||
&& saPrvIssueReq) // Previous can issue.
|
||||
{
|
||||
// Rate: quality in : 1.0
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0"));
|
||||
|
||||
calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax);
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0: saPrvIssueAct=%s saCurIssueAct=%s")
|
||||
% saPrvIssueAct.getFullText()
|
||||
% saCurIssueAct.getFullText());
|
||||
}
|
||||
|
||||
if (!saCurRedeemAct && !saCurIssueAct)
|
||||
{
|
||||
// Must want something.
|
||||
// Did not make progress.
|
||||
terResult = tepPATH_DRY;
|
||||
}
|
||||
|
||||
@@ -990,6 +1026,9 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
|
||||
// Note: deliver is always issue as ACCOUNT is the issuer for the offer input.
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> offer"));
|
||||
|
||||
saPrvRedeemAct.zero(saCurRedeemReq);
|
||||
saPrvIssueAct.zero(saCurRedeemReq);
|
||||
|
||||
// redeem -> deliver/issue.
|
||||
if (saPrvOwed.isPositive() // Previous has IOUs to redeem.
|
||||
&& saCurDeliverReq) // Need some issued.
|
||||
@@ -1019,6 +1058,8 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
|
||||
}
|
||||
else if (!bPrvAccount && bNxtAccount)
|
||||
{
|
||||
saPrvDeliverAct.zero(saCurRedeemReq);
|
||||
|
||||
if (uIndex == uLast)
|
||||
{
|
||||
// offer --> ACCOUNT --> $
|
||||
@@ -1079,6 +1120,8 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
|
||||
// deliver/redeem -> deliver/issue.
|
||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> offer"));
|
||||
|
||||
saPrvDeliverAct.zero(saCurRedeemReq);
|
||||
|
||||
// Rate : 1.0 : transfer_rate
|
||||
calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct, uRateMax);
|
||||
|
||||
@@ -1092,6 +1135,7 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
|
||||
return terResult;
|
||||
}
|
||||
|
||||
// When moving forward, we know the actual amount to push through so adjust balances.
|
||||
// Perform balance adjustments between previous and current node.
|
||||
// - The previous node: specifies what to push through to current.
|
||||
// - All of previous output is consumed.
|
||||
@@ -1429,7 +1473,7 @@ TER PathState::pushImply(
|
||||
}
|
||||
|
||||
// Append a node and insert before it any implied nodes.
|
||||
// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_LINE
|
||||
// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_LINE, tepPATH_DRY
|
||||
TER PathState::pushNode(
|
||||
const int iType,
|
||||
const uint160& uAccountID,
|
||||
@@ -1477,6 +1521,8 @@ TER PathState::pushNode(
|
||||
pnCur.uAccountID, // Current account.
|
||||
pnCur.uCurrencyID, // Wanted currency.
|
||||
!!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer.
|
||||
|
||||
// Note: pnPrv may no longer be the immediately previous node.
|
||||
}
|
||||
|
||||
if (tesSUCCESS == terResult && !vpnNodes.empty())
|
||||
@@ -1511,6 +1557,13 @@ TER PathState::pushNode(
|
||||
<< " for "
|
||||
<< STAmount::createHumanCurrency(pnPrv.uCurrencyID)
|
||||
<< "." ;
|
||||
|
||||
STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, uCurrencyID);
|
||||
|
||||
if (!saOwed.isPositive() && *saOwed.negate() >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, uCurrencyID))
|
||||
{
|
||||
terResult = tepPATH_DRY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1792,6 +1845,8 @@ void RippleCalc::pathNext(PathState::ref pspCur, const int iPaths, const LedgerE
|
||||
const bool bMultiQuality = iPaths == 1;
|
||||
const unsigned int uLast = pspCur->vpnNodes.size() - 1;
|
||||
|
||||
pspCur->bConsumed = false;
|
||||
|
||||
// YYY This clearing should only be needed for nice logging.
|
||||
pspCur->saInPass = STAmount(pspCur->saInReq.getCurrency(), pspCur->saInReq.getIssuer());
|
||||
pspCur->saOutPass = STAmount(pspCur->saOutReq.getCurrency(), pspCur->saOutReq.getIssuer());
|
||||
@@ -1897,6 +1952,10 @@ TER RippleCalc::rippleCalc(
|
||||
|
||||
vpsPaths.push_back(pspDirect);
|
||||
}
|
||||
else if (terNO_LINE != pspDirect->terStatus)
|
||||
{
|
||||
terResult = pspDirect->terStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1917,28 +1976,26 @@ TER RippleCalc::rippleCalc(
|
||||
|
||||
if (pspExpanded)
|
||||
{
|
||||
// Return if malformed.
|
||||
// Return, if the path specification was malformed.
|
||||
if (isTemMalformed(pspExpanded->terStatus))
|
||||
return pspExpanded->terStatus;
|
||||
|
||||
if (tesSUCCESS == pspExpanded->terStatus)
|
||||
if (tesSUCCESS == pspExpanded->terStatus) {
|
||||
terResult = tesSUCCESS; // Had a success.
|
||||
|
||||
vpsPaths.push_back(pspExpanded);
|
||||
vpsPaths.push_back(pspExpanded);
|
||||
}
|
||||
else if (terNO_LINE != pspExpanded->terStatus)
|
||||
{
|
||||
terResult = pspExpanded->terStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vpsPaths.empty())
|
||||
if (tesSUCCESS != terResult)
|
||||
{
|
||||
// No paths. Missing credit lines.
|
||||
return terNO_LINE;
|
||||
}
|
||||
else if (tesSUCCESS != terResult)
|
||||
{
|
||||
// No path successes.
|
||||
|
||||
return vpsPaths[0]->terStatus;
|
||||
}
|
||||
return terResult == temUNCERTAIN ? terNO_LINE : terResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
terResult = temUNCERTAIN;
|
||||
@@ -1955,6 +2012,7 @@ TER RippleCalc::rippleCalc(
|
||||
{
|
||||
PathState::pointer pspBest;
|
||||
const LedgerEntrySet lesCheckpoint = lesActive;
|
||||
int iDry = 0;
|
||||
|
||||
// Find the best path.
|
||||
BOOST_FOREACH(PathState::pointer& pspCur, vpsPaths)
|
||||
@@ -1969,12 +2027,12 @@ TER RippleCalc::rippleCalc(
|
||||
if (!pspCur->uQuality) {
|
||||
// Path was dry.
|
||||
|
||||
nothing();
|
||||
++iDry;
|
||||
}
|
||||
else {
|
||||
tLog(!pspCur->saInPass || !pspCur->saOutPass, lsDEBUG)
|
||||
<< boost::str(boost::format("calcOfferFirst: better: uQuality=%016lX saInPass=%s saOutPass=%s")
|
||||
% pspCur->uQuality
|
||||
<< boost::str(boost::format("rippleCalc: better: uQuality=%s saInPass=%s saOutPass=%s")
|
||||
% STAmount::saFromRate(pspCur->uQuality)
|
||||
% pspCur->saInPass.getFullText()
|
||||
% pspCur->saOutPass.getFullText());
|
||||
|
||||
@@ -1984,8 +2042,8 @@ TER RippleCalc::rippleCalc(
|
||||
|| !pspBest // Best is not yet set.
|
||||
|| PathState::lessPriority(pspBest, pspCur)) // Current is better than set.
|
||||
{
|
||||
cLog(lsDEBUG) << boost::str(boost::format("calcOfferFirst: better: uQuality=%016lX saInPass=%s saOutPass=%s")
|
||||
% pspCur->uQuality
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: better: uQuality=%s saInPass=%s saOutPass=%s")
|
||||
% STAmount::saFromRate(pspCur->uQuality)
|
||||
% pspCur->saInPass.getFullText()
|
||||
% pspCur->saOutPass.getFullText());
|
||||
|
||||
@@ -2000,8 +2058,8 @@ TER RippleCalc::rippleCalc(
|
||||
{
|
||||
// Apply best path.
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("calcOfferFirst: best: uQuality=%016lX saInPass=%s saOutPass=%s")
|
||||
% pspBest->uQuality
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: best: uQuality=%s saInPass=%s saOutPass=%s")
|
||||
% STAmount::saFromRate(pspBest->uQuality)
|
||||
% pspBest->saInPass.getFullText()
|
||||
% pspBest->saOutPass.getFullText());
|
||||
|
||||
@@ -2014,18 +2072,25 @@ TER RippleCalc::rippleCalc(
|
||||
saInAct += pspBest->saInPass;
|
||||
saOutAct += pspBest->saOutPass;
|
||||
|
||||
if (pspBest->bConsumed)
|
||||
{
|
||||
++iDry;
|
||||
pspBest->uQuality = 0;
|
||||
}
|
||||
|
||||
if (saOutAct == saDstAmountReq)
|
||||
{
|
||||
// Done. Delivered requested amount.
|
||||
|
||||
terResult = tesSUCCESS;
|
||||
}
|
||||
else if (saInAct != saMaxAmountReq)
|
||||
else if (saInAct != saMaxAmountReq && iDry != vpsPaths.size())
|
||||
{
|
||||
// Have not met requested amount or max send. Prepare for next pass.
|
||||
// Have not met requested amount or max send, try to do more. Prepare for next pass.
|
||||
|
||||
// Merge best pass' umReverse.
|
||||
rc.mumSource.insert(pspBest->umReverse.begin(), pspBest->umReverse.end());
|
||||
|
||||
}
|
||||
else if (!bPartialPayment)
|
||||
{
|
||||
|
||||
@@ -90,14 +90,15 @@ public:
|
||||
|
||||
LedgerEntrySet lesEntries;
|
||||
|
||||
int mIndex;
|
||||
uint64 uQuality; // 0 = none.
|
||||
int mIndex; // Index/rank amoung siblings.
|
||||
uint64 uQuality; // 0 = no quality/liquity left.
|
||||
const STAmount& saInReq; // --> Max amount to spend by sender.
|
||||
STAmount saInAct; // --> Amount spent by sender so far.
|
||||
STAmount saInPass; // <-- Amount spent by sender.
|
||||
const STAmount& saOutReq; // --> Amount to send.
|
||||
STAmount saOutAct; // --> Amount actually sent so far.
|
||||
STAmount saOutPass; // <-- Amount actually sent.
|
||||
bool bConsumed; // If true, use consumes full liquidity. False, may or may not.
|
||||
|
||||
PathState(
|
||||
const int iIndex,
|
||||
|
||||
@@ -41,6 +41,7 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
|
||||
stack.pop();
|
||||
|
||||
int base = rand() % 256;
|
||||
bool have_all = false;
|
||||
for (int ii = 0; ii < 16; ++ii)
|
||||
{ // traverse in semi-random order
|
||||
int branch = (base + ii) % 16;
|
||||
@@ -76,7 +77,8 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
|
||||
}
|
||||
if (!d)
|
||||
{ // we need this node
|
||||
nodeIDs.push_back(node->getChildNodeID(branch));
|
||||
have_all = false;
|
||||
nodeIDs.push_back(childID);
|
||||
if (--max <= 0)
|
||||
return;
|
||||
}
|
||||
@@ -84,6 +86,8 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
|
||||
stack.push(d);
|
||||
}
|
||||
}
|
||||
if (have_all)
|
||||
node->setFullBelow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
FIELD(Flags, UINT32, 2)
|
||||
FIELD(SourceTag, UINT32, 3)
|
||||
FIELD(Sequence, UINT32, 4)
|
||||
FIELD(LastTxnSeq, UINT32, 5)
|
||||
FIELD(PreviousTxnLgrSeq, UINT32, 5)
|
||||
FIELD(LedgerSequence, UINT32, 6)
|
||||
FIELD(CloseTime, UINT32, 7)
|
||||
FIELD(ParentCloseTime, UINT32, 8)
|
||||
@@ -71,7 +71,7 @@
|
||||
FIELD(ParentHash, HASH256, 2)
|
||||
FIELD(TransactionHash, HASH256, 3)
|
||||
FIELD(AccountHash, HASH256, 4)
|
||||
FIELD(LastTxnID, HASH256, 5)
|
||||
FIELD(PreviousTxnID, HASH256, 5)
|
||||
FIELD(LedgerIndex, HASH256, 6)
|
||||
FIELD(WalletLocator, HASH256, 7)
|
||||
FIELD(PublishHash, HASH256, 8)
|
||||
@@ -95,12 +95,6 @@
|
||||
// currency amount (uncommon)
|
||||
FIELD(MinimumOffer, AMOUNT, 16)
|
||||
FIELD(RippleEscrow, AMOUNT, 17)
|
||||
FIELD(PreviousBalance, AMOUNT, 18)
|
||||
FIELD(FinalBalance, AMOUNT, 19)
|
||||
FIELD(PreviousTakerPays, AMOUNT, 20)
|
||||
FIELD(PreviousTakerGets, AMOUNT, 21)
|
||||
FIELD(FinalTakerPays, AMOUNT, 22)
|
||||
FIELD(FinalTakerGets, AMOUNT, 23)
|
||||
|
||||
// variable length
|
||||
FIELD(PublicKey, VL, 1)
|
||||
@@ -123,16 +117,12 @@
|
||||
FIELD(Target, ACCOUNT, 7)
|
||||
FIELD(AuthorizedKey, ACCOUNT, 8)
|
||||
|
||||
// account (uncommon)
|
||||
FIELD(PreviousAccount, ACCOUNT, 16)
|
||||
FIELD(LowID, ACCOUNT, 17)
|
||||
FIELD(HighID, ACCOUNT, 18)
|
||||
|
||||
// path set
|
||||
FIELD(Paths, PATHSET, 1)
|
||||
|
||||
// vector of 256-bit
|
||||
FIELD(Indexes, VECTOR256, 1)
|
||||
FIELD(Hashes, VECTOR256, 2)
|
||||
|
||||
// inner object
|
||||
// OBJECT/1 is reserved for end of object
|
||||
@@ -141,6 +131,8 @@
|
||||
FIELD(CreatedNode, OBJECT, 3)
|
||||
FIELD(DeletedNode, OBJECT, 4)
|
||||
FIELD(ModifiedNode, OBJECT, 5)
|
||||
FIELD(PreviousFields, OBJECT, 6)
|
||||
FIELD(FinalFields, OBJECT, 7)
|
||||
|
||||
// array of objects
|
||||
// ARRAY/1 is reserved for end of array
|
||||
|
||||
@@ -75,37 +75,37 @@ Json::Value SerializedLedgerEntry::getJson(int options) const
|
||||
|
||||
bool SerializedLedgerEntry::isThreadedType()
|
||||
{
|
||||
return getFieldIndex(sfLastTxnID) != -1;
|
||||
return getFieldIndex(sfPreviousTxnID) != -1;
|
||||
}
|
||||
|
||||
bool SerializedLedgerEntry::isThreaded()
|
||||
{
|
||||
return isFieldPresent(sfLastTxnID);
|
||||
return isFieldPresent(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
uint256 SerializedLedgerEntry::getThreadedTransaction()
|
||||
{
|
||||
return getFieldH256(sfLastTxnID);
|
||||
return getFieldH256(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
uint32 SerializedLedgerEntry::getThreadedLedger()
|
||||
{
|
||||
return getFieldU32(sfLastTxnSeq);
|
||||
return getFieldU32(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
|
||||
bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID)
|
||||
{
|
||||
uint256 oldPrevTxID = getFieldH256(sfLastTxnID);
|
||||
uint256 oldPrevTxID = getFieldH256(sfPreviousTxnID);
|
||||
Log(lsTRACE) << "Thread Tx:" << txID << " prev:" << oldPrevTxID;
|
||||
if (oldPrevTxID == txID)
|
||||
{ // this transaction is already threaded
|
||||
assert(getFieldU32(sfLastTxnSeq) == ledgerSeq);
|
||||
assert(getFieldU32(sfPreviousTxnLgrSeq) == ledgerSeq);
|
||||
return false;
|
||||
}
|
||||
prevTxID = oldPrevTxID;
|
||||
prevLedgerID = getFieldU32(sfLastTxnSeq);
|
||||
setFieldH256(sfLastTxnID, txID);
|
||||
setFieldU32(sfLastTxnSeq, ledgerSeq);
|
||||
prevLedgerID = getFieldU32(sfPreviousTxnLgrSeq);
|
||||
setFieldH256(sfPreviousTxnID, txID);
|
||||
setFieldU32(sfPreviousTxnLgrSeq, ledgerSeq);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -206,6 +206,8 @@ bool STObject::isValidForType()
|
||||
|
||||
bool STObject::isFieldAllowed(SField::ref field)
|
||||
{
|
||||
if (isFree())
|
||||
return true;
|
||||
BOOST_FOREACH(SOElement::ptr elem, mType)
|
||||
{ // are any required elemnents missing
|
||||
if (elem->e_field == field)
|
||||
@@ -242,6 +244,14 @@ std::auto_ptr<SerializedType> STObject::deserialize(SerializerIterator& sit, SFi
|
||||
return object;
|
||||
}
|
||||
|
||||
bool STObject::hasMatchingEntry(const SerializedType& t)
|
||||
{
|
||||
const SerializedType* o = peekAtPField(t.getFName());
|
||||
if (!o)
|
||||
return false;
|
||||
return t == *o;
|
||||
}
|
||||
|
||||
std::string STObject::getFullText() const
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
|
||||
virtual SerializedTypeID getSType() const { return STI_OBJECT; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return mData.empty(); }
|
||||
|
||||
virtual void add(Serializer& s) const { add(s, true); } // just inner elements
|
||||
void add(Serializer& s, bool withSignature) const;
|
||||
@@ -156,6 +157,9 @@ public:
|
||||
iterator end() { return mData.end(); }
|
||||
const_iterator begin() const { return mData.begin(); }
|
||||
const_iterator end() const { return mData.end(); }
|
||||
bool empty() const { return mData.empty(); }
|
||||
|
||||
bool hasMatchingEntry(const SerializedType&);
|
||||
|
||||
bool operator==(const STObject& o) const;
|
||||
bool operator!=(const STObject& o) const { return ! (*this == o); }
|
||||
@@ -238,6 +242,7 @@ public:
|
||||
|
||||
virtual SerializedTypeID getSType() const { return STI_ARRAY; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value.empty(); }
|
||||
};
|
||||
|
||||
inline STArray::iterator range_begin(STArray& x) { return x.begin(); }
|
||||
|
||||
@@ -72,6 +72,8 @@ public:
|
||||
{ return (getSType() == t.getSType()) && isEquivalent(t); }
|
||||
bool operator!=(const SerializedType& t) const
|
||||
{ return (getSType() != t.getSType()) || !isEquivalent(t); }
|
||||
|
||||
virtual bool isDefault() const { return true; }
|
||||
};
|
||||
|
||||
inline SerializedType* new_clone(const SerializedType& s) { return s.clone().release(); }
|
||||
@@ -103,6 +105,7 @@ public:
|
||||
|
||||
operator unsigned char() const { return value; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value == 0; }
|
||||
};
|
||||
|
||||
class STUInt16 : public SerializedType
|
||||
@@ -130,6 +133,7 @@ public:
|
||||
|
||||
operator uint16() const { return value; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value == 0; }
|
||||
};
|
||||
|
||||
class STUInt32 : public SerializedType
|
||||
@@ -157,6 +161,7 @@ public:
|
||||
|
||||
operator uint32() const { return value; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value == 0; }
|
||||
};
|
||||
|
||||
class STUInt64 : public SerializedType
|
||||
@@ -184,6 +189,7 @@ public:
|
||||
|
||||
operator uint64() const { return value; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value == 0; }
|
||||
};
|
||||
|
||||
class STAmount : public SerializedType
|
||||
@@ -200,12 +206,12 @@ class STAmount : public SerializedType
|
||||
// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
|
||||
|
||||
protected:
|
||||
uint160 mCurrency;
|
||||
uint160 mIssuer; // Only for access, not compared.
|
||||
uint160 mCurrency; // Compared by ==. Always update mIsNative.
|
||||
uint160 mIssuer; // Not compared by ==. 0 for XNS.
|
||||
|
||||
uint64 mValue;
|
||||
int mOffset;
|
||||
bool mIsNative; // True for native stamps, ripple stamps are not native.
|
||||
bool mIsNative; // Always !mCurrency. Native is XNS.
|
||||
bool mIsNegative;
|
||||
|
||||
void canonicalize();
|
||||
@@ -282,12 +288,17 @@ public:
|
||||
bool isGEZero() const { return !mIsNegative; }
|
||||
operator bool() const { return !isZero(); }
|
||||
|
||||
void negate() { if (!isZero()) mIsNegative = !mIsNegative; }
|
||||
void zero() { mOffset = mIsNative ? -100 : 0; mValue = 0; mIsNegative = false; }
|
||||
STAmount* negate() { if (!isZero()) mIsNegative = !mIsNegative; return this; }
|
||||
STAmount* zero() { mOffset = mIsNative ? 0 : -100; mValue = 0; mIsNegative = false; return this; }
|
||||
|
||||
// Zero while copying currency and issuer.
|
||||
STAmount* zero(const STAmount& saTmpl)
|
||||
{ mCurrency = saTmpl.mCurrency; mIssuer = saTmpl.mIssuer; mIsNative = saTmpl.mIsNative; return zero(); }
|
||||
|
||||
int compare(const STAmount&) const;
|
||||
|
||||
const uint160& getIssuer() const { return mIssuer; }
|
||||
void setIssuer(const uint160& uIssuer) { mIssuer = uIssuer; }
|
||||
STAmount* setIssuer(const uint160& uIssuer) { mIssuer = uIssuer; return this; }
|
||||
|
||||
const uint160& getCurrency() const { return mCurrency; }
|
||||
bool setValue(const std::string& sAmount);
|
||||
@@ -295,6 +306,7 @@ public:
|
||||
void setValue(const STAmount &);
|
||||
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return mValue == 0 && mIssuer.isZero() && mCurrency.isZero(); }
|
||||
|
||||
bool operator==(const STAmount&) const;
|
||||
bool operator!=(const STAmount&) const;
|
||||
@@ -398,6 +410,7 @@ public:
|
||||
|
||||
operator uint128() const { return value; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value.isZero(); }
|
||||
};
|
||||
|
||||
class STHash160 : public SerializedType
|
||||
@@ -428,6 +441,7 @@ public:
|
||||
|
||||
operator uint160() const { return value; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value.isZero(); }
|
||||
};
|
||||
|
||||
class STHash256 : public SerializedType
|
||||
@@ -458,6 +472,7 @@ public:
|
||||
|
||||
operator uint256() const { return value; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value.isZero(); }
|
||||
};
|
||||
|
||||
class STVariableLength : public SerializedType
|
||||
@@ -489,6 +504,7 @@ public:
|
||||
|
||||
operator std::vector<unsigned char>() const { return value; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value.empty(); }
|
||||
};
|
||||
|
||||
class STAccount : public STVariableLength
|
||||
@@ -668,6 +684,7 @@ public:
|
||||
void addPath(const STPath& e) { value.push_back(e); }
|
||||
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return value.empty(); }
|
||||
|
||||
void printDebug();
|
||||
|
||||
@@ -735,6 +752,7 @@ public:
|
||||
const std::vector<uint256>& peekValue() const { return mValue; }
|
||||
std::vector<uint256>& peekValue() { return mValue; }
|
||||
virtual bool isEquivalent(const SerializedType& t) const;
|
||||
virtual bool isDefault() const { return mValue.empty(); }
|
||||
|
||||
std::vector<uint256> getValue() const { return mValue; }
|
||||
bool isEmpty() const { return mValue.empty(); }
|
||||
|
||||
@@ -90,16 +90,16 @@ public:
|
||||
{ return getPrefixHash(prefix, reinterpret_cast<const unsigned char *>(strData.c_str()), strData.size()); }
|
||||
|
||||
// totality functions
|
||||
const std::vector<unsigned char>& peekData() const { return mData; }
|
||||
std::vector<unsigned char> getData() const { return mData; }
|
||||
int getCapacity() const { return mData.capacity(); }
|
||||
int getDataLength() const { return mData.size(); }
|
||||
const void* getDataPtr() const { return &mData.front(); }
|
||||
void* getDataPtr() { return &mData.front(); }
|
||||
int getLength() const { return mData.size(); }
|
||||
const std::vector<unsigned char>& peekData() const { return mData; }
|
||||
std::vector<unsigned char> getData() const { return mData; }
|
||||
std::string getString() const { return std::string(static_cast<const char *>(getDataPtr()), size()); }
|
||||
void secureErase() { memset(&(mData.front()), 0, mData.size()); erase(); }
|
||||
void erase() { mData.clear(); }
|
||||
std::string getString() const { return std::string(static_cast<const char *>(getDataPtr()), size()); }
|
||||
void secureErase() { memset(&(mData.front()), 0, mData.size()); erase(); }
|
||||
void erase() { mData.clear(); }
|
||||
int removeLastByte();
|
||||
bool chop(int num);
|
||||
|
||||
@@ -113,10 +113,10 @@ public:
|
||||
void resize(size_t n) { mData.resize(n); }
|
||||
size_t capacity() const { return mData.capacity(); }
|
||||
|
||||
bool operator==(const std::vector<unsigned char>& v) { return v == mData; }
|
||||
bool operator!=(const std::vector<unsigned char>& v) { return v != mData; }
|
||||
bool operator==(const Serializer& v) { return v.mData == mData; }
|
||||
bool operator!=(const Serializer& v) { return v.mData != mData; }
|
||||
bool operator==(const std::vector<unsigned char>& v) { return v == mData; }
|
||||
bool operator!=(const std::vector<unsigned char>& v) { return v != mData; }
|
||||
bool operator==(const Serializer& v) { return v.mData == mData; }
|
||||
bool operator!=(const Serializer& v) { return v.mData != mData; }
|
||||
|
||||
// signature functions
|
||||
bool checkSignature(int pubkeyOffset, int signatureOffset) const;
|
||||
@@ -147,12 +147,12 @@ public:
|
||||
// Reference is not const because we don't want to bind to a temporary
|
||||
SerializerIterator(Serializer& s) : mSerializer(s), mPos(0) { ; }
|
||||
|
||||
void reset(void) { mPos = 0; }
|
||||
void setPos(int p) { mPos = p; }
|
||||
const Serializer& operator*(void) { return mSerializer; }
|
||||
void reset(void) { mPos = 0; }
|
||||
void setPos(int p) { mPos = p; }
|
||||
|
||||
int getPos(void) { return mPos; }
|
||||
bool empty() { return mPos == mSerializer.getLength(); }
|
||||
int getPos(void) { return mPos; }
|
||||
bool empty() { return mPos == mSerializer.getLength(); }
|
||||
int getBytesLeft();
|
||||
|
||||
// get functions throw on error
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
// This class implemented a cache and a map. The cache keeps objects alive
|
||||
|
||||
@@ -101,15 +101,15 @@ void TransactionMetaSet::swap(TransactionMetaSet& s)
|
||||
|
||||
bool TransactionMetaSet::thread(STObject& node, const uint256& prevTxID, uint32 prevLgrID)
|
||||
{
|
||||
if (node.getFieldIndex(sfLastTxnID) == -1)
|
||||
if (node.getFieldIndex(sfPreviousTxnID) == -1)
|
||||
{
|
||||
assert(node.getFieldIndex(sfLastTxnSeq) == -1);
|
||||
node.setFieldH256(sfLastTxnID, prevTxID);
|
||||
node.setFieldU32(sfLastTxnSeq, prevLgrID);
|
||||
assert(node.getFieldIndex(sfPreviousTxnLgrSeq) == -1);
|
||||
node.setFieldH256(sfPreviousTxnID, prevTxID);
|
||||
node.setFieldU32(sfPreviousTxnLgrSeq, prevLgrID);
|
||||
return true;
|
||||
}
|
||||
assert(node.getFieldH256(sfLastTxnID) == prevTxID);
|
||||
assert(node.getFieldU32(sfLastTxnSeq) == prevLgrID);
|
||||
assert(node.getFieldH256(sfPreviousTxnID) == prevTxID);
|
||||
assert(node.getFieldU32(sfPreviousTxnLgrSeq) == prevLgrID);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@ void UniqueNodeList::start()
|
||||
{
|
||||
miscLoad();
|
||||
|
||||
Log(lsDEBUG) << "Validator fetch updated: " << mtpFetchUpdated;
|
||||
Log(lsDEBUG) << "Validator score updated: " << mtpScoreUpdated;
|
||||
cLog(lsDEBUG) << "Validator fetch updated: " << mtpFetchUpdated;
|
||||
cLog(lsDEBUG) << "Validator score updated: " << mtpScoreUpdated;
|
||||
|
||||
fetchNext(); // Start fetching.
|
||||
scoreNext(false); // Start scoring.
|
||||
@@ -139,10 +139,10 @@ bool UniqueNodeList::scoreRound(std::vector<scoreNode>& vsnNodes)
|
||||
|
||||
if (sLog(lsTRACE))
|
||||
{
|
||||
Log(lsTRACE) << "midway: ";
|
||||
cLog(lsTRACE) << "midway: ";
|
||||
BOOST_FOREACH(scoreNode& sn, vsnNodes)
|
||||
{
|
||||
Log(lsTRACE) << str(boost::format("%s| %d, %d, %d: [%s]")
|
||||
cLog(lsTRACE) << str(boost::format("%s| %d, %d, %d: [%s]")
|
||||
% sn.strValidator
|
||||
% sn.iScore
|
||||
% sn.iRoundScore
|
||||
@@ -164,10 +164,10 @@ bool UniqueNodeList::scoreRound(std::vector<scoreNode>& vsnNodes)
|
||||
|
||||
if (sLog(lsTRACE))
|
||||
{
|
||||
Log(lsTRACE) << "finish: ";
|
||||
cLog(lsTRACE) << "finish: ";
|
||||
BOOST_FOREACH(scoreNode& sn, vsnNodes)
|
||||
{
|
||||
Log(lsTRACE) << str(boost::format("%s| %d, %d, %d: [%s]")
|
||||
cLog(lsTRACE) << str(boost::format("%s| %d, %d, %d: [%s]")
|
||||
% sn.strValidator
|
||||
% sn.iScore
|
||||
% sn.iRoundScore
|
||||
@@ -290,7 +290,7 @@ void UniqueNodeList::scoreCompute()
|
||||
{
|
||||
BOOST_FOREACH(scoreNode& sn, vsnNodes)
|
||||
{
|
||||
Log(lsTRACE) << str(boost::format("%s| %d, %d, %d")
|
||||
cLog(lsTRACE) << str(boost::format("%s| %d, %d, %d")
|
||||
% sn.strValidator
|
||||
% sn.iScore
|
||||
% sn.iRoundScore
|
||||
@@ -376,10 +376,10 @@ void UniqueNodeList::scoreCompute()
|
||||
|
||||
if (sLog(lsTRACE))
|
||||
{
|
||||
Log(lsTRACE) << "Scored:";
|
||||
cLog(lsTRACE) << "Scored:";
|
||||
BOOST_FOREACH(scoreNode& sn, vsnNodes)
|
||||
{
|
||||
Log(lsTRACE) << str(boost::format("%s| %d, %d, %d: [%s]")
|
||||
cLog(lsTRACE) << str(boost::format("%s| %d, %d, %d: [%s]")
|
||||
% sn.strValidator
|
||||
% sn.iScore
|
||||
% sn.iRoundScore
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "Log.h"
|
||||
#include "Version.h"
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
using namespace boost;
|
||||
using namespace boost::asio;
|
||||
|
||||
@@ -69,7 +71,7 @@ std::string rfc1123Time()
|
||||
|
||||
std::string HTTPReply(int nStatus, const std::string& strMsg)
|
||||
{
|
||||
Log(lsTRACE) << "HTTP Reply " << nStatus << " " << strMsg;
|
||||
cLog(lsTRACE) << "HTTP Reply " << nStatus << " " << strMsg;
|
||||
|
||||
if (nStatus == 401)
|
||||
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
|
||||
|
||||
@@ -12,7 +12,7 @@ var serverDelay = 1500;
|
||||
|
||||
buster.testRunner.timeout = 3000;
|
||||
|
||||
buster.testCase("// Sending", {
|
||||
buster.testCase("Sending", {
|
||||
'setUp' : testutils.build_setup(),
|
||||
'tearDown' : testutils.build_teardown(),
|
||||
|
||||
@@ -234,7 +234,7 @@ buster.testCase("// Sending", {
|
||||
});
|
||||
|
||||
// XXX In the future add ledger_accept after partial retry is implemented in the server.
|
||||
buster.testCase("// Sending future", {
|
||||
buster.testCase("Sending future", {
|
||||
'setUp' : testutils.build_setup(),
|
||||
'tearDown' : testutils.build_teardown(),
|
||||
|
||||
@@ -242,7 +242,7 @@ buster.testCase("// Sending future", {
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
self.remote.set_trace();
|
||||
// self.remote.set_trace();
|
||||
|
||||
async.waterfall([
|
||||
function (callback) {
|
||||
@@ -279,12 +279,6 @@ buster.testCase("// Sending future", {
|
||||
|
||||
self.remote.request_ripple_balance("alice", "bob", "USD", 'CURRENT')
|
||||
.once('ripple_state', function (m) {
|
||||
console.log("BALANCE: %s", JSON.stringify(m));
|
||||
console.log("account_balance: %s", m.account_balance.to_text_full());
|
||||
console.log("account_limit: %s", m.account_limit.to_text_full());
|
||||
console.log("issuer_balance: %s", m.issuer_balance.to_text_full());
|
||||
console.log("issuer_limit: %s", m.issuer_limit.to_text_full());
|
||||
|
||||
buster.assert(m.account_balance.equals("-24/USD/alice"));
|
||||
buster.assert(m.issuer_balance.equals("24/USD/bob"));
|
||||
|
||||
@@ -401,7 +395,7 @@ buster.testCase("// Sending future", {
|
||||
.payment('bob', 'alice', "1/USD/bob")
|
||||
.once('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
callback(m.result != 'tepPATH_PARTIAL');
|
||||
callback(m.result != 'tepPATH_DRY');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
@@ -454,14 +448,14 @@ buster.testCase("// Sending future", {
|
||||
});
|
||||
|
||||
buster.testCase("Indirect ripple", {
|
||||
'setUp' : testutils.build_setup({ verbose: true, no_server: false }),
|
||||
'tearDown' : testutils.test_teardown,
|
||||
'setUp' : testutils.build_setup({ verbose: false, no_server: false }),
|
||||
'tearDown' : testutils.build_teardown(),
|
||||
|
||||
"indirect ripple" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
self.remote.set_trace();
|
||||
// self.remote.set_trace();
|
||||
|
||||
async.waterfall([
|
||||
function (callback) {
|
||||
@@ -499,13 +493,40 @@ buster.testCase("Indirect ripple", {
|
||||
|
||||
testutils.verify_balance(self.remote, "bob", "50/USD/mtgox", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Alice sends more than has to issuer: 100 out of 70";
|
||||
|
||||
self.remote.transaction()
|
||||
.payment("alice", "mtgox", "100/USD/mtgox")
|
||||
.on('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
|
||||
callback(m.result != 'tepPATH_PARTIAL');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Alice sends more than has to bob: 100 out of 70";
|
||||
|
||||
self.remote.transaction()
|
||||
.payment("alice", "bob", "100/USD/mtgox")
|
||||
.on('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
|
||||
callback(m.result != 'tepPATH_PARTIAL');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
], function (error) {
|
||||
buster.refute(error, self.what);
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
// Direct ripple without no liqudity.
|
||||
// Ripple without credit path.
|
||||
// Ripple with one-way credit path.
|
||||
// Transfer Fees
|
||||
// Use multiple paths.
|
||||
});
|
||||
// vim:sw=2:sts=2:ts=8
|
||||
|
||||
@@ -117,7 +117,7 @@ var credit_limit = function (remote, src, amount, callback) {
|
||||
remote.transaction()
|
||||
.ripple_line_set(src, amount)
|
||||
.on('proposed', function (m) {
|
||||
console.log("proposed: %s", JSON.stringify(m));
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
|
||||
callback(m.result != 'tesSUCCESS');
|
||||
})
|
||||
@@ -153,11 +153,11 @@ var verify_balance = function (remote, src, amount_json, callback) {
|
||||
|
||||
remote.request_ripple_balance(src, amount.issuer.to_json(), amount.currency.to_json(), 'CURRENT')
|
||||
.once('ripple_state', function (m) {
|
||||
console.log("BALANCE: %s", JSON.stringify(m));
|
||||
console.log("account_balance: %s", m.account_balance.to_text_full());
|
||||
console.log("account_limit: %s", m.account_limit.to_text_full());
|
||||
console.log("issuer_balance: %s", m.issuer_balance.to_text_full());
|
||||
console.log("issuer_limit: %s", m.issuer_limit.to_text_full());
|
||||
// console.log("BALANCE: %s", JSON.stringify(m));
|
||||
// console.log("account_balance: %s", m.account_balance.to_text_full());
|
||||
// console.log("account_limit: %s", m.account_limit.to_text_full());
|
||||
// console.log("issuer_balance: %s", m.issuer_balance.to_text_full());
|
||||
// console.log("issuer_limit: %s", m.issuer_limit.to_text_full());
|
||||
|
||||
callback(!m.account_balance.equals(amount));
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user