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

This commit is contained in:
jed
2012-10-30 06:58:57 -07:00
47 changed files with 971 additions and 386 deletions

View File

@@ -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))));

View File

@@ -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'

View File

@@ -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" />

View File

@@ -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;

View File

@@ -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));

View File

@@ -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; }

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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; }

View File

@@ -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
View 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
View 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

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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();

View File

@@ -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;
}
}
}
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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)
{

View File

@@ -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,

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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(); }

View File

@@ -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(); }

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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));
})