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