mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-03 02:08:05 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
263
bin/browser.js
Executable file
263
bin/browser.js
Executable file
@@ -0,0 +1,263 @@
|
||||
#!/usr/bin/node
|
||||
//
|
||||
// ledger_header?l=L
|
||||
// transaction?h=H
|
||||
// ledger_entry?l=L&h=H
|
||||
// account_root?l=L&a=A
|
||||
// directory?l=L&dir_root=H&i=I
|
||||
// directory?l=L&o=A&i=I // owner directory
|
||||
// offer?l=L&offer=H
|
||||
// offer?l=L&account=A&i=I
|
||||
// ripple_state=l=L&a=A&b=A&c=C
|
||||
// account_lines?l=L&a=A
|
||||
//
|
||||
// A=address
|
||||
// C=currency 3 letter code
|
||||
// H=hash
|
||||
// I=index
|
||||
// L=current | closed | validated | index | hash
|
||||
//
|
||||
|
||||
var extend = require("extend");
|
||||
var http = require("http");
|
||||
var url = require("url");
|
||||
|
||||
var Remote = require("../src/js/remote.js").Remote;
|
||||
|
||||
var program = process.argv[1];
|
||||
|
||||
// Build a link to a type.
|
||||
var build_uri = function (params, opts) {
|
||||
var c;
|
||||
|
||||
if (params.type === 'account_root') {
|
||||
c = {
|
||||
pathname: 'account_root',
|
||||
query: {
|
||||
l: params.ledger,
|
||||
a: params.account,
|
||||
},
|
||||
};
|
||||
|
||||
} else if (params.type === 'ledger_header') {
|
||||
c = {
|
||||
pathname: 'ledger_header',
|
||||
query: {
|
||||
l: params.ledger,
|
||||
},
|
||||
};
|
||||
|
||||
} else if (params.type === 'transaction') {
|
||||
c = {
|
||||
pathname: 'transaction',
|
||||
query: {
|
||||
h: params.hash,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
c = {};
|
||||
}
|
||||
|
||||
c.protocol = "http";
|
||||
c.hostname = opts.hostname;
|
||||
c.port = opts.port;
|
||||
|
||||
return url.format(c);
|
||||
};
|
||||
|
||||
var build_link = function (item, link) {
|
||||
console.log(link);
|
||||
return "<A HREF=" + link + ">" + item + "</A>";
|
||||
};
|
||||
|
||||
var rewrite_object = function (obj, opts) {
|
||||
var out = extend({}, obj);
|
||||
|
||||
if ('ledger_index' in obj) {
|
||||
out.ledger_index =
|
||||
build_link(
|
||||
obj.ledger_index,
|
||||
build_uri({
|
||||
type: 'ledger_header',
|
||||
ledger: obj.ledger_index,
|
||||
}, opts)
|
||||
);
|
||||
}
|
||||
|
||||
if ('node' in obj) {
|
||||
if (obj.node.LedgerEntryType === 'AccountRoot') {
|
||||
out.node.PreviousTxnID =
|
||||
build_link(
|
||||
obj.node.PreviousTxnID,
|
||||
build_uri({
|
||||
type: 'transaction',
|
||||
hash: obj.node.PreviousTxnID,
|
||||
}, opts)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
if (process.argv.length < 4 || process.argv.length > 7) {
|
||||
console.log("Usage: %s ws_ip ws_port [<ip> [<port> [<start>]]]", program);
|
||||
}
|
||||
else {
|
||||
var ws_ip = process.argv[2];
|
||||
var ws_port = process.argv[3];
|
||||
var ip = process.argv.length > 4 ? process.argv[4] : "127.0.0.1";
|
||||
var port = process.argv.length > 5 ? process.argv[5] : "8080";
|
||||
|
||||
console.log("START");
|
||||
var self = this;
|
||||
|
||||
self.base = {
|
||||
hostname: ip,
|
||||
port: port,
|
||||
};
|
||||
|
||||
var remote = (new Remote({
|
||||
websocket_ip: ws_ip,
|
||||
websocket_port: ws_port,
|
||||
trace: true
|
||||
}))
|
||||
.on('state', function (m) {
|
||||
console.log("STATE: %s", m);
|
||||
|
||||
self.state = m;
|
||||
})
|
||||
// .once('ledger_closed', callback)
|
||||
.connect()
|
||||
;
|
||||
|
||||
console.log("SERVE");
|
||||
var server = http.createServer(function (req, res) {
|
||||
var input = "";
|
||||
|
||||
req.setEncoding();
|
||||
|
||||
req.on('data', function (buffer) {
|
||||
// console.log("DATA: %s", buffer);
|
||||
input = input + buffer;
|
||||
});
|
||||
|
||||
req.on('end', function () {
|
||||
console.log("URL: %s", req.url);
|
||||
// console.log("HEADERS: %s", JSON.stringify(req.headers, undefined, 2));
|
||||
|
||||
var _parsed = url.parse(req.url, true);
|
||||
var _url = JSON.stringify(_parsed, undefined, 2);
|
||||
|
||||
if (_parsed.pathname === "/account_root") {
|
||||
var request = remote
|
||||
.request_ledger_entry('account_root')
|
||||
.ledger_index(-1)
|
||||
.account_root(_parsed.query.a)
|
||||
.on('success', function (m) {
|
||||
console.log("account_root: %s", JSON.stringify(m, undefined, 2));
|
||||
|
||||
res.statusCode = 200;
|
||||
res.end(
|
||||
"<HTML>"
|
||||
+ "<HEAD><TITLE>Title</TITLE></HEAD>"
|
||||
+ "<BODY BACKGROUND=\"#FFFFFF\">"
|
||||
+ "State: " + self.state
|
||||
+ "<UL>"
|
||||
+ "<LI><A HREF=\"/\">home</A>"
|
||||
+ "<LI><A HREF=\"/account_root\">account_root</A>"
|
||||
+ "</UL>"
|
||||
+ "<PRE>"
|
||||
+ JSON.stringify(rewrite_object(m, self.base), undefined, 2)
|
||||
+ "</PRE>"
|
||||
+ "</BODY>"
|
||||
+ "</HTML>"
|
||||
);
|
||||
})
|
||||
.request();
|
||||
|
||||
} else if (_parsed.pathname === "/ledger_header") {
|
||||
var request = remote
|
||||
.request_ledger_header()
|
||||
.ledger_index(-1)
|
||||
.on('success', function (m) {
|
||||
console.log("Ledger: %s", JSON.stringify(m, undefined, 2));
|
||||
|
||||
res.statusCode = 200;
|
||||
res.end(
|
||||
"<HTML>"
|
||||
+ "<HEAD><TITLE>Title</TITLE></HEAD>"
|
||||
+ "<BODY BACKGROUND=\"#FFFFFF\">"
|
||||
+ "State: " + self.state
|
||||
+ "<UL>"
|
||||
+ "<LI><A HREF=\"/\">home</A>"
|
||||
+ "<LI><A HREF=\"/ledger_header\">ledger_header</A>"
|
||||
+ "</UL>"
|
||||
+ "<PRE>"
|
||||
+ JSON.stringify(m, undefined, 2)
|
||||
+ "</PRE>"
|
||||
+ "</BODY>"
|
||||
+ "</HTML>"
|
||||
);
|
||||
})
|
||||
.request();
|
||||
|
||||
} else if (_parsed.pathname === "/transaction") {
|
||||
var request = remote
|
||||
.request_transaction_entry(_parsed.query.h)
|
||||
// .ledger_select(_parsed.query.l)
|
||||
.on('success', function (m) {
|
||||
console.log("transaction: %s", JSON.stringify(m, undefined, 2));
|
||||
|
||||
res.statusCode = 200;
|
||||
res.end(
|
||||
"<HTML>"
|
||||
+ "<HEAD><TITLE>Title</TITLE></HEAD>"
|
||||
+ "<BODY BACKGROUND=\"#FFFFFF\">"
|
||||
+ "State: " + self.state
|
||||
+ "<UL>"
|
||||
+ "<LI><A HREF=\"/\">home</A>"
|
||||
+ "<LI><A HREF=\"/account_root\">account_root</A>"
|
||||
+ "</UL>"
|
||||
+ "<PRE>"
|
||||
+ JSON.stringify(rewrite_object(m, self.base), undefined, 2)
|
||||
+ "</PRE>"
|
||||
+ "</BODY>"
|
||||
+ "</HTML>"
|
||||
);
|
||||
})
|
||||
.request();
|
||||
|
||||
} else {
|
||||
var test = build_uri({
|
||||
type: 'account_root',
|
||||
ledger: 'closed',
|
||||
account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
}, self.base);
|
||||
|
||||
res.statusCode = req.url === "/" ? 200 : 404;
|
||||
res.end(
|
||||
"<HTML>"
|
||||
+ "<HEAD><TITLE>Title</TITLE></HEAD>"
|
||||
+ "<BODY BACKGROUND=\"#FFFFFF\">"
|
||||
+ "State: " + self.state
|
||||
+ "<UL>"
|
||||
+ "<LI><A HREF=\"/\">home</A>"
|
||||
+ "<LI><A HREF=\""+test+"\">rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh</A>"
|
||||
+ "<LI><A HREF=\"/ledger_header\">ledger_header</A>"
|
||||
+ "</UL>"
|
||||
+ "<PRE>"+_url+"</PRE>"
|
||||
+ "</BODY>"
|
||||
+ "</HTML>"
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(port, ip, undefined,
|
||||
function () {
|
||||
console.log("Listening at: http://%s:%s", ip, port);
|
||||
});
|
||||
}
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
@@ -96,6 +96,7 @@
|
||||
<ClCompile Include="src\cpp\json\json_reader.cpp" />
|
||||
<ClCompile Include="src\cpp\json\json_value.cpp" />
|
||||
<ClCompile Include="src\cpp\json\json_writer.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AcceptedLedger.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AccountItems.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AccountSetTransactor.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AccountState.cpp" />
|
||||
@@ -205,6 +206,7 @@
|
||||
<ClInclude Include="database\sqlite3.h" />
|
||||
<ClInclude Include="database\sqlite3ext.h" />
|
||||
<ClInclude Include="database\SqliteDatabase.h" />
|
||||
<ClInclude Include="src\cpp\ripple\AcceptedLedger.h" />
|
||||
<ClInclude Include="src\cpp\ripple\AccountItems.h" />
|
||||
<ClInclude Include="src\cpp\ripple\AccountSetTransactor.h" />
|
||||
<ClInclude Include="src\cpp\ripple\AccountState.h" />
|
||||
|
||||
@@ -345,6 +345,9 @@
|
||||
<ClCompile Include="src\cpp\ripple\Offer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\cpp\ripple\AcceptedLedger.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\cpp\ripple\AccountItems.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -662,6 +665,9 @@
|
||||
<ClInclude Include="src\cpp\ripple\Offer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\cpp\ripple\AcceptedLedger.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\cpp\ripple\AccountItems.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.1",
|
||||
"description": "Ripple JavaScript client library",
|
||||
|
||||
"files": [
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
<ClCompile Include="src\cpp\json\json_reader.cpp" />
|
||||
<ClCompile Include="src\cpp\json\json_value.cpp" />
|
||||
<ClCompile Include="src\cpp\json\json_writer.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AcceptedLedger.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AccountItems.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AccountSetTransactor.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AccountState.cpp" />
|
||||
|
||||
@@ -345,6 +345,9 @@
|
||||
<ClCompile Include="src\cpp\ripple\LoadManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\cpp\ripple\AcceptedLedger.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\cpp\ripple\AccountItems.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -223,7 +223,7 @@ void SqliteDatabase::doHook(const char *db, int pages)
|
||||
{
|
||||
walRunning = true;
|
||||
if (mWalQ)
|
||||
mWalQ->addJob(jtWAL, boost::bind(&SqliteDatabase::runWal, this));
|
||||
mWalQ->addJob(jtWAL, std::string("WAL:") + db, boost::bind(&SqliteDatabase::runWal, this));
|
||||
else
|
||||
boost::thread(boost::bind(&SqliteDatabase::runWal, this)).detach();
|
||||
}
|
||||
|
||||
91
src/cpp/ripple/AcceptedLedger.cpp
Normal file
91
src/cpp/ripple/AcceptedLedger.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "AcceptedLedger.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
TaggedCache<uint256, AcceptedLedger> AcceptedLedger::ALCache("AcceptedLedger", 4, 60);
|
||||
|
||||
ALTransaction::ALTransaction(uint32 seq, SerializerIterator& sit)
|
||||
{
|
||||
Serializer txnSer(sit.getVL());
|
||||
SerializerIterator txnIt(txnSer);
|
||||
|
||||
mTxn = boost::make_shared<SerializedTransaction>(boost::ref(txnIt));
|
||||
mRawMeta= sit.getVL();
|
||||
mMeta = boost::make_shared<TransactionMetaSet>(mTxn->getTransactionID(), seq, mRawMeta);
|
||||
mAffected = mMeta->getAffectedAccounts();
|
||||
mResult = mMeta->getResultTER();
|
||||
}
|
||||
|
||||
ALTransaction::ALTransaction(SerializedTransaction::ref txn, TransactionMetaSet::ref met) :
|
||||
mTxn(txn), mMeta(met), mAffected(met->getAffectedAccounts())
|
||||
{
|
||||
mResult = mMeta->getResultTER();
|
||||
}
|
||||
|
||||
ALTransaction::ALTransaction(SerializedTransaction::ref txn, TER result) :
|
||||
mTxn(txn), mResult(result), mAffected(txn->getMentionedAccounts())
|
||||
{ ; }
|
||||
|
||||
std::string ALTransaction::getEscMeta() const
|
||||
{
|
||||
assert(!mRawMeta.empty());
|
||||
return sqlEscape(mRawMeta);
|
||||
}
|
||||
|
||||
Json::Value ALTransaction::getJson(int j) const
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
ret["transaction"] = mTxn->getJson(j);
|
||||
if (mMeta)
|
||||
{
|
||||
ret["meta"] = mMeta->getJson(j);
|
||||
ret["raw_meta"] = strHex(mRawMeta);
|
||||
}
|
||||
ret["result"] = transHuman(mResult);
|
||||
|
||||
if (!mAffected.empty())
|
||||
{
|
||||
Json::Value affected(Json::arrayValue);
|
||||
BOOST_FOREACH(const RippleAddress& ra, mAffected)
|
||||
{
|
||||
affected.append(ra.humanAccountID());
|
||||
}
|
||||
ret["affected"] = affected;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
AcceptedLedger::AcceptedLedger(Ledger::ref ledger) : mLedger(ledger)
|
||||
{
|
||||
SHAMap& txSet = *ledger->peekTransactionMap();
|
||||
for (SHAMapItem::pointer item = txSet.peekFirstItem(); !!item; item = txSet.peekNextItem(item->getTag()))
|
||||
{
|
||||
SerializerIterator sit(item->peekSerializer());
|
||||
insert(ALTransaction(ledger->getLedgerSeq(), sit));
|
||||
}
|
||||
}
|
||||
|
||||
AcceptedLedger::pointer AcceptedLedger::makeAcceptedLedger(Ledger::ref ledger)
|
||||
{
|
||||
AcceptedLedger::pointer ret = ALCache.fetch(ledger->getHash());
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = AcceptedLedger::pointer(new AcceptedLedger(ledger));
|
||||
ALCache.canonicalize(ledger->getHash(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AcceptedLedger::insert(const ALTransaction& at)
|
||||
{
|
||||
assert(mMap.find(at.getIndex()) == mMap.end());
|
||||
mMap.insert(std::make_pair(at.getIndex(), at));
|
||||
}
|
||||
|
||||
const ALTransaction* AcceptedLedger::getTxn(int i) const
|
||||
{
|
||||
map_t::const_iterator it = mMap.find(i);
|
||||
if (it == mMap.end())
|
||||
return NULL;
|
||||
return &it->second;
|
||||
}
|
||||
70
src/cpp/ripple/AcceptedLedger.h
Normal file
70
src/cpp/ripple/AcceptedLedger.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef ACCEPTED_LEDGER__H
|
||||
#define ACCEPTED_LEDGER__H
|
||||
|
||||
#include "SerializedTransaction.h"
|
||||
#include "TransactionMeta.h"
|
||||
#include "Ledger.h"
|
||||
|
||||
|
||||
class ALTransaction
|
||||
{
|
||||
protected:
|
||||
SerializedTransaction::pointer mTxn;
|
||||
TransactionMetaSet::pointer mMeta;
|
||||
TER mResult;
|
||||
std::vector<RippleAddress> mAffected;
|
||||
std::vector<unsigned char> mRawMeta;
|
||||
|
||||
public:
|
||||
|
||||
ALTransaction(uint32 ledgerSeq, SerializerIterator& sit);
|
||||
ALTransaction(SerializedTransaction::ref, TransactionMetaSet::ref);
|
||||
ALTransaction(SerializedTransaction::ref, TER result);
|
||||
|
||||
SerializedTransaction::ref getTxn() const { return mTxn; }
|
||||
TransactionMetaSet::ref getMeta() const { return mMeta; }
|
||||
const std::vector<RippleAddress>& getAffected() const { return mAffected; }
|
||||
|
||||
uint256 getTransactionID() const { return mTxn->getTransactionID(); }
|
||||
TransactionType getTxnType() const { return mTxn->getTxnType(); }
|
||||
TER getResult() const { return mResult; }
|
||||
|
||||
bool isApplied() const { return !!mMeta; }
|
||||
int getIndex() const { return mMeta ? mMeta->getIndex() : 0; }
|
||||
std::string getEscMeta() const;
|
||||
Json::Value getJson(int) const;
|
||||
};
|
||||
|
||||
class AcceptedLedger
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<AcceptedLedger> pointer;
|
||||
typedef const pointer& ret;
|
||||
typedef std::map<int, ALTransaction> map_t;
|
||||
typedef map_t::value_type value_type;
|
||||
typedef map_t::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
Ledger::pointer mLedger;
|
||||
map_t mMap;
|
||||
|
||||
void insert(const ALTransaction&);
|
||||
|
||||
static TaggedCache<uint256, AcceptedLedger> ALCache;
|
||||
AcceptedLedger(Ledger::ref ledger);
|
||||
|
||||
public:
|
||||
|
||||
static pointer makeAcceptedLedger(Ledger::ref ledger);
|
||||
static void sweep() { ALCache.sweep(); }
|
||||
|
||||
Ledger::ref getLedger() const { return mLedger; }
|
||||
const map_t& getMap() const { return mMap; }
|
||||
|
||||
int getLedgerSeq() const { return mLedger->getLedgerSeq(); }
|
||||
int getTxnCount() const { return mMap.size(); }
|
||||
|
||||
const ALTransaction* getTxn(int) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
#include "Application.h"
|
||||
#include "AcceptedLedger.h"
|
||||
#include "Config.h"
|
||||
#include "PeerDoor.h"
|
||||
#include "RPCDoor.h"
|
||||
@@ -45,7 +46,7 @@ Application::Application() :
|
||||
mSNTPClient(mAuxService), mRPCHandler(&mNetOps), mFeeTrack(),
|
||||
mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL),
|
||||
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mWSPublicDoor(NULL), mWSPrivateDoor(NULL),
|
||||
mSweepTimer(mAuxService)
|
||||
mSweepTimer(mAuxService), mShutdown(false)
|
||||
{
|
||||
getRand(mNonce256.begin(), mNonce256.size());
|
||||
getRand(reinterpret_cast<unsigned char *>(&mNonceST), sizeof(mNonceST));
|
||||
@@ -58,6 +59,7 @@ bool Instance::running = true;
|
||||
void Application::stop()
|
||||
{
|
||||
cLog(lsINFO) << "Received shutdown request";
|
||||
mShutdown = true;
|
||||
mIOService.stop();
|
||||
mHashedObjectStore.bulkWrite();
|
||||
mValidations.flush();
|
||||
@@ -302,6 +304,7 @@ void Application::sweep()
|
||||
mValidations.sweep();
|
||||
getMasterLedgerAcquire().sweep();
|
||||
mSLECache.sweep();
|
||||
AcceptedLedger::sweep();
|
||||
mSweepTimer.expires_from_now(boost::posix_time::seconds(theConfig.getSize(siSweepInterval)));
|
||||
mSweepTimer.async_wait(boost::bind(&Application::sweep, this));
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ class Application
|
||||
std::map<std::string, Peer::pointer> mPeerMap;
|
||||
boost::recursive_mutex mPeerMapLock;
|
||||
|
||||
volatile bool mShutdown;
|
||||
|
||||
void startNewLedger();
|
||||
void loadOldLedger(const std::string&);
|
||||
|
||||
@@ -140,6 +142,7 @@ public:
|
||||
uint256 getNonce256() { return mNonce256; }
|
||||
std::size_t getNonceST() { return mNonceST; }
|
||||
|
||||
bool isShutdown() { return mShutdown; }
|
||||
void setup();
|
||||
void run();
|
||||
void stop();
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
//
|
||||
// This a trusted interface, the user is expected to provide valid input to perform valid requests.
|
||||
// Error catching and reporting is not a requirement of this command line interface.
|
||||
//
|
||||
// Improvements to be more strict and to provide better diagnostics are welcome.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
@@ -9,6 +15,7 @@
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/evp.h>
|
||||
@@ -55,6 +62,63 @@ std::string EncodeBase64(const std::string& s)
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO New routine for parsing ledger parameters, other routines should standardize on this.
|
||||
static bool jvParseLedger(Json::Value& jvRequest, const std::string& strLedger)
|
||||
{
|
||||
if (strLedger == "closed")
|
||||
{
|
||||
jvRequest["ledger_index"] = -1;
|
||||
}
|
||||
else if (strLedger == "current")
|
||||
{
|
||||
jvRequest["ledger_index"] = -2;
|
||||
}
|
||||
else if (strLedger == "validated")
|
||||
{
|
||||
jvRequest["ledger_index"] = -3;
|
||||
}
|
||||
else if (strLedger.length() > 12)
|
||||
{
|
||||
// YYY Could confirm this is a uint256.
|
||||
jvRequest["ledger_hash"] = strLedger;
|
||||
}
|
||||
else
|
||||
{
|
||||
jvRequest["ledger_index"] = lexical_cast_s<uint32>(strLedger);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build a object { "currency" : "XYZ", "issuer" : "rXYX" }
|
||||
static Json::Value jvParseCurrencyIssuer(const std::string& strCurrencyIssuer)
|
||||
{
|
||||
static boost::regex reCurIss("\\`([[:alpha:]]{3})(?:/(.+))?\\'");
|
||||
|
||||
boost::smatch smMatch;
|
||||
|
||||
if (boost::regex_match(strCurrencyIssuer, smMatch, reCurIss))
|
||||
{
|
||||
Json::Value jvResult(Json::objectValue);
|
||||
std::string strCurrency = smMatch[1];
|
||||
std::string strIssuer = smMatch[2];
|
||||
|
||||
jvResult["currency"] = strCurrency;
|
||||
|
||||
if (strIssuer.length())
|
||||
{
|
||||
// Could confirm issuer is a valid Ripple address.
|
||||
jvResult["issuer"] = strIssuer;
|
||||
}
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value RPCParser::parseAsIs(const Json::Value& jvParams)
|
||||
{
|
||||
Json::Value v(Json::objectValue);
|
||||
@@ -145,6 +209,63 @@ Json::Value RPCParser::parseAccountTransactions(const Json::Value& jvParams)
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
// book_offers <taker_pays> <taker_gets> [<taker> [<ledger> [<limit> [<proof> [<marker>]]]]]
|
||||
// limit: 0 = no limit
|
||||
// proof: 0 or 1
|
||||
//
|
||||
// Mnemonic: taker pays --> offer --> taker gets
|
||||
Json::Value RPCParser::parseBookOffers(const Json::Value& jvParams)
|
||||
{
|
||||
Json::Value jvRequest(Json::objectValue);
|
||||
|
||||
Json::Value jvTakerPays = jvParseCurrencyIssuer(jvParams[0u].asString());
|
||||
Json::Value jvTakerGets = jvParseCurrencyIssuer(jvParams[1u].asString());
|
||||
|
||||
if (isRpcError(jvTakerPays))
|
||||
{
|
||||
return jvTakerPays;
|
||||
}
|
||||
else
|
||||
{
|
||||
jvRequest["taker_pays"] = jvTakerPays;
|
||||
}
|
||||
|
||||
if (isRpcError(jvTakerGets))
|
||||
{
|
||||
return jvTakerGets;
|
||||
}
|
||||
else
|
||||
{
|
||||
jvRequest["taker_gets"] = jvTakerGets;
|
||||
}
|
||||
|
||||
if (jvParams.size() >= 3)
|
||||
{
|
||||
jvRequest["issuer"] = jvParams[2u].asString();
|
||||
}
|
||||
|
||||
if (jvParams.size() >= 4 && !jvParseLedger(jvRequest, jvParams[3u].asString()))
|
||||
return jvRequest;
|
||||
|
||||
if (jvParams.size() >= 5)
|
||||
{
|
||||
int iLimit = jvParams[5u].asInt();
|
||||
|
||||
if (iLimit > 0)
|
||||
jvRequest["limit"] = iLimit;
|
||||
}
|
||||
|
||||
if (jvParams.size() >= 6 && jvParams[5u].asInt())
|
||||
{
|
||||
jvRequest["proof"] = true;
|
||||
}
|
||||
|
||||
if (jvParams.size() == 7)
|
||||
jvRequest["marker"] = jvParams[6u];
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
// connect <ip> [port]
|
||||
Json::Value RPCParser::parseConnect(const Json::Value& jvParams)
|
||||
{
|
||||
@@ -509,11 +630,11 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
|
||||
// Request-response methods
|
||||
// - Returns an error, or the request.
|
||||
// - To modify the method, provide a new method in the request.
|
||||
{ "accept_ledger", &RPCParser::parseAsIs, 0, 0 },
|
||||
{ "account_info", &RPCParser::parseAccountInfo, 1, 2 },
|
||||
{ "account_lines", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_offers", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_tx", &RPCParser::parseAccountTransactions, 2, 4 },
|
||||
{ "book_offers", &RPCParser::parseBookOffers, 2, 7 },
|
||||
{ "connect", &RPCParser::parseConnect, 1, 2 },
|
||||
{ "consensus_info", &RPCParser::parseAsIs, 0, 0 },
|
||||
{ "get_counts", &RPCParser::parseGetCounts, 0, 1 },
|
||||
@@ -622,7 +743,7 @@ int commandLineRPC(const std::vector<std::string>& vCmd)
|
||||
|
||||
jvRequest = rpParser.parseCommand(vCmd[0], jvRpcParams);
|
||||
|
||||
// std::cerr << "Request: " << jvRequest << std::endl;
|
||||
cLog(lsTRACE) << "RPC Request: " << jvRequest << std::endl;
|
||||
|
||||
if (jvRequest.isMember("error"))
|
||||
{
|
||||
@@ -756,6 +877,8 @@ bool responseRPC(
|
||||
// Build the request.
|
||||
void requestRPC(const std::string& strMethod, const Json::Value& jvParams, const std::map<std::string, std::string>& mHeaders, const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost)
|
||||
{
|
||||
cLog(lsDEBUG) << "requestRPC: strPath='" << strPath << "'";
|
||||
|
||||
std::ostream osRequest(&sb);
|
||||
|
||||
osRequest <<
|
||||
@@ -804,7 +927,7 @@ void callRPC(
|
||||
strMethod,
|
||||
jvParams,
|
||||
mapRequestHeaders,
|
||||
"/", _1, _2),
|
||||
strPath, _1, _2),
|
||||
RPC_REPLY_MAX_BYTES,
|
||||
boost::posix_time::seconds(RPC_NOTIFY_SECONDS),
|
||||
boost::bind(&responseRPC, callbackFuncP, _1, _2, _3));
|
||||
|
||||
@@ -14,6 +14,7 @@ protected:
|
||||
Json::Value parseAccountItems(const Json::Value& jvParams);
|
||||
Json::Value parseAccountTransactions(const Json::Value& jvParams);
|
||||
Json::Value parseAsIs(const Json::Value& jvParams);
|
||||
Json::Value parseBookOffers(const Json::Value& jvParams);
|
||||
Json::Value parseConnect(const Json::Value& jvParams);
|
||||
#if ENABLE_INSECURE
|
||||
Json::Value parseDataDelete(const Json::Value& jvParams);
|
||||
|
||||
@@ -235,14 +235,10 @@ void ConnectionPool::policyHandler(const boost::system::error_code& ecResult)
|
||||
int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg)
|
||||
{
|
||||
int sentTo = 0;
|
||||
boost::recursive_mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
BOOST_FOREACH(const vtConMap& pair, mConnectedMap)
|
||||
std::vector<Peer::pointer> peerVector = getPeerVector();
|
||||
BOOST_FOREACH(Peer::ref peer, peerVector)
|
||||
{
|
||||
Peer::ref peer = pair.second;
|
||||
if (!peer)
|
||||
std::cerr << "CP::RM null peer in list" << std::endl;
|
||||
else if ((!fromPeer || !(peer.get() == fromPeer)) && peer->isConnected())
|
||||
if ((!fromPeer || !(peer.get() == fromPeer)) && peer->isConnected())
|
||||
{
|
||||
++sentTo;
|
||||
peer->sendPacket(msg);
|
||||
@@ -254,11 +250,9 @@ int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& m
|
||||
|
||||
void ConnectionPool::relayMessageBut(const std::set<uint64>& fromPeers, const PackedMessage::pointer& msg)
|
||||
{ // Relay message to all but the specified peers
|
||||
boost::recursive_mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
BOOST_FOREACH(const vtConMap& pair, mConnectedMap)
|
||||
std::vector<Peer::pointer> peerVector = getPeerVector();
|
||||
BOOST_FOREACH(Peer::ref peer, peerVector)
|
||||
{
|
||||
Peer::ref peer = pair.second;
|
||||
if (peer->isConnected() && (fromPeers.count(peer->getPeerId()) == 0))
|
||||
peer->sendPacket(msg);
|
||||
}
|
||||
@@ -267,13 +261,11 @@ void ConnectionPool::relayMessageBut(const std::set<uint64>& fromPeers, const Pa
|
||||
|
||||
void ConnectionPool::relayMessageTo(const std::set<uint64>& fromPeers, const PackedMessage::pointer& msg)
|
||||
{ // Relay message to the specified peers
|
||||
boost::recursive_mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
BOOST_FOREACH(const uint64& peerID, fromPeers)
|
||||
std::vector<Peer::pointer> peerVector = getPeerVector();
|
||||
BOOST_FOREACH(Peer::ref peer, peerVector)
|
||||
{
|
||||
const boost::unordered_map<uint64, Peer::pointer>::iterator& it = mPeerIdMap.find(peerID);
|
||||
if ((it != mPeerIdMap.end()) && it->second->isConnected())
|
||||
it->second->sendPacket(msg);
|
||||
if (peer->isConnected() && (fromPeers.count(peer->getPeerId()) != 0))
|
||||
peer->sendPacket(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const char *TxnDBInit[] = {
|
||||
TxnMeta BLOB \
|
||||
);",
|
||||
"CREATE TABLE AccountTransactions ( \
|
||||
TransID CHARACTER(64), \
|
||||
TransID CHARACTER(64) PRIMARY KEY, \
|
||||
Account CHARACTER(64), \
|
||||
LedgerSeq BIGINT UNSIGNED \
|
||||
);",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// These must stay at the top of this file
|
||||
std::map<int, SField::ptr> SField::codeToField;
|
||||
boost::mutex SField::mapMutex;
|
||||
int SField::num = 0;
|
||||
|
||||
SField sfInvalid(-1), sfGeneric(0);
|
||||
SField sfLedgerEntry(STI_LEDGERENTRY, 1, "LedgerEntry");
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
protected:
|
||||
static std::map<int, ptr> codeToField;
|
||||
static boost::mutex mapMutex;
|
||||
static int num;
|
||||
|
||||
SField(SerializedTypeID id, int val);
|
||||
|
||||
@@ -61,6 +62,7 @@ public:
|
||||
const int fieldValue; // Code number for protocol
|
||||
std::string fieldName;
|
||||
int fieldMeta;
|
||||
int fieldNum;
|
||||
bool signingField;
|
||||
|
||||
SField(int fc, SerializedTypeID tid, int fv, const char* fn) :
|
||||
@@ -68,6 +70,7 @@ public:
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mapMutex);
|
||||
codeToField[fieldCode] = this;
|
||||
fieldNum = ++num;
|
||||
}
|
||||
|
||||
SField(SerializedTypeID tid, int fv, const char *fn) :
|
||||
@@ -76,9 +79,14 @@ public:
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mapMutex);
|
||||
codeToField[fieldCode] = this;
|
||||
fieldNum = ++num;
|
||||
}
|
||||
|
||||
SField(int fc) : fieldCode(fc), fieldType(STI_UNKNOWN), fieldValue(0), fieldMeta(sMD_Never) { ; }
|
||||
SField(int fc) : fieldCode(fc), fieldType(STI_UNKNOWN), fieldValue(0), fieldMeta(sMD_Never)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mapMutex);
|
||||
fieldNum = ++num;
|
||||
}
|
||||
|
||||
~SField();
|
||||
|
||||
@@ -96,6 +104,9 @@ public:
|
||||
bool isKnown() const { return fieldType != STI_UNKNOWN; }
|
||||
bool isBinary() const { return fieldValue < 256; }
|
||||
bool isDiscardable() const { return fieldValue > 256; }
|
||||
int getCode() const { return fieldCode; }
|
||||
int getNum() const { return fieldNum; }
|
||||
static int getNumFields() { return num; }
|
||||
|
||||
bool isSigningField() const { return signingField; }
|
||||
void notSigningField() { signingField = false; }
|
||||
|
||||
@@ -51,7 +51,8 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index,
|
||||
if (!mWritePending)
|
||||
{
|
||||
mWritePending = true;
|
||||
theApp->getJobQueue().addJob(jtWRITE, boost::bind(&HashedObjectStore::bulkWrite, this));
|
||||
theApp->getJobQueue().addJob(jtWRITE, "HashedObject::store",
|
||||
boost::bind(&HashedObjectStore::bulkWrite, this));
|
||||
}
|
||||
}
|
||||
// else
|
||||
@@ -113,7 +114,6 @@ void HashedObjectStore::bulkWrite()
|
||||
default: type = "U";
|
||||
}
|
||||
|
||||
pSt.reset();
|
||||
pSt.bind(1, it->getHash().GetHex());
|
||||
pSt.bind(2, type);
|
||||
pSt.bind(3, it->getIndex());
|
||||
@@ -124,6 +124,7 @@ void HashedObjectStore::bulkWrite()
|
||||
cLog(lsFATAL) << "Error saving hashed object " << ret;
|
||||
assert(false);
|
||||
}
|
||||
pSt.reset();
|
||||
}
|
||||
|
||||
db->executeSQL("END TRANSACTION;");
|
||||
@@ -186,12 +187,12 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
|
||||
static SqliteStatement pSt(theApp->getHashNodeDB()->getDB()->getSqliteDB(),
|
||||
"SELECT ObjType,LedgerIndex,Object FROM CommittedObjects WHERE Hash = ?;");
|
||||
|
||||
pSt.reset();
|
||||
pSt.bind(1, hash.GetHex());
|
||||
|
||||
int ret = pSt.step();
|
||||
if (pSt.isDone(ret))
|
||||
{
|
||||
pSt.reset();
|
||||
mNegativeCache.add(hash);
|
||||
cLog(lsTRACE) << "HOS: " << hash <<" fetch: not in db";
|
||||
return obj;
|
||||
@@ -200,6 +201,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
|
||||
type = pSt.peekString(0);
|
||||
index = pSt.getUInt32(1);
|
||||
pSt.getBlob(2).swap(data);
|
||||
pSt.reset();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -370,10 +370,14 @@ void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, int
|
||||
|
||||
if (ecCancel)
|
||||
{
|
||||
cLog(lsTRACE) << "Deadline cancel error: " << ecCancel.message();
|
||||
cLog(lsTRACE) << "HttpsClient::invokeComplete: Deadline cancel error: " << ecCancel.message();
|
||||
}
|
||||
|
||||
mDeqSites.pop_front();
|
||||
cLog(lsDEBUG) << "HttpsClient::invokeComplete: Deadline popping: " << mDeqSites.size();
|
||||
if (!mDeqSites.empty())
|
||||
{
|
||||
mDeqSites.pop_front();
|
||||
}
|
||||
|
||||
bool bAgain = true;
|
||||
|
||||
|
||||
@@ -50,6 +50,11 @@ public:
|
||||
sMultiThreaded = true;
|
||||
}
|
||||
|
||||
static bool isMultiThread()
|
||||
{
|
||||
return sMultiThreaded;
|
||||
}
|
||||
|
||||
void addInstance()
|
||||
{
|
||||
if (sMultiThreaded)
|
||||
|
||||
@@ -98,7 +98,7 @@ bool Job::operator<=(const Job& j) const
|
||||
return mJobIndex <= j.mJobIndex;
|
||||
}
|
||||
|
||||
void JobQueue::addJob(JobType type, const boost::function<void(Job&)>& jobFunc)
|
||||
void JobQueue::addJob(JobType type, const std::string& name, const boost::function<void(Job&)>& jobFunc)
|
||||
{
|
||||
assert(type != jtINVALID);
|
||||
|
||||
@@ -107,7 +107,7 @@ void JobQueue::addJob(JobType type, const boost::function<void(Job&)>& jobFunc)
|
||||
if (type != jtCLIENT) // FIXME: Workaround incorrect client shutdown ordering
|
||||
assert(mThreadCount != 0); // do not add jobs to a queue with no threads
|
||||
|
||||
mJobSet.insert(Job(type, ++mLastJob, mJobLoads[type], jobFunc));
|
||||
mJobSet.insert(Job(type, name, ++mLastJob, mJobLoads[type], jobFunc));
|
||||
++mJobCounts[type];
|
||||
mJobCond.notify_one();
|
||||
}
|
||||
@@ -176,9 +176,9 @@ Json::Value JobQueue::getJson(int)
|
||||
if (count != 0)
|
||||
pri["per_second"] = static_cast<int>(count);
|
||||
if (latencyPeak != 0)
|
||||
pri["peak_latency"] = static_cast<int>(latencyPeak);
|
||||
pri["peak_time"] = static_cast<int>(latencyPeak);
|
||||
if (latencyAvg != 0)
|
||||
pri["avg_latency"] = static_cast<int>(latencyAvg);
|
||||
pri["avg_time"] = static_cast<int>(latencyAvg);
|
||||
priorities.append(pri);
|
||||
}
|
||||
}
|
||||
@@ -256,16 +256,18 @@ void JobQueue::threadEntry()
|
||||
break;
|
||||
|
||||
std::set<Job>::iterator it = mJobSet.begin();
|
||||
Job job(*it);
|
||||
mJobSet.erase(it);
|
||||
--mJobCounts[job.getType()];
|
||||
{
|
||||
Job job(*it);
|
||||
mJobSet.erase(it);
|
||||
--mJobCounts[job.getType()];
|
||||
|
||||
if (job.getType() == jtDEATH)
|
||||
break;
|
||||
if (job.getType() == jtDEATH)
|
||||
break;
|
||||
|
||||
sl.unlock();
|
||||
cLog(lsTRACE) << "Doing " << Job::toString(job.getType()) << " job";
|
||||
job.doJob();
|
||||
sl.unlock();
|
||||
cLog(lsTRACE) << "Doing " << Job::toString(job.getType()) << " job";
|
||||
job.doJob();
|
||||
} // must destroy job without holding lock
|
||||
sl.lock();
|
||||
}
|
||||
--mThreadCount;
|
||||
|
||||
@@ -54,6 +54,7 @@ protected:
|
||||
uint64 mJobIndex;
|
||||
boost::function<void(Job&)> mJob;
|
||||
LoadEvent::pointer mLoadMonitor;
|
||||
std::string mName;
|
||||
|
||||
public:
|
||||
|
||||
@@ -62,12 +63,15 @@ public:
|
||||
Job(JobType type, uint64 index) : mType(type), mJobIndex(index)
|
||||
{ ; }
|
||||
|
||||
Job(JobType type, uint64 index, LoadMonitor& lm, const boost::function<void(Job&)>& job)
|
||||
: mType(type), mJobIndex(index), mJob(job)
|
||||
{ mLoadMonitor = boost::make_shared<LoadEvent>(boost::ref(lm), true, 1); }
|
||||
Job(JobType type, const std::string& name, uint64 index, LoadMonitor& lm, const boost::function<void(Job&)>& job)
|
||||
: mType(type), mJobIndex(index), mJob(job), mName(name)
|
||||
{
|
||||
mLoadMonitor = boost::make_shared<LoadEvent>(boost::ref(lm), false, 1);
|
||||
}
|
||||
|
||||
JobType getType() const { return mType; }
|
||||
void doJob(void) { mJob(*this); }
|
||||
void doJob(void) { mLoadMonitor->start(); mJob(*this); mLoadMonitor->setName(mName); }
|
||||
void rename(const std::string& n) { mName = n; }
|
||||
|
||||
bool operator<(const Job& j) const;
|
||||
bool operator>(const Job& j) const;
|
||||
@@ -97,7 +101,7 @@ public:
|
||||
|
||||
JobQueue();
|
||||
|
||||
void addJob(JobType type, const boost::function<void(Job&)>& job);
|
||||
void addJob(JobType type, const std::string& name, const boost::function<void(Job&)>& job);
|
||||
|
||||
int getJobCount(JobType t); // Jobs at this priority
|
||||
int getJobCountGE(JobType t); // All jobs at or greater than this priority
|
||||
|
||||
@@ -403,9 +403,9 @@ uint256 Ledger::getHash()
|
||||
void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event)
|
||||
{ // can be called in a different thread
|
||||
cLog(lsTRACE) << "saveAcceptedLedger " << (fromConsensus ? "fromConsensus " : "fromAcquire ") << getLedgerSeq();
|
||||
static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers where LedgerSeq = %d;");
|
||||
static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers INDEXED BY SeqLedger where LedgerSeq = %d;");
|
||||
static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;");
|
||||
static boost::format AcctTransExists("SELECT LedgerSeq FROM AccountTransactions WHERE TransId = '%s';");
|
||||
static boost::format AcctTransExists("SELECT LedgerSeq FROM AccountTransactions WHERE TransID = '%s';");
|
||||
static boost::format transExists("SELECT Status FROM Transactions WHERE TransID = '%s';");
|
||||
static boost::format
|
||||
updateTx("UPDATE Transactions SET LedgerSeq = %d, Status = '%c', TxnMeta = %s WHERE TransID = '%s';");
|
||||
@@ -428,6 +428,8 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event)
|
||||
addRaw(s);
|
||||
theApp->getHashedObjectStore().store(hotLEDGER, mLedgerSeq, s.peekData(), mHash);
|
||||
|
||||
AcceptedLedger::pointer aLedger = AcceptedLedger::makeAcceptedLedger(shared_from_this());
|
||||
|
||||
{
|
||||
{
|
||||
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
|
||||
@@ -435,37 +437,26 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event)
|
||||
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(deleteLedger % mLedgerSeq));
|
||||
}
|
||||
|
||||
SHAMap& txSet = *peekTransactionMap();
|
||||
Database *db = theApp->getTxnDB()->getDB();
|
||||
{
|
||||
ScopedLock dbLock(theApp->getTxnDB()->getDBLock());
|
||||
db->executeSQL("BEGIN TRANSACTION;");
|
||||
SHAMapTreeNode::TNType type;
|
||||
for (SHAMapItem::pointer item = txSet.peekFirstItem(type); !!item;
|
||||
item = txSet.peekNextItem(item->getTag(), type))
|
||||
|
||||
BOOST_FOREACH(const AcceptedLedger::value_type& vt, aLedger->getMap())
|
||||
{
|
||||
assert(type == SHAMapTreeNode::tnTRANSACTION_MD);
|
||||
SerializerIterator sit(item->peekSerializer());
|
||||
Serializer rawTxn(sit.getVL());
|
||||
Serializer rawMeta(sit.getVL());
|
||||
std::string escMeta(sqlEscape(rawMeta.peekData()));
|
||||
|
||||
SerializerIterator txnIt(rawTxn);
|
||||
|
||||
SerializedTransaction txn(txnIt);
|
||||
assert(txn.getTransactionID() == item->getTag());
|
||||
TransactionMetaSet meta(item->getTag(), mLedgerSeq, rawMeta.peekData());
|
||||
theApp->getMasterTransaction().inLedger(item->getTag(), mLedgerSeq);
|
||||
cLog(lsTRACE) << "Saving: " << vt.second.getJson(0);
|
||||
uint256 txID = vt.second.getTransactionID();
|
||||
theApp->getMasterTransaction().inLedger(txID, mLedgerSeq);
|
||||
|
||||
// Make sure transaction is in AccountTransactions.
|
||||
if (!SQL_EXISTS(db, boost::str(AcctTransExists % item->getTag().GetHex())))
|
||||
if (!SQL_EXISTS(db, boost::str(AcctTransExists % txID.GetHex())))
|
||||
{
|
||||
// Transaction not in AccountTransactions
|
||||
const std::vector<RippleAddress> accts = meta.getAffectedAccounts();
|
||||
const std::vector<RippleAddress>& accts = vt.second.getAffected();
|
||||
if (!accts.empty())
|
||||
{
|
||||
|
||||
std::string sql = "INSERT INTO AccountTransactions (TransID, Account, LedgerSeq) VALUES ";
|
||||
std::string sql = "INSERT OR REPLACE INTO AccountTransactions (TransID, Account, LedgerSeq) VALUES ";
|
||||
bool first = true;
|
||||
for (std::vector<RippleAddress>::const_iterator it = accts.begin(), end = accts.end(); it != end; ++it)
|
||||
{
|
||||
@@ -476,7 +467,7 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event)
|
||||
sql += "('";
|
||||
first = false;
|
||||
}
|
||||
sql += txn.getTransactionID().GetHex();
|
||||
sql += txID.GetHex();
|
||||
sql += "','";
|
||||
sql += it->humanAccountID();
|
||||
sql += "',";
|
||||
@@ -491,20 +482,21 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event)
|
||||
cLog(lsWARNING) << "Transaction in ledger " << mLedgerSeq << " affects no accounts";
|
||||
}
|
||||
|
||||
if (SQL_EXISTS(db, boost::str(transExists % txn.getTransactionID().GetHex())))
|
||||
if (SQL_EXISTS(db, boost::str(transExists % txID.GetHex())))
|
||||
{
|
||||
// In Transactions, update LedgerSeq, metadata and Status.
|
||||
db->executeSQL(boost::str(updateTx
|
||||
% getLedgerSeq()
|
||||
% TXN_SQL_VALIDATED
|
||||
% escMeta
|
||||
% txn.getTransactionID().GetHex()));
|
||||
% vt.second.getEscMeta()
|
||||
% txID.GetHex()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not in Transactions, insert the whole thing..
|
||||
db->executeSQL(
|
||||
txn.getMetaSQLInsertHeader() + txn.getMetaSQL(getLedgerSeq(), escMeta) + ";");
|
||||
SerializedTransaction::getMetaSQLInsertHeader() +
|
||||
vt.second.getTxn()->getMetaSQL(getLedgerSeq(), vt.second.getEscMeta()) + ";");
|
||||
}
|
||||
}
|
||||
db->executeSQL("COMMIT TRANSACTION;");
|
||||
@@ -548,9 +540,9 @@ Ledger::pointer Ledger::loadByIndex(uint32 ledgerIndex)
|
||||
"ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,LedgerSeq"
|
||||
" from Ledgers WHERE LedgerSeq = ?;");
|
||||
|
||||
pSt.reset();
|
||||
pSt.bind(1, ledgerIndex);
|
||||
ledger = getSQL1(&pSt);
|
||||
pSt.reset();
|
||||
}
|
||||
if (ledger)
|
||||
Ledger::getSQL2(ledger);
|
||||
@@ -569,9 +561,9 @@ Ledger::pointer Ledger::loadByHash(const uint256& ledgerHash)
|
||||
"ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,LedgerSeq"
|
||||
" from Ledgers WHERE LedgerHash = ?;");
|
||||
|
||||
pSt.reset();
|
||||
pSt.bind(1, ledgerHash.GetHex());
|
||||
ledger = getSQL1(&pSt);
|
||||
pSt.reset();
|
||||
}
|
||||
if (ledger)
|
||||
{
|
||||
@@ -729,19 +721,20 @@ bool Ledger::getHashesByIndex(uint32 ledgerIndex, uint256& ledgerHash, uint256&
|
||||
ScopedLock sl(con->getDBLock());
|
||||
|
||||
static SqliteStatement pSt(con->getDB()->getSqliteDB(),
|
||||
"SELECT LedgerHash,PrevHash FROM Ledgers Where LedgerSeq = ?;");
|
||||
"SELECT LedgerHash,PrevHash FROM Ledgers INDEXED BY SeqLedger Where LedgerSeq = ?;");
|
||||
|
||||
pSt.reset();
|
||||
pSt.bind(1, ledgerIndex);
|
||||
|
||||
int ret = pSt.step();
|
||||
if (pSt.isDone(ret))
|
||||
{
|
||||
pSt.reset();
|
||||
cLog(lsTRACE) << "Don't have ledger " << ledgerIndex;
|
||||
return false;
|
||||
}
|
||||
if (!pSt.isRow(ret))
|
||||
{
|
||||
pSt.reset();
|
||||
assert(false);
|
||||
cLog(lsFATAL) << "Unexpected statement result " << ret;
|
||||
return false;
|
||||
@@ -749,6 +742,7 @@ bool Ledger::getHashesByIndex(uint32 ledgerIndex, uint256& ledgerHash, uint256&
|
||||
|
||||
ledgerHash.SetHex(pSt.peekString(0), true);
|
||||
parentHash.SetHex(pSt.peekString(1), true);
|
||||
pSt.reset();
|
||||
|
||||
return true;
|
||||
|
||||
@@ -779,6 +773,45 @@ bool Ledger::getHashesByIndex(uint32 ledgerIndex, uint256& ledgerHash, uint256&
|
||||
#endif
|
||||
}
|
||||
|
||||
std::map< uint32, std::pair<uint256, uint256> > Ledger::getHashesByIndex(uint32 minSeq, uint32 maxSeq)
|
||||
{
|
||||
#ifndef NO_SQLITE_PREPARE
|
||||
std::map< uint32, std::pair<uint256, uint256> > ret;
|
||||
DatabaseCon *con = theApp->getLedgerDB();
|
||||
ScopedLock sl(con->getDBLock());
|
||||
|
||||
static SqliteStatement pSt(con->getDB()->getSqliteDB(),
|
||||
"SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers INDEXED BY SeqLedger "
|
||||
"WHERE LedgerSeq >= ? AND LedgerSeq <= ?;");
|
||||
|
||||
std::pair<uint256, uint256> hashes;
|
||||
|
||||
pSt.bind(1, minSeq);
|
||||
pSt.bind(2, maxSeq);
|
||||
|
||||
do
|
||||
{
|
||||
int r = pSt.step();
|
||||
if (pSt.isDone(r))
|
||||
{
|
||||
pSt.reset();
|
||||
return ret;
|
||||
}
|
||||
if (!pSt.isRow(r))
|
||||
{
|
||||
pSt.reset();
|
||||
return ret;
|
||||
}
|
||||
hashes.first.SetHex(pSt.peekString(1), true);
|
||||
hashes.second.SetHex(pSt.peekString(2), true);
|
||||
ret[pSt.getUInt32(0)] = hashes;
|
||||
} while(1);
|
||||
|
||||
#else
|
||||
#error SQLite prepare is required
|
||||
#endif
|
||||
}
|
||||
|
||||
Ledger::pointer Ledger::getLastFullLedger()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -202,6 +202,7 @@ public:
|
||||
static Ledger::pointer loadByHash(const uint256& ledgerHash);
|
||||
static uint256 getHashByIndex(uint32 index);
|
||||
static bool getHashesByIndex(uint32 index, uint256& ledgerHash, uint256& parentHash);
|
||||
static std::map< uint32, std::pair<uint256, uint256> > getHashesByIndex(uint32 minSeq, uint32 maxSeq);
|
||||
void pendSave(bool fromConsensus);
|
||||
|
||||
// next/prev function
|
||||
|
||||
@@ -392,7 +392,7 @@ void LedgerConsensus::checkLCL()
|
||||
{
|
||||
case lcsPRE_CLOSE: status = "PreClose"; break;
|
||||
case lcsESTABLISH: status = "Establish"; break;
|
||||
case lcsFINISHED: status = "Finised"; break;
|
||||
case lcsFINISHED: status = "Finished"; break;
|
||||
case lcsACCEPTED: status = "Accepted"; break;
|
||||
default: status = "unknown";
|
||||
}
|
||||
@@ -400,6 +400,7 @@ void LedgerConsensus::checkLCL()
|
||||
cLog(lsWARNING) << "View of consensus changed during " << status << " (" << netLgrCount << ") status="
|
||||
<< status << ", " << (mHaveCorrectLCL ? "CorrectLCL" : "IncorrectLCL");
|
||||
cLog(lsWARNING) << mPrevLedgerHash << " to " << netLgr;
|
||||
cLog(lsWARNING) << mPreviousLedger->getJson(0);
|
||||
|
||||
if (sLog(lsDEBUG))
|
||||
{
|
||||
@@ -762,6 +763,7 @@ void LedgerConsensus::updateOurPositions()
|
||||
|
||||
|
||||
int neededWeight;
|
||||
|
||||
if (mClosePercent < AV_MID_CONSENSUS_TIME)
|
||||
neededWeight = AV_INIT_CONSENSUS_PCT;
|
||||
else if (mClosePercent < AV_LATE_CONSENSUS_TIME)
|
||||
@@ -769,41 +771,50 @@ void LedgerConsensus::updateOurPositions()
|
||||
else if (mClosePercent < AV_STUCK_CONSENSUS_TIME)
|
||||
neededWeight = AV_LATE_CONSENSUS_PCT;
|
||||
else
|
||||
neededWeight = AV_STUCK_CONSENSUS_TIME;
|
||||
neededWeight = AV_STUCK_CONSENSUS_PCT;
|
||||
|
||||
uint32 closeTime = 0;
|
||||
mHaveCloseTimeConsensus = false;
|
||||
|
||||
int thresh = mPeerPositions.size();
|
||||
if (thresh == 0)
|
||||
if (mPeerPositions.empty())
|
||||
{ // no other times
|
||||
mHaveCloseTimeConsensus = true;
|
||||
closeTime = roundCloseTime(mOurPosition->getCloseTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
int threshVote = mPeerPositions.size(); // Threshold for non-zero vote
|
||||
int threshConsensus = mPeerPositions.size(); // Threshold to declare consensus
|
||||
if (mProposing)
|
||||
{
|
||||
++closeTimes[roundCloseTime(mOurPosition->getCloseTime())];
|
||||
++thresh;
|
||||
++threshVote;
|
||||
++threshConsensus;
|
||||
}
|
||||
thresh = ((thresh * neededWeight) + (neededWeight / 2)) / 100;
|
||||
if (thresh == 0)
|
||||
thresh = 1;
|
||||
threshVote = ((threshVote * neededWeight) + (neededWeight / 2)) / 100;
|
||||
threshConsensus = ((threshConsensus * AV_CT_CONSENSUS_PCT) + (AV_CT_CONSENSUS_PCT / 2)) / 100;
|
||||
|
||||
if (threshVote == 0)
|
||||
threshVote = 1;
|
||||
if (threshConsensus == 0)
|
||||
threshConsensus = 1;
|
||||
cLog(lsINFO) << "Proposers:" << mPeerPositions.size() << " nw:" << neededWeight
|
||||
<< " thrV:" << threshVote << " thrC:" << threshConsensus;
|
||||
|
||||
for (std::map<uint32, int>::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it)
|
||||
{
|
||||
cLog(lsTRACE) << "CCTime: " << it->first << " has " << it->second << ", " << thresh << " required";
|
||||
if (it->second >= thresh)
|
||||
cLog(lsDEBUG) << "CCTime: " << it->first << " has " << it->second << ", " << threshVote << " required";
|
||||
if (it->second >= threshVote)
|
||||
{
|
||||
cLog(lsDEBUG) << "Close time consensus reached: " << it->first;
|
||||
mHaveCloseTimeConsensus = true;
|
||||
closeTime = it->first;
|
||||
thresh = it->second;
|
||||
threshVote = it->second;
|
||||
if (threshVote >= threshConsensus)
|
||||
mHaveCloseTimeConsensus = true;
|
||||
}
|
||||
}
|
||||
tLog(!mHaveCloseTimeConsensus, lsDEBUG) << "No CT consensus: Proposers:" << mPeerPositions.size()
|
||||
<< " Proposing:" << (mProposing ? "yes" : "no") << " Thresh:" << thresh << " Pos:" << closeTime;
|
||||
<< " Proposing:" << (mProposing ? "yes" : "no") << " Thresh:" << threshConsensus << " Pos:" << closeTime;
|
||||
}
|
||||
|
||||
if (!changes &&
|
||||
@@ -1044,7 +1055,10 @@ bool LedgerConsensus::peerHasSet(Peer::ref peer, const uint256& hashSet, ripple:
|
||||
set.push_back(peer);
|
||||
boost::unordered_map<uint256, TransactionAcquire::pointer>::iterator acq = mAcquiring.find(hashSet);
|
||||
if (acq != mAcquiring.end())
|
||||
acq->second->peerHas(peer);
|
||||
{
|
||||
TransactionAcquire::pointer ta = acq->second; // make sure it doesn't go away
|
||||
ta->peerHas(peer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1066,6 +1066,8 @@ STAmount LedgerEntrySet::rippleHolds(const uint160& uAccountID, const uint160& u
|
||||
return saBalance;
|
||||
}
|
||||
|
||||
// Returns the amount an account can spend without going into debt.
|
||||
//
|
||||
// <-- saAmount: amount of uCurrencyID held by uAccountID. May be negative.
|
||||
STAmount LedgerEntrySet::accountHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ std::map<std::string, LedgerEntryFormat*> LedgerEntryFormat::byName;
|
||||
|
||||
#define DECLARE_LEF(name, type) lef = new LedgerEntryFormat(#name, type); (*lef) LEF_BASE
|
||||
|
||||
static bool LEFInit()
|
||||
void LEFInit()
|
||||
{
|
||||
LedgerEntryFormat* lef;
|
||||
|
||||
@@ -111,12 +111,8 @@ static bool LEFInit()
|
||||
<< SOElement(sfReserveBase, SOE_REQUIRED)
|
||||
<< SOElement(sfReserveIncrement, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LEFInitComplete = LEFInit();
|
||||
|
||||
LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(LedgerEntryType t)
|
||||
{
|
||||
std::map<int, LedgerEntryFormat*>::iterator it = byType.find(static_cast<int>(t));
|
||||
|
||||
@@ -58,7 +58,7 @@ class LedgerEntryFormat
|
||||
public:
|
||||
std::string t_name;
|
||||
LedgerEntryType t_type;
|
||||
std::vector<SOElement::ref> elements;
|
||||
SOTemplate elements;
|
||||
|
||||
static std::map<int, LedgerEntryFormat*> byType;
|
||||
static std::map<std::string, LedgerEntryFormat*> byName;
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
}
|
||||
LedgerEntryFormat& operator<<(const SOElement& el)
|
||||
{
|
||||
elements.push_back(new SOElement(el));
|
||||
elements.push_back(el);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,11 +119,11 @@ Ledger::pointer LedgerMaster::closeLedger(bool recover)
|
||||
return closingLedger;
|
||||
}
|
||||
|
||||
TER LedgerMaster::doTransaction(const SerializedTransaction& txn, TransactionEngineParams params, bool& didApply)
|
||||
TER LedgerMaster::doTransaction(SerializedTransaction::ref txn, TransactionEngineParams params, bool& didApply)
|
||||
{
|
||||
TER result = mEngine.applyTransaction(txn, params, didApply);
|
||||
// CHECKME: Should we call this even on gross failures?
|
||||
theApp->getOPs().pubProposedTransaction(mEngine.getLedger(), txn, result);
|
||||
TER result = mEngine.applyTransaction(*txn, params, didApply);
|
||||
// if (didApply)
|
||||
theApp->getOPs().pubProposedTransaction(mEngine.getLedger(), txn, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -145,6 +145,8 @@ void LedgerMaster::asyncAccept(Ledger::pointer ledger)
|
||||
uint32 seq = ledger->getLedgerSeq();
|
||||
uint256 prevHash = ledger->getParentHash();
|
||||
|
||||
std::map< uint32, std::pair<uint256, uint256> > ledgerHashes;
|
||||
|
||||
while (seq > 0)
|
||||
{
|
||||
{
|
||||
@@ -155,10 +157,20 @@ void LedgerMaster::asyncAccept(Ledger::pointer ledger)
|
||||
break;
|
||||
}
|
||||
|
||||
uint256 tHash, pHash;
|
||||
if (!Ledger::getHashesByIndex(seq, tHash, pHash) || (tHash != prevHash))
|
||||
std::map< uint32, std::pair<uint256, uint256> >::iterator it = ledgerHashes.find(seq);
|
||||
if (it == ledgerHashes.end())
|
||||
{
|
||||
if (theApp->isShutdown())
|
||||
return;
|
||||
ledgerHashes = Ledger::getHashesByIndex((seq < 500) ? 0 : (seq - 499), seq);
|
||||
it = ledgerHashes.find(seq);
|
||||
if (it == ledgerHashes.end())
|
||||
break;
|
||||
}
|
||||
|
||||
if (it->second.first != prevHash)
|
||||
break;
|
||||
prevHash = pHash;
|
||||
prevHash = it->second.second;
|
||||
}
|
||||
|
||||
resumeAcquiring();
|
||||
@@ -174,7 +186,8 @@ bool LedgerMaster::acquireMissingLedger(Ledger::ref origLedger, const uint256& l
|
||||
{
|
||||
cLog(lsTRACE) << "Ledger hash found in database";
|
||||
mTooFast = true;
|
||||
theApp->getJobQueue().addJob(jtPUBOLDLEDGER, boost::bind(&LedgerMaster::asyncAccept, this, ledger));
|
||||
theApp->getJobQueue().addJob(jtPUBOLDLEDGER, "LedgerMaster::asyncAccept",
|
||||
boost::bind(&LedgerMaster::asyncAccept, this, ledger));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -528,7 +541,8 @@ void LedgerMaster::tryPublish()
|
||||
{
|
||||
theApp->getOPs().clearNeedNetworkLedger();
|
||||
mPubThread = true;
|
||||
theApp->getJobQueue().addJob(jtPUBLEDGER, boost::bind(&LedgerMaster::pubThread, this));
|
||||
theApp->getJobQueue().addJob(jtPUBLEDGER, "Ledger::pubThread",
|
||||
boost::bind(&LedgerMaster::pubThread, this));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
// The published ledger is the last fully validated ledger
|
||||
Ledger::ref getValidatedLedger() { return mPubLedger; }
|
||||
|
||||
TER doTransaction(const SerializedTransaction& txn, TransactionEngineParams params, bool& didApply);
|
||||
TER doTransaction(SerializedTransaction::ref txn, TransactionEngineParams params, bool& didApply);
|
||||
|
||||
void pushLedger(Ledger::ref newLedger);
|
||||
void pushLedger(Ledger::ref newLCL, Ledger::ref newOL, bool fromConsensus);
|
||||
|
||||
@@ -39,17 +39,18 @@
|
||||
# define PROPOSE_INTERVAL 12
|
||||
|
||||
// Avalanche tuning
|
||||
#define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes
|
||||
# define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes
|
||||
|
||||
#define AV_MID_CONSENSUS_TIME 50 // percentage of previous close time before we advance
|
||||
#define AV_MID_CONSENSUS_PCT 65 // percentage of nodes that most vote yes after advancing
|
||||
# define AV_MID_CONSENSUS_TIME 50 // percentage of previous close time before we advance
|
||||
# define AV_MID_CONSENSUS_PCT 65 // percentage of nodes that most vote yes after advancing
|
||||
|
||||
#define AV_LATE_CONSENSUS_TIME 85 // percentage of previous close time before we advance
|
||||
#define AV_LATE_CONSENSUS_PCT 70 // percentage of nodes that most vote yes after advancing
|
||||
# define AV_LATE_CONSENSUS_TIME 85 // percentage of previous close time before we advance
|
||||
# define AV_LATE_CONSENSUS_PCT 70 // percentage of nodes that most vote yes after advancing
|
||||
|
||||
#define AV_STUCK_CONSENSUS_TIME 200
|
||||
#define AV_STUCK_CONSENSUS_PCT 95
|
||||
# define AV_STUCK_CONSENSUS_TIME 200
|
||||
# define AV_STUCK_CONSENSUS_PCT 95
|
||||
|
||||
# define AV_CT_CONSENSUS_PCT 75
|
||||
|
||||
class ContinuousLedgerTiming
|
||||
{
|
||||
|
||||
@@ -318,7 +318,10 @@ void LoadManager::threadEntry()
|
||||
|
||||
bool change;
|
||||
if (theApp->getJobQueue().isOverloaded())
|
||||
{
|
||||
cLog(lsINFO) << theApp->getJobQueue().getJson(0);
|
||||
change = theApp->getFeeTrack().raiseLocalFee();
|
||||
}
|
||||
else
|
||||
change = theApp->getFeeTrack().lowerLocalFee();
|
||||
if (change)
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#include "LoadMonitor.h"
|
||||
#include "Log.h"
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
void LoadMonitor::update()
|
||||
{ // call with the mutex
|
||||
@@ -52,8 +55,12 @@ void LoadMonitor::addLatency(int latency)
|
||||
mLatencyMSPeak = lp;
|
||||
}
|
||||
|
||||
void LoadMonitor::addCountAndLatency(int counts, int latency)
|
||||
void LoadMonitor::addCountAndLatency(const std::string& name, int counts, int latency)
|
||||
{
|
||||
if (latency > 1000)
|
||||
{
|
||||
cLog(lsWARNING) << "Job: " << name << " ExecutionTime: " << latency;
|
||||
}
|
||||
if (latency == 1)
|
||||
latency = 0;
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
|
||||
void addCount(int counts);
|
||||
void addLatency(int latency);
|
||||
void addCountAndLatency(int counts, int latency);
|
||||
void addCountAndLatency(const std::string& name, int counts, int latency);
|
||||
|
||||
void setTargetLatency(uint64 avg, uint64 pk)
|
||||
{
|
||||
@@ -60,6 +60,7 @@ protected:
|
||||
LoadMonitor& mMonitor;
|
||||
bool mRunning;
|
||||
int mCount;
|
||||
std::string mName;
|
||||
boost::posix_time::ptime mStartTime;
|
||||
|
||||
public:
|
||||
@@ -76,6 +77,11 @@ public:
|
||||
stop();
|
||||
}
|
||||
|
||||
void setName(const std::string& name)
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
void start()
|
||||
{ // okay to call if already started
|
||||
mRunning = true;
|
||||
@@ -86,7 +92,7 @@ public:
|
||||
{
|
||||
assert(mRunning);
|
||||
mRunning = false;
|
||||
mMonitor.addCountAndLatency(mCount,
|
||||
mMonitor.addCountAndLatency(mName, mCount,
|
||||
static_cast<int>((boost::posix_time::microsec_clock::universal_time() - mStartTime).total_milliseconds()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -267,7 +267,7 @@ void NetworkOPs::runTransactionQueue()
|
||||
assert(dbtx);
|
||||
|
||||
bool didApply;
|
||||
TER r = mLedgerMaster->doTransaction(*dbtx->getSTransaction(),
|
||||
TER r = mLedgerMaster->doTransaction(dbtx->getSTransaction(),
|
||||
tapOPEN_LEDGER | tapNO_CHECK_SIGN, didApply);
|
||||
dbtx->setResult(r);
|
||||
|
||||
@@ -352,7 +352,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
||||
boost::recursive_mutex::scoped_lock sl(theApp->getMasterLock());
|
||||
Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true);
|
||||
bool didApply;
|
||||
TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tapOPEN_LEDGER | tapNO_CHECK_SIGN, didApply);
|
||||
TER r = mLedgerMaster->doTransaction(trans->getSTransaction(), tapOPEN_LEDGER | tapNO_CHECK_SIGN, didApply);
|
||||
trans->setResult(r);
|
||||
|
||||
if (isTemMalformed(r)) // malformed, cache bad
|
||||
@@ -426,30 +426,6 @@ Transaction::pointer NetworkOPs::findTransactionByID(const uint256& transactionI
|
||||
return Transaction::load(transactionID);
|
||||
}
|
||||
|
||||
#if 0
|
||||
int NetworkOPs::findTransactionsBySource(const uint256& uLedger, std::list<Transaction::pointer>& txns,
|
||||
const RippleAddress& sourceAccount, uint32 minSeq, uint32 maxSeq)
|
||||
{
|
||||
AccountState::pointer state = getAccountState(uLedger, sourceAccount);
|
||||
if (!state) return 0;
|
||||
if (minSeq > state->getSeq()) return 0;
|
||||
if (maxSeq > state->getSeq()) maxSeq = state->getSeq();
|
||||
if (maxSeq > minSeq) return 0;
|
||||
|
||||
int count = 0;
|
||||
for(unsigned int i = minSeq; i <= maxSeq; ++i)
|
||||
{
|
||||
Transaction::pointer txn = Transaction::findFrom(sourceAccount, i);
|
||||
if(txn)
|
||||
{
|
||||
txns.push_back(txn);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
int NetworkOPs::findTransactionsByDestination(std::list<Transaction::pointer>& txns,
|
||||
const RippleAddress& destinationAccount, uint32 startLedgerSeq, uint32 endLedgerSeq, int maxTransactions)
|
||||
{
|
||||
@@ -1313,9 +1289,9 @@ Json::Value NetworkOPs::pubBootstrapAccountInfo(Ledger::ref lpAccepted, const Ri
|
||||
return jvObj;
|
||||
}
|
||||
|
||||
void NetworkOPs::pubProposedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult)
|
||||
void NetworkOPs::pubProposedTransaction(Ledger::ref lpCurrent, SerializedTransaction::ref stTxn, TER terResult)
|
||||
{
|
||||
Json::Value jvObj = transJson(stTxn, terResult, false, lpCurrent, "transaction");
|
||||
Json::Value jvObj = transJson(*stTxn, terResult, false, lpCurrent, "transaction");
|
||||
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
@@ -1332,15 +1308,19 @@ void NetworkOPs::pubProposedTransaction(Ledger::ref lpCurrent, const SerializedT
|
||||
it = mSubRTTransactions.erase(it);
|
||||
}
|
||||
}
|
||||
TransactionMetaSet::pointer ret;
|
||||
pubAccountTransaction(lpCurrent,stTxn,terResult,false,ret);
|
||||
ALTransaction alt(stTxn, terResult);
|
||||
cLog(lsTRACE) << "pubProposed: " << alt.getJson(0);
|
||||
pubAccountTransaction(lpCurrent, ALTransaction(stTxn, terResult));
|
||||
}
|
||||
|
||||
void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
|
||||
void NetworkOPs::pubLedger(Ledger::ref accepted)
|
||||
{
|
||||
// Ledgers are published only when they acquire sufficient validations
|
||||
// Holes are filled across connection loss or other catastrophe
|
||||
|
||||
AcceptedLedger::pointer alpAccepted = AcceptedLedger::makeAcceptedLedger(accepted);
|
||||
Ledger::ref lpAccepted = alpAccepted->getLedger();
|
||||
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
|
||||
@@ -1358,6 +1338,8 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
|
||||
jvObj["reserve_base"] = Json::UInt(lpAccepted->getReserve(0));
|
||||
jvObj["reserve_inc"] = Json::UInt(lpAccepted->getReserveInc());
|
||||
|
||||
jvObj["txn_count"] = Json::UInt(alpAccepted->getTxnCount());
|
||||
|
||||
NetworkOPs::subMapType::const_iterator it = mSubLedger.begin();
|
||||
while (it != mSubLedger.end())
|
||||
{
|
||||
@@ -1376,21 +1358,10 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
|
||||
// Don't lock since pubAcceptedTransaction is locking.
|
||||
if (!mSubTransactions.empty() || !mSubRTTransactions.empty() || !mSubAccount.empty() || !mSubRTAccount.empty())
|
||||
{
|
||||
SHAMap& txSet = *lpAccepted->peekTransactionMap();
|
||||
|
||||
for (SHAMapItem::pointer item = txSet.peekFirstItem(); !!item; item = txSet.peekNextItem(item->getTag()))
|
||||
BOOST_FOREACH(const AcceptedLedger::value_type& vt, alpAccepted->getMap())
|
||||
{
|
||||
SerializerIterator it(item->peekSerializer());
|
||||
|
||||
// OPTIMIZEME: Could get transaction from txn master, but still must call getVL
|
||||
Serializer txnSer(it.getVL());
|
||||
SerializerIterator txnIt(txnSer);
|
||||
SerializedTransaction stTxn(txnIt);
|
||||
|
||||
TransactionMetaSet::pointer meta = boost::make_shared<TransactionMetaSet>(
|
||||
stTxn.getTransactionID(), lpAccepted->getLedgerSeq(), it.getVL());
|
||||
|
||||
pubAcceptedTransaction(lpAccepted, stTxn, meta->getResultTER(), meta);
|
||||
cLog(lsTRACE) << "pubAccepted: " << vt.second.getJson(0);
|
||||
pubAcceptedTransaction(lpAccepted, vt.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1401,7 +1372,7 @@ void NetworkOPs::reportFeeChange()
|
||||
(theApp->getFeeTrack().getLoadFactor() == mLastLoadFactor))
|
||||
return;
|
||||
|
||||
theApp->getJobQueue().addJob(jtCLIENT, boost::bind(&NetworkOPs::pubServer, this));
|
||||
theApp->getJobQueue().addJob(jtCLIENT, "reportFeeChange->pubServer", boost::bind(&NetworkOPs::pubServer, this));
|
||||
}
|
||||
|
||||
Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terResult, bool bAccepted, Ledger::ref lpCurrent, const std::string& strType)
|
||||
@@ -1431,11 +1402,10 @@ Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terRes
|
||||
return jvObj;
|
||||
}
|
||||
|
||||
void NetworkOPs::pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta)
|
||||
void NetworkOPs::pubAcceptedTransaction(Ledger::ref alAccepted, const ALTransaction& alTx)
|
||||
{
|
||||
Json::Value jvObj = transJson(stTxn, terResult, true, lpCurrent, "transaction");
|
||||
|
||||
if (meta) jvObj["meta"] = meta->getJson(0);
|
||||
Json::Value jvObj = transJson(*alTx.getTxn(), alTx.getResult(), true, alAccepted, "transaction");
|
||||
jvObj["meta"] = alTx.getMeta()->getJson(0);
|
||||
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
@@ -1466,14 +1436,14 @@ void NetworkOPs::pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedT
|
||||
it = mSubRTTransactions.erase(it);
|
||||
}
|
||||
}
|
||||
theApp->getOrderBookDB().processTxn(stTxn, terResult, meta, jvObj);
|
||||
|
||||
pubAccountTransaction(lpCurrent, stTxn, terResult, true, meta);
|
||||
theApp->getOrderBookDB().processTxn(alAccepted, alTx, jvObj);
|
||||
pubAccountTransaction(alAccepted, alTx);
|
||||
}
|
||||
|
||||
void NetworkOPs::pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, bool bAccepted, TransactionMetaSet::pointer& meta)
|
||||
void NetworkOPs::pubAccountTransaction(Ledger::ref lpCurrent, const ALTransaction& alTx)
|
||||
{
|
||||
boost::unordered_set<InfoSub::pointer> notify;
|
||||
bool bAccepted = alTx.isApplied();
|
||||
int iProposed = 0;
|
||||
int iAccepted = 0;
|
||||
|
||||
@@ -1484,8 +1454,7 @@ void NetworkOPs::pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTr
|
||||
|
||||
if (!mSubAccount.empty() || (!mSubRTAccount.empty()) )
|
||||
{
|
||||
std::vector<RippleAddress> accounts = meta ? meta->getAffectedAccounts() : stTxn.getMentionedAccounts();
|
||||
BOOST_FOREACH(const RippleAddress& affectedAccount, accounts)
|
||||
BOOST_FOREACH(const RippleAddress& affectedAccount, alTx.getAffected())
|
||||
{
|
||||
subInfoMapIterator simiIt = mSubRTAccount.find(affectedAccount.getAccountID());
|
||||
|
||||
@@ -1534,9 +1503,10 @@ void NetworkOPs::pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTr
|
||||
|
||||
if (!notify.empty())
|
||||
{
|
||||
Json::Value jvObj = transJson(stTxn, terResult, bAccepted, lpCurrent, "account");
|
||||
Json::Value jvObj = transJson(*alTx.getTxn(), alTx.getResult(), bAccepted, lpCurrent, "account");
|
||||
|
||||
if (meta) jvObj["meta"] = meta->getJson(0);
|
||||
if (alTx.isApplied())
|
||||
jvObj["meta"] = alTx.getMeta()->getJson(0);
|
||||
|
||||
BOOST_FOREACH(InfoSub::ref isrListener, notify)
|
||||
{
|
||||
@@ -1696,12 +1666,14 @@ bool NetworkOPs::subLedger(InfoSub::ref isrListener, Json::Value& jvResult)
|
||||
jvResult["reserve_base"] = Json::UInt(lpClosed->getReserve(0));
|
||||
jvResult["reserve_inc"] = Json::UInt(lpClosed->getReserveInc());
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
return mSubLedger.insert(std::make_pair(isrListener->getSeq(), isrListener)).second;
|
||||
}
|
||||
|
||||
// <-- bool: true=erased, false=was not there
|
||||
bool NetworkOPs::unsubLedger(uint64 uSeq)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
return !!mSubLedger.erase(uSeq);
|
||||
}
|
||||
|
||||
@@ -1722,36 +1694,42 @@ bool NetworkOPs::subServer(InfoSub::ref isrListener, Json::Value& jvResult)
|
||||
jvResult["load_base"] = theApp->getFeeTrack().getLoadBase();
|
||||
jvResult["load_factor"] = theApp->getFeeTrack().getLoadFactor();
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
return mSubServer.insert(std::make_pair(isrListener->getSeq(), isrListener)).second;
|
||||
}
|
||||
|
||||
// <-- bool: true=erased, false=was not there
|
||||
bool NetworkOPs::unsubServer(uint64 uSeq)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
return !!mSubServer.erase(uSeq);
|
||||
}
|
||||
|
||||
// <-- bool: true=added, false=already there
|
||||
bool NetworkOPs::subTransactions(InfoSub::ref isrListener)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
return mSubTransactions.insert(std::make_pair(isrListener->getSeq(), isrListener)).second;
|
||||
}
|
||||
|
||||
// <-- bool: true=erased, false=was not there
|
||||
bool NetworkOPs::unsubTransactions(uint64 uSeq)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
return !!mSubTransactions.erase(uSeq);
|
||||
}
|
||||
|
||||
// <-- bool: true=added, false=already there
|
||||
bool NetworkOPs::subRTTransactions(InfoSub::ref isrListener)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
return mSubTransactions.insert(std::make_pair(isrListener->getSeq(), isrListener)).second;
|
||||
}
|
||||
|
||||
// <-- bool: true=erased, false=was not there
|
||||
bool NetworkOPs::unsubRTTransactions(uint64 uSeq)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mMonitorLock);
|
||||
return !!mSubTransactions.erase(uSeq);
|
||||
}
|
||||
|
||||
@@ -1774,5 +1752,170 @@ InfoSub::pointer NetworkOPs::addRpcSub(const std::string& strUrl, InfoSub::ref r
|
||||
return rspEntry;
|
||||
}
|
||||
|
||||
// FIXME : support iLimit.
|
||||
void NetworkOPs::getBookPage(Ledger::pointer lpLedger, const uint160& uTakerPaysCurrencyID, const uint160& uTakerPaysIssuerID, const uint160& uTakerGetsCurrencyID, const uint160& uTakerGetsIssuerID, const uint160& uTakerID, const bool bProof, const unsigned int iLimit, const Json::Value& jvMarker, Json::Value& jvResult)
|
||||
{
|
||||
boost::unordered_map<uint160, STAmount> umBalance;
|
||||
Json::Value jvOffers = Json::Value(Json::arrayValue);
|
||||
const uint256 uBookBase = Ledger::getBookBase(uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID);
|
||||
const uint256 uBookEnd = Ledger::getQualityNext(uBookBase);
|
||||
uint256 uTipIndex = uBookBase;
|
||||
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: uTakerPaysCurrencyID=%s uTakerPaysIssuerID=%s") % STAmount::createHumanCurrency(uTakerPaysCurrencyID) % RippleAddress::createHumanAccountID(uTakerPaysIssuerID));
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: uTakerGetsCurrencyID=%s uTakerGetsIssuerID=%s") % STAmount::createHumanCurrency(uTakerGetsCurrencyID) % RippleAddress::createHumanAccountID(uTakerGetsIssuerID));
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: uBookBase=%s") % uBookBase);
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: uBookEnd=%s") % uBookEnd);
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: uTipIndex=%s") % uTipIndex);
|
||||
|
||||
LedgerEntrySet lesActive(lpLedger);
|
||||
|
||||
bool bDone = false;
|
||||
bool bDirectAdvance = true;
|
||||
|
||||
SLE::pointer sleOfferDir;
|
||||
uint256 uOfferIndex;
|
||||
unsigned int uBookEntry;
|
||||
STAmount saDirRate;
|
||||
|
||||
// unsigned int iLeft = iLimit;
|
||||
|
||||
uint32 uTransferRate = lesActive.rippleTransferRate(uTakerGetsIssuerID);
|
||||
|
||||
while (!bDone) {
|
||||
if (bDirectAdvance) {
|
||||
bDirectAdvance = false;
|
||||
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: bDirectAdvance"));
|
||||
|
||||
sleOfferDir = lesActive.entryCache(ltDIR_NODE, lpLedger->getNextLedgerIndex(uTipIndex, uBookEnd));
|
||||
if (!sleOfferDir)
|
||||
{
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: bDone"));
|
||||
bDone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uTipIndex = sleOfferDir->getIndex();
|
||||
saDirRate = STAmount::setRate(Ledger::getQuality(uTipIndex));
|
||||
SLE::pointer sleBookNode;
|
||||
|
||||
lesActive.dirFirst(uTipIndex, sleBookNode, uBookEntry, uOfferIndex);
|
||||
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: uTipIndex=%s") % uTipIndex);
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: uOfferIndex=%s") % uOfferIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bDone)
|
||||
{
|
||||
SLE::pointer sleOffer = lesActive.entryCache(ltOFFER, uOfferIndex);
|
||||
const uint160 uOfferOwnerID = sleOffer->getFieldAccount(sfAccount).getAccountID();
|
||||
STAmount saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
|
||||
STAmount saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
|
||||
STAmount saOwnerFunds;
|
||||
|
||||
if (uTakerGetsIssuerID == uOfferOwnerID)
|
||||
{
|
||||
// If offer is selling issuer's own IOUs, it is fully funded.
|
||||
saOwnerFunds = saTakerGets;
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::unordered_map<uint160, STAmount>::const_iterator umBalanceEntry = umBalance.find(uOfferOwnerID);
|
||||
|
||||
if (umBalanceEntry != umBalance.end())
|
||||
{
|
||||
// Found in running balance table.
|
||||
|
||||
saOwnerFunds = umBalanceEntry->second;
|
||||
// cLog(lsINFO) << boost::str(boost::format("getBookPage: saOwnerFunds=%s (cached)") % saOwnerFunds.getFullText());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Did not find balance in table.
|
||||
|
||||
saOwnerFunds = lesActive.accountHolds(uOfferOwnerID, uTakerGetsCurrencyID, uTakerGetsIssuerID);
|
||||
// cLog(lsINFO) << boost::str(boost::format("getBookPage: saOwnerFunds=%s (new)") % saOwnerFunds.getFullText());
|
||||
if (saOwnerFunds.isNegative())
|
||||
{
|
||||
// Treat negative funds as zero.
|
||||
|
||||
saOwnerFunds.zero();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value jvOffer = sleOffer->getJson(0);
|
||||
|
||||
STAmount saTakerGetsFunded;
|
||||
STAmount saOwnerFundsLimit;
|
||||
uint32 uOfferRate;
|
||||
|
||||
|
||||
if (uTransferRate != QUALITY_ONE // Have a tranfer fee.
|
||||
&& uTakerID != uTakerGetsIssuerID // Not taking offers of own IOUs.
|
||||
&& uTakerGetsIssuerID != uOfferOwnerID) { // Offer owner not issuing ownfunds
|
||||
// Need to charge a transfer fee to offer owner.
|
||||
uOfferRate = uTransferRate;
|
||||
saOwnerFundsLimit = STAmount::divide(saOwnerFunds, STAmount(CURRENCY_ONE, ACCOUNT_ONE, uOfferRate, -9));
|
||||
}
|
||||
else
|
||||
{
|
||||
uOfferRate = QUALITY_ONE;
|
||||
saOwnerFundsLimit = saOwnerFunds;
|
||||
}
|
||||
|
||||
if (saOwnerFundsLimit >= saTakerGets)
|
||||
{
|
||||
// Sufficient funds no shenanigans.
|
||||
saTakerGetsFunded = saTakerGets;
|
||||
}
|
||||
else
|
||||
{
|
||||
// cLog(lsINFO) << boost::str(boost::format("getBookPage: saTakerGets=%s") % saTakerGets.getFullText());
|
||||
// cLog(lsINFO) << boost::str(boost::format("getBookPage: saTakerPays=%s") % saTakerPays.getFullText());
|
||||
// cLog(lsINFO) << boost::str(boost::format("getBookPage: saOwnerFunds=%s") % saOwnerFunds.getFullText());
|
||||
// cLog(lsINFO) << boost::str(boost::format("getBookPage: saDirRate=%s") % saDirRate.getText());
|
||||
// cLog(lsINFO) << boost::str(boost::format("getBookPage: multiply=%s") % STAmount::multiply(saTakerGetsFunded, saDirRate).getFullText());
|
||||
// cLog(lsINFO) << boost::str(boost::format("getBookPage: multiply=%s") % STAmount::multiply(saTakerGetsFunded, saDirRate, saTakerPays).getFullText());
|
||||
STAmount saTakerPaysFunded;
|
||||
|
||||
saTakerGetsFunded = saOwnerFundsLimit;
|
||||
saTakerPaysFunded = std::min(saTakerPays, STAmount::multiply(saTakerGetsFunded, saDirRate, saTakerPays));
|
||||
|
||||
// Only provide, if not fully funded.
|
||||
jvOffer["taker_gets_funded"] = saTakerGetsFunded.getJson(0);
|
||||
jvOffer["taker_pays_funded"] = saTakerPaysFunded.getJson(0);
|
||||
|
||||
}
|
||||
STAmount saOwnerPays = QUALITY_ONE == uOfferRate
|
||||
? saTakerGetsFunded
|
||||
: std::min(saOwnerFunds, STAmount::multiply(saTakerGetsFunded, STAmount(CURRENCY_ONE, ACCOUNT_ONE, uOfferRate, -9)));
|
||||
|
||||
STAmount saOwnerBalance = saOwnerFunds-saOwnerPays;
|
||||
|
||||
umBalance[uOfferOwnerID] = saOwnerBalance;
|
||||
|
||||
if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
|
||||
{
|
||||
// Only provide funded offers and offers of the taker.
|
||||
jvOffers.append(jvOffer);
|
||||
}
|
||||
|
||||
if (!lesActive.dirNext(uTipIndex, sleOfferDir, uBookEntry, uOfferIndex))
|
||||
{
|
||||
bDirectAdvance = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsTRACE) << boost::str(boost::format("getBookPage: uOfferIndex=%s") % uOfferIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jvResult["offers"] = jvOffers;
|
||||
// jvResult["marker"] = Json::Value(Json::arrayValue);
|
||||
// jvResult["nodes"] = Json::Value(Json::arrayValue);
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "LedgerAcquire.h"
|
||||
#include "LedgerProposal.h"
|
||||
#include "JobQueue.h"
|
||||
#include "AcceptedLedger.h"
|
||||
|
||||
// Operations that clients may wish to perform against the network
|
||||
// Master operational handler, server sequencer, network tracker
|
||||
@@ -119,7 +120,6 @@ protected:
|
||||
boost::recursive_mutex mMonitorLock;
|
||||
subInfoMapType mSubAccount;
|
||||
subInfoMapType mSubRTAccount;
|
||||
|
||||
|
||||
subRpcMapType mRpcSubMap;
|
||||
|
||||
@@ -141,8 +141,8 @@ protected:
|
||||
|
||||
Json::Value pubBootstrapAccountInfo(Ledger::ref lpAccepted, const RippleAddress& naAccountID);
|
||||
|
||||
void pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta);
|
||||
void pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult,bool accepted,TransactionMetaSet::pointer& meta);
|
||||
void pubAcceptedTransaction(Ledger::ref alAccepted, const ALTransaction& alTransaction);
|
||||
void pubAccountTransaction(Ledger::ref lpCurrent, const ALTransaction& alTransaction);
|
||||
|
||||
void pubServer();
|
||||
|
||||
@@ -230,6 +230,12 @@ public:
|
||||
|
||||
Json::Value getOwnerInfo(Ledger::pointer lpLedger, const RippleAddress& naAccount);
|
||||
|
||||
//
|
||||
// Book functions
|
||||
//
|
||||
|
||||
void getBookPage(Ledger::pointer lpLedger, const uint160& uTakerPaysCurrencyID, const uint160& uTakerPaysIssuerID, const uint160& uTakerGetsCurrencyID, const uint160& uTakerGetsIssuerID, const uint160& uTakerID, const bool bProof, const unsigned int iLimit, const Json::Value& jvMarker, Json::Value& jvResult);
|
||||
|
||||
// raw object operations
|
||||
bool findRawLedger(const uint256& ledgerHash, std::vector<unsigned char>& rawLedger);
|
||||
bool findRawTransaction(const uint256& transactionHash, std::vector<unsigned char>& rawTransaction);
|
||||
@@ -301,7 +307,7 @@ public:
|
||||
// Monitoring: publisher side
|
||||
//
|
||||
void pubLedger(Ledger::ref lpAccepted);
|
||||
void pubProposedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult);
|
||||
void pubProposedTransaction(Ledger::ref lpCurrent, SerializedTransaction::ref stTxn, TER terResult);
|
||||
|
||||
|
||||
//
|
||||
|
||||
@@ -321,6 +321,7 @@ TER OfferCreateTransactor::doApply()
|
||||
cLog(lsWARNING) << "OfferCreate> " << mTxn.getJson(0);
|
||||
const uint32 uTxFlags = mTxn.getFlags();
|
||||
const bool bPassive = isSetBit(uTxFlags, tfPassive);
|
||||
const bool bMarket = isSetBit(uTxFlags, tfMarket);
|
||||
STAmount saTakerPays = mTxn.getFieldAmount(sfTakerPays);
|
||||
STAmount saTakerGets = mTxn.getFieldAmount(sfTakerGets);
|
||||
|
||||
@@ -457,9 +458,21 @@ TER OfferCreateTransactor::doApply()
|
||||
// cLog(lsWARNING) << "OfferCreate: takeOffers: uPaysIssuerID=" << RippleAddress::createHumanAccountID(uPaysIssuerID);
|
||||
// cLog(lsWARNING) << "OfferCreate: takeOffers: uGetsIssuerID=" << RippleAddress::createHumanAccountID(uGetsIssuerID);
|
||||
|
||||
if (tesSUCCESS != terResult
|
||||
|| !saTakerPays // Wants nothing more.
|
||||
if (tesSUCCESS != terResult)
|
||||
{
|
||||
// Fail as is.
|
||||
nothing();
|
||||
}
|
||||
else if (saTakerPays.isNegative() || saTakerGets.isNegative())
|
||||
{
|
||||
terResult = isSetBit(mParams, tapOPEN_LEDGER)
|
||||
? telFAILED_PROCESSING // Ledger is not final, can vote no.
|
||||
: tecFAILED_PROCESSING;
|
||||
}
|
||||
else if (
|
||||
!saTakerPays // Wants nothing more.
|
||||
|| !saTakerGets // Offering nothing more.
|
||||
|| bMarket // Do not persist.
|
||||
|| !mEngine->getNodes().accountFunds(mTxnAccountID, saTakerGets).isPositive() // Not funded.
|
||||
|| bUnfunded) // Consider unfunded.
|
||||
{
|
||||
|
||||
@@ -187,15 +187,14 @@ BookListeners::pointer OrderBookDB::getBookListeners(const uint160& currencyIn,
|
||||
*/
|
||||
// Based on the meta, send the meta to the streams that are listening
|
||||
// We need to determine which streams a given meta effects
|
||||
void OrderBookDB::processTxn(const SerializedTransaction& stTxn, TER terResult,
|
||||
TransactionMetaSet::pointer& meta, Json::Value& jvObj)
|
||||
void OrderBookDB::processTxn(Ledger::ref ledger, const ALTransaction& alTx, Json::Value& jvObj)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
if (terResult == tesSUCCESS)
|
||||
if (alTx.getResult() == tesSUCCESS)
|
||||
{
|
||||
// check if this is an offer or an offer cancel or a payment that consumes an offer
|
||||
//check to see what the meta looks like
|
||||
BOOST_FOREACH(STObject& node, meta->getNodes())
|
||||
BOOST_FOREACH(STObject& node, alTx.getMeta()->getNodes())
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include "Ledger.h"
|
||||
#include "AcceptedLedger.h"
|
||||
#include "OrderBook.h"
|
||||
|
||||
|
||||
@@ -66,7 +67,7 @@ public:
|
||||
const uint160& issuerIn, const uint160& issuerOut);
|
||||
|
||||
// see if this txn effects any orderbook
|
||||
void processTxn(const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta,Json::Value& jvObj);
|
||||
void processTxn(Ledger::ref ledger, const ALTransaction& alTx, Json::Value& jvObj);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@ void Peer::recvTransaction(ripple::TMTransaction& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
theApp->getJobQueue().addJob(jtTRANSACTION,
|
||||
theApp->getJobQueue().addJob(jtTRANSACTION, "recvTransction->checkTransaction",
|
||||
boost::bind(&checkTransaction, _1, flags, stx, boost::weak_ptr<Peer>(shared_from_this())));
|
||||
|
||||
#ifndef TRUST_NETWORK
|
||||
@@ -986,7 +986,7 @@ void Peer::recvPropose(const boost::shared_ptr<ripple::TMProposeSet>& packet)
|
||||
prevLedger.isNonZero() ? prevLedger : consensusLCL,
|
||||
set.proposeseq(), proposeHash, set.closetime(), signerPublic, suppression);
|
||||
|
||||
theApp->getJobQueue().addJob(isTrusted ? jtPROPOSAL_t : jtPROPOSAL_ut,
|
||||
theApp->getJobQueue().addJob(isTrusted ? jtPROPOSAL_t : jtPROPOSAL_ut, "recvPropose->checkPropose",
|
||||
boost::bind(&checkPropose, _1, packet, proposal, consensusLCL,
|
||||
mNodePublic, boost::weak_ptr<Peer>(shared_from_this())));
|
||||
}
|
||||
@@ -1062,7 +1062,7 @@ void Peer::recvValidation(const boost::shared_ptr<ripple::TMValidation>& packet)
|
||||
}
|
||||
|
||||
bool isTrusted = theApp->getUNL().nodeInUNL(val->getSignerPublic());
|
||||
theApp->getJobQueue().addJob(isTrusted ? jtVALIDATION_t : jtVALIDATION_ut,
|
||||
theApp->getJobQueue().addJob(isTrusted ? jtVALIDATION_t : jtVALIDATION_ut, "recvValidation->checkValidation",
|
||||
boost::bind(&checkValidation, _1, val, signingHash, isTrusted, packet,
|
||||
boost::weak_ptr<Peer>(shared_from_this())));
|
||||
}
|
||||
@@ -1299,7 +1299,7 @@ void Peer::recvProofWork(ripple::TMProofWork& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
theApp->getJobQueue().addJob(jtPROOFWORK,
|
||||
theApp->getJobQueue().addJob(jtPROOFWORK, "recvProof->doProof",
|
||||
boost::bind(&Peer::doProofOfWork, _1, boost::weak_ptr<Peer>(shared_from_this()), pow));
|
||||
|
||||
return;
|
||||
|
||||
@@ -19,12 +19,16 @@ Json::Value rpcError(int iError, Json::Value jvResult)
|
||||
{ rpcACT_MALFORMED, "actMalformed", "Account malformed." },
|
||||
{ rpcACT_NOT_FOUND, "actNotFound", "Account not found." },
|
||||
{ rpcBAD_BLOB, "badBlob", "Blob must be a non-empty hex string." },
|
||||
{ rpcBAD_ISSUER, "badIssuer", "Issuer account malformed." },
|
||||
{ rpcBAD_MARKET, "badMarket", "No such market." },
|
||||
{ rpcBAD_SECRET, "badSecret", "Secret does not match account." },
|
||||
{ rpcBAD_SEED, "badSeed", "Disallowed seed." },
|
||||
{ rpcBAD_SYNTAX, "badSyntax", "Syntax error." },
|
||||
{ rpcCOMMAND_MISSING, "commandMissing", "Missing command entry." },
|
||||
{ rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." },
|
||||
{ rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exist." },
|
||||
{ rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed." },
|
||||
{ rpcDST_ISR_MALFORMED, "dstIsrMalformed", "Destination issuer is malformed." },
|
||||
{ rpcFORBIDDEN, "forbidden", "Bad credentials." },
|
||||
{ rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." },
|
||||
{ rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." },
|
||||
@@ -60,7 +64,6 @@ Json::Value rpcError(int iError, Json::Value jvResult)
|
||||
{ rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." },
|
||||
{ rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided." },
|
||||
{ rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source account not found." },
|
||||
{ rpcBAD_SECRET, "badSecret", "Secret does not match account." },
|
||||
{ rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." },
|
||||
{ rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed." },
|
||||
{ rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed." },
|
||||
@@ -88,4 +91,9 @@ Json::Value rpcError(int iError, Json::Value jvResult)
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
bool isRpcError(Json::Value jvResult)
|
||||
{
|
||||
return jvResult.isObject() && jvResult.isMember("error");
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -45,11 +45,15 @@ enum {
|
||||
rpcACT_MALFORMED,
|
||||
rpcQUALITY_MALFORMED,
|
||||
rpcBAD_BLOB,
|
||||
rpcBAD_ISSUER,
|
||||
rpcBAD_MARKET,
|
||||
rpcBAD_SECRET,
|
||||
rpcBAD_SEED,
|
||||
rpcCOMMAND_MISSING,
|
||||
rpcDST_ACT_MALFORMED,
|
||||
rpcDST_ACT_MISSING,
|
||||
rpcDST_AMT_MALFORMED,
|
||||
rpcDST_ISR_MALFORMED,
|
||||
rpcGETS_ACT_MALFORMED,
|
||||
rpcGETS_AMT_MALFORMED,
|
||||
rpcHOST_IP_MALFORMED,
|
||||
@@ -67,7 +71,6 @@ enum {
|
||||
rpcSRC_AMT_MALFORMED,
|
||||
rpcSRC_CUR_MALFORMED,
|
||||
rpcSRC_ISR_MALFORMED,
|
||||
rpcBAD_SECRET,
|
||||
|
||||
// Internal error (should never happen)
|
||||
rpcINTERNAL, // Generic internal error.
|
||||
@@ -77,6 +80,8 @@ enum {
|
||||
rpcNO_GEN_DECRPYT,
|
||||
};
|
||||
|
||||
bool isRpcError(Json::Value jvResult);
|
||||
Json::Value rpcError(int iError, Json::Value jvResult=Json::Value(Json::objectValue));
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
|
||||
@@ -176,7 +176,7 @@ Json::Value RPCHandler::transactionSign(Json::Value jvRequest, bool bSubmit)
|
||||
}
|
||||
|
||||
Ledger::pointer lSnapshot = boost::make_shared<Ledger>(
|
||||
boost::ref(*theApp->getOPs().getCurrentLedger()), false);
|
||||
boost::ref(*mNetOps->getCurrentLedger()), false);
|
||||
{
|
||||
ScopedUnlock su(theApp->getMasterLock());
|
||||
Pathfinder pf(lSnapshot, raSrcAddressID, dstAccountID,
|
||||
@@ -558,18 +558,6 @@ Json::Value RPCHandler::accountFromString(Ledger::ref lrLedger, RippleAddress& n
|
||||
return Json::Value(Json::objectValue);
|
||||
}
|
||||
|
||||
Json::Value RPCHandler::doAcceptLedger(Json::Value jvRequest)
|
||||
{
|
||||
if (!theConfig.RUN_STANDALONE)
|
||||
return rpcError(rpcNOT_STANDALONE);
|
||||
|
||||
Json::Value jvResult(Json::objectValue);
|
||||
|
||||
jvResult["newLedger"] = theApp->getOPs().acceptLedger();
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
// {
|
||||
// ident : <indent>,
|
||||
// account_index : <index> // optional
|
||||
@@ -1033,6 +1021,106 @@ Json::Value RPCHandler::doAccountOffers(Json::Value jvRequest)
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
// {
|
||||
// "ledger_hash" : ledger, // Optional.
|
||||
// "ledger_index" : ledger_index, // Optional.
|
||||
// "taker_gets" : { "currency": currency, "issuer" : address },
|
||||
// "taker_pays" : { "currency": currency, "issuer" : address },
|
||||
// "taker" : address, // Optional.
|
||||
// "marker" : element, // Optional.
|
||||
// "limit" : integer, // Optional.
|
||||
// "proof" : boolean // Defaults to false.
|
||||
// }
|
||||
Json::Value RPCHandler::doBookOffers(Json::Value jvRequest)
|
||||
{
|
||||
Ledger::pointer lpLedger;
|
||||
Json::Value jvResult = lookupLedger(jvRequest, lpLedger);
|
||||
|
||||
if (!lpLedger)
|
||||
return jvResult;
|
||||
|
||||
ScopedUnlock su(theApp->getMasterLock());
|
||||
|
||||
if (!jvRequest.isMember("taker_pays") || !jvRequest.isMember("taker_gets"))
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
|
||||
uint160 uTakerPaysCurrencyID;
|
||||
uint160 uTakerPaysIssuerID;
|
||||
Json::Value jvTakerPays = jvRequest["taker_pays"];
|
||||
|
||||
// Parse mandatory currency.
|
||||
if (!jvTakerPays.isMember("currency")
|
||||
|| !STAmount::currencyFromString(uTakerPaysCurrencyID, jvTakerPays["currency"].asString()))
|
||||
{
|
||||
cLog(lsINFO) << "Bad taker_pays currency.";
|
||||
|
||||
return rpcError(rpcSRC_CUR_MALFORMED);
|
||||
}
|
||||
// Parse optional issuer.
|
||||
else if (((jvTakerPays.isMember("issuer"))
|
||||
&& (!jvTakerPays["issuer"].isString()
|
||||
|| !STAmount::issuerFromString(uTakerPaysIssuerID, jvTakerPays["issuer"].asString())))
|
||||
// Don't allow illegal issuers.
|
||||
|| (!uTakerPaysCurrencyID != !uTakerPaysIssuerID)
|
||||
|| ACCOUNT_ONE == uTakerPaysIssuerID)
|
||||
{
|
||||
cLog(lsINFO) << "Bad taker_pays issuer.";
|
||||
|
||||
return rpcError(rpcSRC_ISR_MALFORMED);
|
||||
}
|
||||
|
||||
uint160 uTakerGetsCurrencyID;
|
||||
uint160 uTakerGetsIssuerID;
|
||||
Json::Value jvTakerGets = jvRequest["taker_gets"];
|
||||
|
||||
// Parse mandatory currency.
|
||||
if (!jvTakerGets.isMember("currency")
|
||||
|| !STAmount::currencyFromString(uTakerGetsCurrencyID, jvTakerGets["currency"].asString()))
|
||||
{
|
||||
cLog(lsINFO) << "Bad taker_pays currency.";
|
||||
|
||||
return rpcError(rpcSRC_CUR_MALFORMED);
|
||||
}
|
||||
// Parse optional issuer.
|
||||
else if (((jvTakerGets.isMember("issuer"))
|
||||
&& (!jvTakerGets["issuer"].isString()
|
||||
|| !STAmount::issuerFromString(uTakerGetsIssuerID, jvTakerGets["issuer"].asString())))
|
||||
// Don't allow illegal issuers.
|
||||
|| (!uTakerGetsCurrencyID != !uTakerGetsIssuerID)
|
||||
|| ACCOUNT_ONE == uTakerGetsIssuerID)
|
||||
{
|
||||
cLog(lsINFO) << "Bad taker_gets issuer.";
|
||||
|
||||
return rpcError(rpcDST_ISR_MALFORMED);
|
||||
}
|
||||
|
||||
if (uTakerPaysCurrencyID == uTakerGetsCurrencyID
|
||||
&& uTakerPaysIssuerID == uTakerGetsIssuerID) {
|
||||
cLog(lsINFO) << "taker_gets same as taker_pays.";
|
||||
|
||||
return rpcError(rpcBAD_MARKET);
|
||||
}
|
||||
|
||||
RippleAddress raTakerID;
|
||||
|
||||
if (!jvRequest.isMember("taker"))
|
||||
{
|
||||
raTakerID.setAccountID(ACCOUNT_ONE);
|
||||
}
|
||||
else if (!raTakerID.setAccountID(jvRequest["taker"].asString()))
|
||||
{
|
||||
return rpcError(rpcBAD_ISSUER);
|
||||
}
|
||||
|
||||
const bool bProof = jvRequest.isMember("proof");
|
||||
const unsigned int iLimit = jvRequest.isMember("limit") ? jvRequest["limit"].asUInt() : 0;
|
||||
const Json::Value jvMarker = jvRequest.isMember("marker") ? jvRequest["marker"] : Json::Value(Json::nullValue);
|
||||
|
||||
mNetOps->getBookPage(lpLedger, uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID, raTakerID.getAccountID(), bProof, iLimit, jvMarker, jvResult);
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
// Result:
|
||||
// {
|
||||
// random: <uint256>
|
||||
@@ -1366,7 +1454,7 @@ Json::Value RPCHandler::doConsensusInfo(Json::Value)
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
|
||||
ret["info"] = theApp->getOPs().getConsensusInfo();
|
||||
ret["info"] = mNetOps->getConsensusInfo();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1375,7 +1463,7 @@ Json::Value RPCHandler::doServerInfo(Json::Value)
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
|
||||
ret["info"] = theApp->getOPs().getServerInfo(true, mRole == ADMIN);
|
||||
ret["info"] = mNetOps->getServerInfo(true, mRole == ADMIN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1384,7 +1472,7 @@ Json::Value RPCHandler::doServerState(Json::Value)
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
|
||||
ret["state"] = theApp->getOPs().getServerInfo(false, mRole == ADMIN);
|
||||
ret["state"] = mNetOps->getServerInfo(false, mRole == ADMIN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1453,7 +1541,7 @@ Json::Value RPCHandler::doTx(Json::Value jvRequest)
|
||||
|
||||
if (txn->getLedger() != 0)
|
||||
{
|
||||
Ledger::pointer lgr = theApp->getOPs().getLedgerBySeq(txn->getLedger());
|
||||
Ledger::pointer lgr = mNetOps->getLedgerBySeq(txn->getLedger());
|
||||
if (lgr)
|
||||
{
|
||||
bool okay = false;
|
||||
@@ -1476,7 +1564,7 @@ Json::Value RPCHandler::doTx(Json::Value jvRequest)
|
||||
}
|
||||
}
|
||||
if (okay)
|
||||
ret["validated"] = theApp->getOPs().isValidated(lgr);
|
||||
ret["validated"] = mNetOps->isValidated(lgr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1594,7 +1682,7 @@ Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest)
|
||||
try
|
||||
{
|
||||
#endif
|
||||
int vl = theApp->getOPs().getValidatedSeq();
|
||||
int vl = mNetOps->getValidatedSeq();
|
||||
ScopedUnlock su(theApp->getMasterLock());
|
||||
|
||||
Json::Value ret(Json::objectValue);
|
||||
@@ -1613,7 +1701,7 @@ Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest)
|
||||
obj["inLedger"] = it->get<2>();
|
||||
if (it->get<2>() > vl)
|
||||
obj["validated"] = false;
|
||||
else if (theApp->getOPs().haveLedger(it->get<2>()))
|
||||
else if (mNetOps->haveLedger(it->get<2>()))
|
||||
obj["validated"] = true;
|
||||
ret["transactions"].append(obj);
|
||||
}
|
||||
@@ -1634,7 +1722,7 @@ Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest)
|
||||
uint32 s = it->second->getLgrSeq();
|
||||
if (s > vl)
|
||||
obj["validated"] = false;
|
||||
else if (theApp->getOPs().haveLedger(s))
|
||||
else if (mNetOps->haveLedger(s))
|
||||
obj["validated"] = true;
|
||||
}
|
||||
|
||||
@@ -2807,11 +2895,11 @@ Json::Value RPCHandler::doCommand(const Json::Value& jvRequest, int iRole)
|
||||
unsigned int iOptions;
|
||||
} commandsA[] = {
|
||||
// Request-response methods
|
||||
{ "accept_ledger", &RPCHandler::doAcceptLedger, true, optCurrent },
|
||||
{ "account_info", &RPCHandler::doAccountInfo, false, optCurrent },
|
||||
{ "account_lines", &RPCHandler::doAccountLines, false, optCurrent },
|
||||
{ "account_offers", &RPCHandler::doAccountOffers, false, optCurrent },
|
||||
{ "account_tx", &RPCHandler::doAccountTransactions, false, optNetwork },
|
||||
{ "book_offers", &RPCHandler::doBookOffers, false, optCurrent },
|
||||
{ "connect", &RPCHandler::doConnect, true, optNone },
|
||||
{ "consensus_info", &RPCHandler::doConsensusInfo, true, optNone },
|
||||
{ "get_counts", &RPCHandler::doGetCounts, true, optNone },
|
||||
@@ -2888,6 +2976,8 @@ Json::Value RPCHandler::doCommand(const Json::Value& jvRequest, int iRole)
|
||||
&& mNetOps->getOperatingMode() != NetworkOPs::omTRACKING
|
||||
&& mNetOps->getOperatingMode() != NetworkOPs::omFULL)
|
||||
{
|
||||
cLog(lsINFO) << "Insufficient network mode for RPC: " << mNetOps->strOperatingMode();
|
||||
|
||||
return rpcError(rpcNO_NETWORK);
|
||||
}
|
||||
// XXX Should verify we have a current ledger.
|
||||
|
||||
@@ -43,12 +43,11 @@ class RPCHandler
|
||||
|
||||
Json::Value accountFromString(Ledger::ref lrLedger, RippleAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex, const bool bStrict);
|
||||
|
||||
Json::Value doAcceptLedger(Json::Value jvRequest);
|
||||
|
||||
Json::Value doAccountInfo(Json::Value params);
|
||||
Json::Value doAccountLines(Json::Value params);
|
||||
Json::Value doAccountOffers(Json::Value params);
|
||||
Json::Value doAccountTransactions(Json::Value params);
|
||||
Json::Value doBookOffers(Json::Value params);
|
||||
Json::Value doConnect(Json::Value params);
|
||||
Json::Value doConsensusInfo(Json::Value params);
|
||||
#if ENABLE_INSECURE
|
||||
|
||||
@@ -29,6 +29,12 @@ RPCSub::RPCSub(const std::string& strUrl, const std::string& strUsername, const
|
||||
|
||||
if (mPort < 0)
|
||||
mPort = mSSL ? 443 : 80;
|
||||
|
||||
cLog(lsINFO) << boost::str(boost::format("callRPC sub: ip='%s' port=%d ssl=%d path='%s'")
|
||||
% mIp
|
||||
% mPort
|
||||
% mSSL
|
||||
% mPath);
|
||||
}
|
||||
|
||||
// XXX Could probably create a bunch of send jobs in a single get of the lock.
|
||||
|
||||
@@ -325,10 +325,10 @@ void PathState::setExpanded(
|
||||
uMaxCurrencyID, // Max specifes the currency.
|
||||
uSenderIssuerID);
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: pushed: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uSenderID)
|
||||
% STAmount::createHumanCurrency(uMaxCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uSenderIssuerID));
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: pushed: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uSenderID)
|
||||
% STAmount::createHumanCurrency(uMaxCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uSenderIssuerID));
|
||||
|
||||
if (tesSUCCESS == terStatus
|
||||
&& uMaxIssuerID != uSenderIssuerID) { // Issuer was not same as sender.
|
||||
@@ -347,19 +347,19 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: pushed: account=%s currenc
|
||||
: uOutIssuerID // Use implied node.
|
||||
: ACCOUNT_XRP;
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: implied check: uNxtCurrencyID=%s uNxtAccountID=%s")
|
||||
% RippleAddress::createHumanAccountID(uNxtCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uNxtAccountID));
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: implied check: uNxtCurrencyID=%s uNxtAccountID=%s")
|
||||
% RippleAddress::createHumanAccountID(uNxtCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uNxtAccountID));
|
||||
|
||||
// Can't just use push implied, because it can't compensate for next account.
|
||||
if (!uNxtCurrencyID // Next is XRP, offer next. Must go through issuer.
|
||||
|| uMaxCurrencyID != uNxtCurrencyID // Next is different currency, offer next...
|
||||
|| uMaxIssuerID != uNxtAccountID) // Next is not implied issuer
|
||||
{
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: sender implied: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uMaxIssuerID)
|
||||
% RippleAddress::createHumanAccountID(uMaxCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uMaxIssuerID));
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: sender implied: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uMaxIssuerID)
|
||||
% RippleAddress::createHumanAccountID(uMaxCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uMaxIssuerID));
|
||||
// Add account implied by SendMax.
|
||||
terStatus = pushNode(
|
||||
!!uMaxCurrencyID
|
||||
@@ -375,7 +375,7 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: sender implied: account=%s
|
||||
{
|
||||
if (tesSUCCESS == terStatus)
|
||||
{
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: element in path:"));
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: element in path:"));
|
||||
terStatus = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID());
|
||||
}
|
||||
}
|
||||
@@ -389,10 +389,10 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: element in path:"));
|
||||
|| pnPrv.uAccountID != uOutIssuerID)) // Need the implied issuer.
|
||||
{
|
||||
// Add implied account.
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: receiver implied: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uOutIssuerID)
|
||||
% RippleAddress::createHumanAccountID(uOutCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uOutIssuerID));
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: receiver implied: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uOutIssuerID)
|
||||
% RippleAddress::createHumanAccountID(uOutCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uOutIssuerID));
|
||||
terStatus = pushNode(
|
||||
!!uOutCurrencyID
|
||||
? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer
|
||||
@@ -2494,9 +2494,9 @@ int iIndex = 0;
|
||||
|
||||
pspExpanded->setExpanded(lesActive, spPath, uDstAccountID, uSrcAccountID);
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Build path: %d: status: %s")
|
||||
% ++iIndex
|
||||
% transToken(pspExpanded->terStatus));
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Build path: %d: status: %s")
|
||||
% ++iIndex
|
||||
% transToken(pspExpanded->terStatus));
|
||||
|
||||
// Return, if the path specification was malformed.
|
||||
if (isTemMalformed(pspExpanded->terStatus))
|
||||
@@ -2550,17 +2550,18 @@ int iPass = 0;
|
||||
pspCur->saOutAct = saDstAmountAct;
|
||||
|
||||
rc.pathNext(pspCur, bMultiQuality, lesCheckpoint, lesActive); // Compute increment.
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: AFTER: mIndex=%d uQuality=%d rate=%s")
|
||||
% pspCur->mIndex
|
||||
% pspCur->uQuality
|
||||
% STAmount::saFromRate(pspCur->uQuality));
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: AFTER: mIndex=%d uQuality=%d rate=%s")
|
||||
% pspCur->mIndex
|
||||
% pspCur->uQuality
|
||||
% STAmount::saFromRate(pspCur->uQuality));
|
||||
|
||||
if (!pspCur->uQuality) {
|
||||
// Path was dry.
|
||||
|
||||
++iDry;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
tLog(!pspCur->saInPass || !pspCur->saOutPass, lsDEBUG)
|
||||
<< boost::str(boost::format("rippleCalc: better: uQuality=%s saInPass=%s saOutPass=%s")
|
||||
% STAmount::saFromRate(pspCur->uQuality)
|
||||
@@ -2586,15 +2587,18 @@ int iPass = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: Pass: %d Dry: %d Paths: %d") % ++iPass % iDry % vpsExpanded.size());
|
||||
BOOST_FOREACH(PathState::ref pspCur, vpsExpanded)
|
||||
if (sLog(lsDEBUG))
|
||||
{
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: %d rate: %s quality:%d best: %d consumed: %d")
|
||||
% pspCur->mIndex
|
||||
% STAmount::saFromRate(pspCur->uQuality)
|
||||
% pspCur->uQuality
|
||||
% (iBest == pspCur->getIndex())
|
||||
% pspCur->bConsumed);
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: Pass: %d Dry: %d Paths: %d") % ++iPass % iDry % vpsExpanded.size());
|
||||
BOOST_FOREACH(PathState::ref pspCur, vpsExpanded)
|
||||
{
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: %d rate: %s quality:%d best: %d consumed: %d")
|
||||
% pspCur->mIndex
|
||||
% STAmount::saFromRate(pspCur->uQuality)
|
||||
% pspCur->uQuality
|
||||
% (iBest == pspCur->getIndex())
|
||||
% pspCur->bConsumed);
|
||||
}
|
||||
}
|
||||
|
||||
if (iBest >= 0)
|
||||
|
||||
@@ -23,8 +23,14 @@ DECLARE_INSTANCE(SHAMapTreeNode);
|
||||
|
||||
void SHAMapNode::setHash() const
|
||||
{
|
||||
std::size_t h = theApp->getNonceST() + mDepth;
|
||||
std::size_t h = theApp->getNonceST() + (mDepth * 0x9e3779b9);
|
||||
mHash = mNodeID.hash_combine(h);
|
||||
#if 0
|
||||
const unsigned int *ptr = reinterpret_cast<const unsigned int *>(mNodeID.begin());
|
||||
for (int i = (mDepth + 3) / 4; i != 0; --i)
|
||||
boost::hash_combine(h, *ptr++);
|
||||
mHash = h;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::size_t hash_value(const SHAMapNode& mn)
|
||||
@@ -64,6 +70,7 @@ SHAMap::SHAMap(SHAMapType t, const uint256& hash) : mSeq(1), mState(smsSynching)
|
||||
SHAMap::pointer SHAMap::snapShot(bool isMutable)
|
||||
{ // Return a new SHAMap that is an immutable snapshot of this one
|
||||
// Initially nodes are shared, but CoW is forced on both ledgers
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
SHAMap::pointer ret = boost::make_shared<SHAMap>(mType);
|
||||
SHAMap& newMap = *ret;
|
||||
newMap.mSeq = ++mSeq;
|
||||
@@ -158,10 +165,11 @@ SHAMapTreeNode::pointer SHAMap::walkTo(const uint256& id, bool modify)
|
||||
while (!inNode->isLeaf())
|
||||
{
|
||||
int branch = inNode->selectBranch(id);
|
||||
if (inNode->isEmptyBranch(branch))
|
||||
return inNode;
|
||||
uint256 childHash = inNode->getChildHash(branch);
|
||||
|
||||
if (childHash.isZero())
|
||||
return inNode;
|
||||
|
||||
try
|
||||
{
|
||||
inNode = getNode(inNode->getChildNodeID(branch), childHash, false);
|
||||
@@ -205,7 +213,6 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has
|
||||
std::cerr << "ID: " << id << std::endl;
|
||||
std::cerr << "TgtHash " << hash << std::endl;
|
||||
std::cerr << "NodHash " << node->getNodeHash() << std::endl;
|
||||
dump();
|
||||
throw std::runtime_error("invalid node");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -43,20 +43,21 @@ public:
|
||||
|
||||
SHAMapNode() : mDepth(0), mHash(0) { ; }
|
||||
SHAMapNode(int depth, const uint256& hash);
|
||||
virtual ~SHAMapNode() { ; }
|
||||
|
||||
int getDepth() const { return mDepth; }
|
||||
const uint256& getNodeID() const { return mNodeID; }
|
||||
bool isValid() const { return (mDepth >= 0) && (mDepth < 64); }
|
||||
bool isValid() const { return (mDepth >= 0) && (mDepth < 64); }
|
||||
bool isRoot() const { return mDepth == 0; }
|
||||
size_t getHash() const { if (mHash == 0) setHash(); return mHash; }
|
||||
|
||||
virtual bool isPopulated() const { return false; }
|
||||
virtual bool isPopulated() const { return false; }
|
||||
|
||||
SHAMapNode getParentNodeID() const
|
||||
{
|
||||
assert(mDepth);
|
||||
return SHAMapNode(mDepth - 1, mNodeID);
|
||||
}
|
||||
|
||||
SHAMapNode getChildNodeID(int m) const;
|
||||
int selectBranch(const uint256& hash) const;
|
||||
|
||||
@@ -68,7 +69,6 @@ public:
|
||||
bool operator!=(const uint256&) const;
|
||||
bool operator<=(const SHAMapNode&) const;
|
||||
bool operator>=(const SHAMapNode&) const;
|
||||
bool isRoot() const { return mDepth == 0; }
|
||||
|
||||
virtual std::string getString() const;
|
||||
void dump() const;
|
||||
|
||||
@@ -51,7 +51,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type, const uint256
|
||||
|
||||
SerializedLedgerEntry::pointer SerializedLedgerEntry::getMutable() const
|
||||
{
|
||||
SerializedLedgerEntry::pointer ret = boost::make_shared<SerializedLedgerEntry>(boost::ref(*this));
|
||||
SerializedLedgerEntry::pointer ret = boost::make_shared<SerializedLedgerEntry>(boost::cref(*this));
|
||||
ret->mMutable = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -130,14 +130,29 @@ std::auto_ptr<SerializedType> STObject::makeDeserializedObject(SerializedTypeID
|
||||
}
|
||||
}
|
||||
|
||||
void STObject::set(const std::vector<SOElement::ref>& type)
|
||||
void SOTemplate::push_back(const SOElement &r)
|
||||
{
|
||||
if (mIndex.empty())
|
||||
mIndex.resize(SField::getNumFields() + 1, -1);
|
||||
assert(r.e_field.getNum() < mIndex.size());
|
||||
assert(getIndex(r.e_field) == -1);
|
||||
mIndex[r.e_field.getNum()] = mTypes.size();
|
||||
mTypes.push_back(new SOElement(r));
|
||||
}
|
||||
|
||||
int SOTemplate::getIndex(SField::ref f) const
|
||||
{
|
||||
assert(f.getNum() < mIndex.size());
|
||||
return mIndex[f.getNum()];
|
||||
}
|
||||
|
||||
void STObject::set(const SOTemplate& type)
|
||||
{
|
||||
mData.clear();
|
||||
mType.clear();
|
||||
mType = &type;
|
||||
|
||||
BOOST_FOREACH(SOElement::ref elem, type)
|
||||
BOOST_FOREACH(const SOElement* elem, type.peek())
|
||||
{
|
||||
mType.push_back(elem);
|
||||
if (elem->flags != SOE_REQUIRED)
|
||||
giveObject(makeNonPresentObject(elem->e_field));
|
||||
else
|
||||
@@ -145,15 +160,14 @@ void STObject::set(const std::vector<SOElement::ref>& type)
|
||||
}
|
||||
}
|
||||
|
||||
bool STObject::setType(const std::vector<SOElement::ref> &type)
|
||||
bool STObject::setType(const SOTemplate &type)
|
||||
{
|
||||
boost::ptr_vector<SerializedType> newData(type.size());
|
||||
boost::ptr_vector<SerializedType> newData(type.peek().size());
|
||||
bool valid = true;
|
||||
|
||||
mType.clear();
|
||||
mType.reserve(type.size());
|
||||
mType = &type;
|
||||
|
||||
BOOST_FOREACH(SOElement::ref elem, type)
|
||||
BOOST_FOREACH(const SOElement* elem, type.peek())
|
||||
{
|
||||
bool match = false;
|
||||
for (boost::ptr_vector<SerializedType>::iterator it = mData.begin(); it != mData.end(); ++it)
|
||||
@@ -180,8 +194,6 @@ bool STObject::setType(const std::vector<SOElement::ref> &type)
|
||||
}
|
||||
newData.push_back(makeNonPresentObject(elem->e_field));
|
||||
}
|
||||
|
||||
mType.push_back(elem);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const SerializedType& t, mData)
|
||||
@@ -201,7 +213,7 @@ bool STObject::setType(const std::vector<SOElement::ref> &type)
|
||||
bool STObject::isValidForType()
|
||||
{
|
||||
boost::ptr_vector<SerializedType>::iterator it = mData.begin();
|
||||
BOOST_FOREACH(SOElement::ref elem, mType)
|
||||
BOOST_FOREACH(const SOElement* elem, mType->peek())
|
||||
{
|
||||
if (it == mData.end())
|
||||
return false;
|
||||
@@ -215,14 +227,9 @@ bool STObject::isValidForType()
|
||||
|
||||
bool STObject::isFieldAllowed(SField::ref field)
|
||||
{
|
||||
if (isFree())
|
||||
if (mType == NULL)
|
||||
return true;
|
||||
BOOST_FOREACH(SOElement::ref elem, mType)
|
||||
{ // are any required elemnents missing
|
||||
if (elem->e_field == field)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return mType->getIndex(field) != -1;
|
||||
}
|
||||
|
||||
bool STObject::set(SerializerIterator& sit, int depth)
|
||||
@@ -361,6 +368,9 @@ uint256 STObject::getSigningHash(uint32 prefix) const
|
||||
|
||||
int STObject::getFieldIndex(SField::ref field) const
|
||||
{
|
||||
if (mType != NULL)
|
||||
return mType->getIndex(field);
|
||||
|
||||
int i = 0;
|
||||
BOOST_FOREACH(const SerializedType& elem, mData)
|
||||
{
|
||||
@@ -1243,11 +1253,11 @@ BOOST_AUTO_TEST_CASE( FieldManipulation_test )
|
||||
SField sfTestU32(STI_UINT32, 255, "TestU32");
|
||||
SField sfTestObject(STI_OBJECT, 255, "TestObject");
|
||||
|
||||
std::vector<SOElement::ref> elements;
|
||||
elements.push_back(new SOElement(sfFlags, SOE_REQUIRED));
|
||||
elements.push_back(new SOElement(sfTestVL, SOE_REQUIRED));
|
||||
elements.push_back(new SOElement(sfTestH256, SOE_OPTIONAL));
|
||||
elements.push_back(new SOElement(sfTestU32, SOE_REQUIRED));
|
||||
SOTemplate elements;
|
||||
elements.push_back(SOElement(sfFlags, SOE_REQUIRED));
|
||||
elements.push_back(SOElement(sfTestVL, SOE_REQUIRED));
|
||||
elements.push_back(SOElement(sfTestH256, SOE_OPTIONAL));
|
||||
elements.push_back(SOElement(sfTestU32, SOE_REQUIRED));
|
||||
|
||||
STObject object1(elements, sfTestObject);
|
||||
STObject object2(object1);
|
||||
|
||||
@@ -18,32 +18,44 @@ DEFINE_INSTANCE(SerializedArray);
|
||||
class SOElement
|
||||
{ // An element in the description of a serialized object
|
||||
public:
|
||||
typedef SOElement const * ref; // used to point to one element
|
||||
SField::ref e_field;
|
||||
const SOE_Flags flags;
|
||||
|
||||
SField::ref e_field;
|
||||
const SOE_Flags flags;
|
||||
SOElement(SField::ref fi, SOE_Flags fl) : e_field(fi), flags(fl) { ; }
|
||||
};
|
||||
|
||||
SOElement(SField::ref fi, SOE_Flags fl) : e_field(fi), flags(fl) { ; }
|
||||
class SOTemplate
|
||||
{
|
||||
protected:
|
||||
std::vector<const SOElement*> mTypes;
|
||||
std::vector<int> mIndex; // field num -> index
|
||||
|
||||
public:
|
||||
SOTemplate() { ; }
|
||||
const std::vector<const SOElement*>& peek() const { return mTypes; }
|
||||
void push_back(const SOElement& r);
|
||||
int getIndex(SField::ref) const;
|
||||
};
|
||||
|
||||
class STObject : public SerializedType, private IS_INSTANCE(SerializedObject)
|
||||
{
|
||||
protected:
|
||||
boost::ptr_vector<SerializedType> mData;
|
||||
std::vector<SOElement::ref> mType;
|
||||
const SOTemplate* mType;
|
||||
|
||||
STObject* duplicate() const { return new STObject(*this); }
|
||||
STObject(SField::ref name, boost::ptr_vector<SerializedType>& data) : SerializedType(name) { mData.swap(data); }
|
||||
STObject(SField::ref name, boost::ptr_vector<SerializedType>& data) : SerializedType(name), mType(NULL)
|
||||
{ mData.swap(data); }
|
||||
|
||||
public:
|
||||
STObject() { ; }
|
||||
STObject() : mType(NULL) { ; }
|
||||
|
||||
STObject(SField::ref name) : SerializedType(name) { ; }
|
||||
STObject(SField::ref name) : SerializedType(name), mType(NULL) { ; }
|
||||
|
||||
STObject(const std::vector<SOElement::ref>& type, SField::ref name) : SerializedType(name)
|
||||
STObject(const SOTemplate& type, SField::ref name) : SerializedType(name)
|
||||
{ set(type); }
|
||||
|
||||
STObject(const std::vector<SOElement::ref>& type, SerializerIterator& sit, SField::ref name) : SerializedType(name)
|
||||
STObject(const SOTemplate& type, SerializerIterator& sit, SField::ref name) : SerializedType(name)
|
||||
{ set(sit); setType(type); }
|
||||
|
||||
std::auto_ptr<STObject> oClone() const { return std::auto_ptr<STObject>(new STObject(*this)); }
|
||||
@@ -54,12 +66,12 @@ public:
|
||||
|
||||
static std::auto_ptr<SerializedType> deserialize(SerializerIterator& sit, SField::ref name);
|
||||
|
||||
bool setType(const std::vector<SOElement::ref>& type);
|
||||
bool setType(const SOTemplate& type);
|
||||
bool isValidForType();
|
||||
bool isFieldAllowed(SField::ref);
|
||||
bool isFree() const { return mType.empty(); }
|
||||
bool isFree() const { return mType == NULL; }
|
||||
|
||||
void set(const std::vector<SOElement::ref>&);
|
||||
void set(const SOTemplate&);
|
||||
bool set(SerializerIterator& u, int depth = 0);
|
||||
|
||||
virtual SerializedTypeID getSType() const { return STI_OBJECT; }
|
||||
|
||||
@@ -233,7 +233,7 @@ std::string SerializedTransaction::getSQLInsertReplaceHeader()
|
||||
|
||||
std::string SerializedTransaction::getMetaSQLInsertHeader()
|
||||
{
|
||||
return "INSERT INTO Transactions " + getMetaSQLValueHeader() + " VALUES ";
|
||||
return "INSERT OR REPLACE INTO Transactions " + getMetaSQLValueHeader() + " VALUES ";
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getSQL(uint32 inLedger, char status) const
|
||||
|
||||
@@ -6,25 +6,22 @@
|
||||
|
||||
DECLARE_INSTANCE(SerializedValidation);
|
||||
|
||||
std::vector<SOElement::ref> sValidationFormat;
|
||||
SOTemplate sValidationFormat;
|
||||
|
||||
static bool SVFInit()
|
||||
void SVFInit()
|
||||
{
|
||||
sValidationFormat.push_back(new SOElement(sfFlags, SOE_REQUIRED));
|
||||
sValidationFormat.push_back(new SOElement(sfLedgerHash, SOE_REQUIRED));
|
||||
sValidationFormat.push_back(new SOElement(sfLedgerSequence, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(new SOElement(sfCloseTime, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(new SOElement(sfLoadFee, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(new SOElement(sfBaseFee, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(new SOElement(sfFeatures, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(new SOElement(sfSigningTime, SOE_REQUIRED));
|
||||
sValidationFormat.push_back(new SOElement(sfSigningPubKey, SOE_REQUIRED));
|
||||
sValidationFormat.push_back(new SOElement(sfSignature, SOE_OPTIONAL));
|
||||
return true;
|
||||
sValidationFormat.push_back(SOElement(sfFlags, SOE_REQUIRED));
|
||||
sValidationFormat.push_back(SOElement(sfLedgerHash, SOE_REQUIRED));
|
||||
sValidationFormat.push_back(SOElement(sfLedgerSequence, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(SOElement(sfCloseTime, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(SOElement(sfLoadFee, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(SOElement(sfBaseFee, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(SOElement(sfFeatures, SOE_OPTIONAL));
|
||||
sValidationFormat.push_back(SOElement(sfSigningTime, SOE_REQUIRED));
|
||||
sValidationFormat.push_back(SOElement(sfSigningPubKey, SOE_REQUIRED));
|
||||
sValidationFormat.push_back(SOElement(sfSignature, SOE_OPTIONAL));
|
||||
};
|
||||
|
||||
bool SVFinitComplete = SVFInit();
|
||||
|
||||
const uint32 SerializedValidation::sFullFlag = 0x1;
|
||||
|
||||
SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSignature)
|
||||
|
||||
@@ -476,8 +476,8 @@ int Serializer::encodeLengthLength(int length)
|
||||
if (length < 0) throw std::overflow_error("len<0");
|
||||
if (length <= 192) return 1;
|
||||
if (length <= 12480) return 2;
|
||||
if (length >= 918744) return 3;
|
||||
throw std::overflow_error("len>918644");
|
||||
if (length <= 918744) return 3;
|
||||
throw std::overflow_error("len>918744");
|
||||
}
|
||||
|
||||
int Serializer::decodeLengthLength(int b1)
|
||||
|
||||
@@ -116,7 +116,11 @@ bool Transaction::sign(const RippleAddress& naAccountPrivate)
|
||||
|
||||
bool Transaction::checkSign() const
|
||||
{
|
||||
assert(mFromPubKey.isValid());
|
||||
if (!mFromPubKey.isValid())
|
||||
{
|
||||
Log(lsWARNING) << "Transaction has bad source public key";
|
||||
return false;
|
||||
}
|
||||
return mTransaction->checkSign(mFromPubKey);
|
||||
}
|
||||
|
||||
@@ -245,16 +249,6 @@ Transaction::pointer Transaction::load(const uint256& id)
|
||||
return transactionFromSQL(sql);
|
||||
}
|
||||
|
||||
Transaction::pointer Transaction::findFrom(const RippleAddress& fromID, uint32 seq)
|
||||
{
|
||||
std::string sql = "SELECT LedgerSeq,Status,RawTxn FROM Transactions WHERE FromID='";
|
||||
sql.append(fromID.humanAccountID());
|
||||
sql.append("' AND FromSeq='");
|
||||
sql.append(boost::lexical_cast<std::string>(seq));
|
||||
sql.append("';");
|
||||
return transactionFromSQL(sql);
|
||||
}
|
||||
|
||||
bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedgerSeq,
|
||||
bool checkFirstTransactions, bool checkSecondTransactions, const SHAMap::SHAMapDiff& inMap,
|
||||
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >& outMap)
|
||||
|
||||
@@ -99,7 +99,6 @@ public:
|
||||
// database functions
|
||||
void save();
|
||||
static Transaction::pointer load(const uint256& id);
|
||||
static Transaction::pointer findFrom(const RippleAddress& fromID, uint32 seq);
|
||||
|
||||
// conversion function
|
||||
static bool convertToTransactions(uint32 ourLedgerSeq, uint32 otherLedgerSeq,
|
||||
|
||||
@@ -10,6 +10,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman)
|
||||
} transResultInfoA[] = {
|
||||
{ tecCLAIM, "tecCLAIM", "Fee claimed. Sequence used. No action." },
|
||||
{ tecDIR_FULL, "tecDIR_FULL", "Can not add entry to full directory." },
|
||||
{ tecFAILED_PROCESSING, "tecFAILED_PROCESSING", "Failed to correctly process transaction." },
|
||||
{ tecINSUF_RESERVE_LINE, "tecINSUF_RESERVE_LINE", "Insufficent reserve to add trust line." },
|
||||
{ tecINSUF_RESERVE_OFFER, "tecINSUF_RESERVE_OFFER", "Insufficent reserve to create offer." },
|
||||
{ tecNO_DST, "tecNO_DST", "Destination does not exist. Send XRP to create it." },
|
||||
@@ -42,6 +43,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman)
|
||||
{ telBAD_DOMAIN, "telBAD_DOMAIN", "Domain too long." },
|
||||
{ telBAD_PATH_COUNT, "telBAD_PATH_COUNT", "Malformed: Too many paths." },
|
||||
{ telBAD_PUBLIC_KEY, "telBAD_PUBLIC_KEY", "Public key too long." },
|
||||
{ telFAILED_PROCESSING, "telFAILED_PROCESSING", "Failed to correctly process transaction." },
|
||||
{ telINSUF_FEE_P, "telINSUF_FEE_P", "Fee insufficient." },
|
||||
{ telNO_DST_PARTIAL, "telNO_DST_PARTIAL", "Partial payment to create account not allowed." },
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ enum TER // aka TransactionEngineResult
|
||||
telBAD_DOMAIN,
|
||||
telBAD_PATH_COUNT,
|
||||
telBAD_PUBLIC_KEY,
|
||||
telFAILED_PROCESSING,
|
||||
telINSUF_FEE_P,
|
||||
telNO_DST_PARTIAL,
|
||||
|
||||
@@ -121,6 +122,7 @@ enum TER // aka TransactionEngineResult
|
||||
tecUNFUNDED_ADD = 102,
|
||||
tecUNFUNDED_OFFER = 103,
|
||||
tecUNFUNDED_PAYMENT = 104,
|
||||
tecFAILED_PROCESSING = 105,
|
||||
tecDIR_FULL = 121,
|
||||
tecINSUF_RESERVE_LINE = 122,
|
||||
tecINSUF_RESERVE_OFFER = 123,
|
||||
|
||||
@@ -16,7 +16,7 @@ std::map<std::string, TransactionFormat*> TransactionFormat::byName;
|
||||
|
||||
#define DECLARE_TF(name, type) tf = new TransactionFormat(#name, type); (*tf) TF_BASE
|
||||
|
||||
static bool TFInit()
|
||||
void TFInit()
|
||||
{
|
||||
TransactionFormat* tf;
|
||||
|
||||
@@ -84,12 +84,8 @@ static bool TFInit()
|
||||
<< SOElement(sfReserveBase, SOE_REQUIRED)
|
||||
<< SOElement(sfReserveIncrement, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TFInitComplete = TFInit();
|
||||
|
||||
TransactionFormat* TransactionFormat::getTxnFormat(TransactionType t)
|
||||
{
|
||||
std::map<int, TransactionFormat*>::iterator it = byType.find(static_cast<int>(t));
|
||||
|
||||
@@ -31,7 +31,7 @@ class TransactionFormat
|
||||
public:
|
||||
std::string t_name;
|
||||
TransactionType t_type;
|
||||
std::vector<SOElement::ref> elements;
|
||||
SOTemplate elements;
|
||||
|
||||
static std::map<int, TransactionFormat*> byType;
|
||||
static std::map<std::string, TransactionFormat*> byName;
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
}
|
||||
TransactionFormat& operator<<(const SOElement& el)
|
||||
{
|
||||
elements.push_back(new SOElement(el));
|
||||
elements.push_back(el);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,8 @@ const uint32 tfAccountSetMask = ~(tfRequireDestTag|tfOptionalDestTag|tfRequireA
|
||||
|
||||
// OfferCreate flags:
|
||||
const uint32 tfPassive = 0x00010000;
|
||||
const uint32 tfOfferCreateMask = ~(tfPassive);
|
||||
const uint32 tfMarket = 0x00020000;
|
||||
const uint32 tfOfferCreateMask = ~(tfPassive|tfMarket);
|
||||
|
||||
// Payment flags:
|
||||
const uint32 tfNoRippleDirect = 0x00010000;
|
||||
|
||||
@@ -293,7 +293,8 @@ void ValidationCollection::condWrite()
|
||||
if (mWriting)
|
||||
return;
|
||||
mWriting = true;
|
||||
theApp->getJobQueue().addJob(jtWRITE, boost::bind(&ValidationCollection::doWrite, this, _1));
|
||||
theApp->getJobQueue().addJob(jtWRITE, "ValidationCollection::doWrite",
|
||||
boost::bind(&ValidationCollection::doWrite, this, _1));
|
||||
}
|
||||
|
||||
void ValidationCollection::doWrite(Job&)
|
||||
|
||||
@@ -152,17 +152,17 @@ public:
|
||||
ptr->preDestroy(); // Must be done before we return
|
||||
|
||||
// Must be done without holding the websocket send lock
|
||||
theApp->getJobQueue().addJob(jtCLIENT,
|
||||
theApp->getJobQueue().addJob(jtCLIENT, "WSClient::destroy",
|
||||
boost::bind(&WSConnection<endpoint_type>::destroy, ptr));
|
||||
}
|
||||
|
||||
void on_message(connection_ptr cpClient, message_ptr mpMessage)
|
||||
{
|
||||
theApp->getJobQueue().addJob(jtCLIENT,
|
||||
theApp->getJobQueue().addJob(jtCLIENT, "WSClient::command",
|
||||
boost::bind(&WSServerHandler<endpoint_type>::do_message, this, _1, cpClient, mpMessage));
|
||||
}
|
||||
|
||||
void do_message(Job&, connection_ptr cpClient, message_ptr mpMessage)
|
||||
void do_message(Job& job, connection_ptr cpClient, message_ptr mpMessage)
|
||||
{
|
||||
Json::Value jvRequest;
|
||||
Json::Reader jrReader;
|
||||
@@ -190,6 +190,8 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
if (jvRequest.isMember("command"))
|
||||
job.rename(std::string("WSClient::") + jvRequest["command"].asString());
|
||||
boost::shared_ptr< WSConnection<endpoint_type> > conn;
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mMapLock);
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
namespace po = boost::program_options;
|
||||
|
||||
extern bool AddSystemEntropy();
|
||||
extern void TFInit();
|
||||
extern void LEFInit();
|
||||
extern void SVFInit();
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::unit_test;
|
||||
|
||||
@@ -51,7 +55,6 @@ void startServer()
|
||||
theApp->run(); // Blocks till we get a stop RPC.
|
||||
}
|
||||
|
||||
|
||||
bool init_unit_test()
|
||||
{
|
||||
theApp = new Application();
|
||||
@@ -66,34 +69,30 @@ void printHelp(const po::options_description& desc)
|
||||
cerr << desc << endl;
|
||||
|
||||
cerr << "Commands: " << endl;
|
||||
cerr << " account_domain_set <seed> <paying_account> [<domain>]" << endl;
|
||||
cerr << " account_email_set <seed> <paying_account> [<email_address>]" << endl;
|
||||
cerr << " account_tx <account>|<nickname>|<account_public_key> <ledger>|(<minledger> <maxledger>)" << endl;
|
||||
cerr << " account_lines <account>|<nickname>|<account_public_key> [<index>]" << endl;
|
||||
cerr << " account_offers <account>|<nickname>|<account_public_key> [<index>]" << endl;
|
||||
cerr << " account_info <account>|<nickname>" << endl;
|
||||
cerr << " account_info <seed>|<pass_phrase>|<key> [<index>]" << endl;
|
||||
cerr << " account_message_set <seed> <paying_account> <pub_key>" << endl;
|
||||
cerr << " account_publish_set <seed> <paying_account> <hash> <size>" << endl;
|
||||
cerr << " account_rate_set <seed> <paying_account> <rate>" << endl;
|
||||
cerr << " account_wallet_set <seed> <paying_account> [<wallet_hash>]" << endl;
|
||||
cerr << " account_lines <account>|<nickname>|<account_public_key> [<index>]" << endl;
|
||||
cerr << " account_offers <account>|<nickname>|<account_public_key> [<index>]" << endl;
|
||||
cerr << " account_tx <account>|<nickname>|<account_public_key> <ledger>|(<minledger> <maxledger>)" << endl;
|
||||
cerr << " book_offers <taker_pays> <taker_gets> [<taker [<ledger> [<limit> [<proof> [<marker>]]]]]" << endl;
|
||||
cerr << " connect <ip> [<port>]" << endl;
|
||||
cerr << " consensus_info" << endl;
|
||||
#if ENABLE_INSECURE
|
||||
cerr << " data_delete <key>" << endl;
|
||||
cerr << " data_fetch <key>" << endl;
|
||||
cerr << " data_store <key> <value>" << endl;
|
||||
#endif
|
||||
cerr << " get_counts" << endl;
|
||||
cerr << " ledger [<id>|current|lastclosed] [full]" << endl;
|
||||
cerr << " ledger_accept" << endl;
|
||||
cerr << " ledger_closed" << endl;
|
||||
cerr << " ledger_current" << endl;
|
||||
cerr << " ledger_header <ledger>" << endl;
|
||||
cerr << " logrotate " << endl;
|
||||
cerr << " nickname_info <nickname>" << endl;
|
||||
cerr << " nickname_set <seed> <paying_account> <nickname> [<offer_minimum>] [<authorization>]" << endl;
|
||||
cerr << " offer_create <seed> <paying_account> <taker_pays_amount> <taker_pays_currency> <taker_pays_issuer> <takers_gets_amount> <takers_gets_currency> <takers_gets_issuer> <expires> [passive]" << endl;
|
||||
cerr << " offer_cancel <seed> <paying_account> <sequence>" << endl;
|
||||
cerr << " password_fund <seed> <paying_account> [<account>]" << endl;
|
||||
cerr << " password_set <master_seed> <regular_seed> [<account>]" << endl;
|
||||
cerr << " peers" << endl;
|
||||
cerr << " random" << endl;
|
||||
cerr << " ripple ..." << endl;
|
||||
// cerr << " ripple_line_set <seed> <paying_account> <destination_account> <limit_amount> <currency> [<quality_in>] [<quality_out>]" << endl;
|
||||
cerr << " send <seed> <paying_account> <account_id> <amount> [<currency>] [<send_max>] [<send_currency>]" << endl;
|
||||
// cerr << " send <seed> <paying_account> <account_id> <amount> [<currency>] [<send_max>] [<send_currency>]" << endl;
|
||||
cerr << " stop" << endl;
|
||||
cerr << " tx <id>" << endl;
|
||||
cerr << " unl_add <domain>|<public> [<comment>]" << endl;
|
||||
@@ -109,6 +108,19 @@ void printHelp(const po::options_description& desc)
|
||||
cerr << " wallet_claim <master_seed> <regular_seed> [<source_tag>] [<account_annotation>]" << endl;
|
||||
cerr << " wallet_seed [<seed>|<passphrase>|<passkey>]" << endl;
|
||||
cerr << " wallet_propose [<passphrase>]" << endl;
|
||||
|
||||
// Transaction helpers (that were removed):
|
||||
// cerr << " account_domain_set <seed> <paying_account> [<domain>]" << endl;
|
||||
// cerr << " account_email_set <seed> <paying_account> [<email_address>]" << endl;
|
||||
// cerr << " account_rate_set <seed> <paying_account> <rate>" << endl;
|
||||
// cerr << " account_wallet_set <seed> <paying_account> [<wallet_hash>]" << endl;
|
||||
// cerr << " nickname_info <nickname>" << endl;
|
||||
// cerr << " nickname_set <seed> <paying_account> <nickname> [<offer_minimum>] [<authorization>]" << endl;
|
||||
// cerr << " offer_create <seed> <paying_account> <taker_pays_amount> <taker_pays_currency> <taker_pays_issuer> <takers_gets_amount> <takers_gets_currency> <takers_gets_issuer> <expires> [passive]" << endl;
|
||||
// cerr << " offer_cancel <seed> <paying_account> <sequence>" << endl;
|
||||
// cerr << " password_fund <seed> <paying_account> [<account>]" << endl;
|
||||
// cerr << " password_set <master_seed> <regular_seed> [<account>]" << endl;
|
||||
// cerr << " trust_set <seed> <paying_account> <destination_account> <limit_amount> <currency> [<quality_in>] [<quality_out>]" << endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
@@ -180,6 +192,10 @@ int main(int argc, char* argv[])
|
||||
|
||||
InstanceType::multiThread();
|
||||
|
||||
TFInit();
|
||||
LEFInit();
|
||||
SVFInit();
|
||||
|
||||
if (vm.count("unittest"))
|
||||
{
|
||||
unit_test_main(init_unit_test, argc, argv);
|
||||
|
||||
@@ -613,11 +613,16 @@ Amount.prototype.parse_issuer = function (issuer) {
|
||||
Amount.prototype.parse_json = function (j) {
|
||||
if ('string' === typeof j) {
|
||||
// .../.../... notation is not a wire format. But allowed for easier testing.
|
||||
// var m = j.match(/^(.+)\/(...)(?:\/(.+))?$/);
|
||||
var m = j.match(/^(.+)\/(...)\/(.+)$/);
|
||||
|
||||
if (m) {
|
||||
this._currency = Currency.from_json(m[2]);
|
||||
this._issuer = UInt160.from_json(m[3]);
|
||||
if (m[3]) {
|
||||
this._issuer = UInt160.from_json(m[3]);
|
||||
} else {
|
||||
this._issuer = UInt160.from_json('1');
|
||||
}
|
||||
this.parse_value(m[1]);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -91,6 +91,26 @@ Request.prototype.ledger_index = function (ledger_index) {
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.ledger_select = function (ledger_spec) {
|
||||
if (ledger_spec === 'closed') {
|
||||
this.message.ledger_index = -1;
|
||||
|
||||
} else if (ledger_spec === 'current') {
|
||||
this.message.ledger_index = -2;
|
||||
|
||||
} else if (ledger_spec === 'verified') {
|
||||
this.message.ledger_index = -3;
|
||||
|
||||
} else if (String(ledger_spec).length > 12) { // XXX Better test needed
|
||||
this.message.ledger_hash = ledger_spec;
|
||||
|
||||
} else {
|
||||
this.message.ledger_index = ledger_spec;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.account_root = function (account) {
|
||||
this.message.account_root = UInt160.json_rewrite(account);
|
||||
|
||||
@@ -846,15 +866,25 @@ Remote.prototype.request_unsubscribe = function (streams) {
|
||||
return request;
|
||||
};
|
||||
|
||||
// --> current: true, for the current ledger.
|
||||
Remote.prototype.request_transaction_entry = function (hash, current) {
|
||||
// .ledger_choose()
|
||||
// .ledger_hash()
|
||||
// .ledger_index()
|
||||
Remote.prototype.request_transaction_entry = function (hash) {
|
||||
//utils.assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol.
|
||||
|
||||
return (new Request(this, 'transaction_entry'))
|
||||
.ledger_choose(current)
|
||||
.tx_hash(hash);
|
||||
};
|
||||
|
||||
// DEPRECATED: use request_transaction_entry
|
||||
Remote.prototype.request_tx = function (hash) {
|
||||
var request = new Request(this, 'tx');
|
||||
|
||||
request.message.transaction = hash;
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
Remote.prototype.request_account_info = function (accountID) {
|
||||
var request = new Request(this, 'account_info');
|
||||
|
||||
|
||||
@@ -106,14 +106,14 @@ UInt.prototype.parse_generic = function (j) {
|
||||
case undefined:
|
||||
case "0":
|
||||
case this.constructor.STR_ZERO:
|
||||
case this.constructor.ADDRESS_ZERO:
|
||||
case this.constructor.ACCOUNT_ZERO:
|
||||
case this.constructor.HEX_ZERO:
|
||||
this._value = nbi();
|
||||
break;
|
||||
|
||||
case "1":
|
||||
case this.constructor.STR_ONE:
|
||||
case this.constructor.ADDRESS_ONE:
|
||||
case this.constructor.ACCOUNT_ONE:
|
||||
case this.constructor.HEX_ONE:
|
||||
this._value = new BigInteger([1]);
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ UInt160.width = 20;
|
||||
UInt160.prototype = extend({}, UInt.prototype);
|
||||
UInt160.prototype.constructor = UInt160;
|
||||
|
||||
var ADDRESS_ZERO = UInt160.ADDRESS_ZERO = "rrrrrrrrrrrrrrrrrrrrrhoLvTp";
|
||||
var ADDRESS_ONE = UInt160.ADDRESS_ONE = "rrrrrrrrrrrrrrrrrrrrBZbvji";
|
||||
var ACCOUNT_ZERO = UInt160.ACCOUNT_ZERO = "rrrrrrrrrrrrrrrrrrrrrhoLvTp";
|
||||
var ACCOUNT_ONE = UInt160.ACCOUNT_ONE = "rrrrrrrrrrrrrrrrrrrrBZbvji";
|
||||
var HEX_ZERO = UInt160.HEX_ZERO = "0000000000000000000000000000000000000000";
|
||||
var HEX_ONE = UInt160.HEX_ONE = "0000000000000000000000000000000000000001";
|
||||
var STR_ZERO = UInt160.STR_ZERO = utils.hexToString(HEX_ZERO);
|
||||
|
||||
@@ -24,9 +24,6 @@ UInt256.width = 32;
|
||||
UInt256.prototype = extend({}, UInt.prototype);
|
||||
UInt256.prototype.constructor = UInt256;
|
||||
|
||||
// XXX Generate these constants (or remove them)
|
||||
var ADDRESS_ZERO = UInt256.ADDRESS_ZERO = "XXX";
|
||||
var ADDRESS_ONE = UInt256.ADDRESS_ONE = "XXX";
|
||||
var HEX_ZERO = UInt256.HEX_ZERO = "00000000000000000000000000000000" +
|
||||
"00000000000000000000000000000000";
|
||||
var HEX_ONE = UInt256.HEX_ONE = "00000000000000000000000000000000" +
|
||||
|
||||
@@ -17,16 +17,16 @@ buster.testCase("Amount", {
|
||||
buster.assert.equals(nbi(), UInt160.from_generic("0")._value);
|
||||
},
|
||||
"Parse 0 export" : function () {
|
||||
buster.assert.equals(UInt160.ADDRESS_ZERO, UInt160.from_generic("0").to_json());
|
||||
buster.assert.equals(UInt160.ACCOUNT_ZERO, UInt160.from_generic("0").to_json());
|
||||
},
|
||||
"Parse 1" : function () {
|
||||
buster.assert.equals(new BigInteger([1]), UInt160.from_generic("1")._value);
|
||||
},
|
||||
"Parse rrrrrrrrrrrrrrrrrrrrrhoLvTp export" : function () {
|
||||
buster.assert.equals(UInt160.ADDRESS_ZERO, UInt160.from_json("rrrrrrrrrrrrrrrrrrrrrhoLvTp").to_json());
|
||||
buster.assert.equals(UInt160.ACCOUNT_ZERO, UInt160.from_json("rrrrrrrrrrrrrrrrrrrrrhoLvTp").to_json());
|
||||
},
|
||||
"Parse rrrrrrrrrrrrrrrrrrrrBZbvji export" : function () {
|
||||
buster.assert.equals(UInt160.ADDRESS_ONE, UInt160.from_json("rrrrrrrrrrrrrrrrrrrrBZbvji").to_json());
|
||||
buster.assert.equals(UInt160.ACCOUNT_ONE, UInt160.from_json("rrrrrrrrrrrrrrrrrrrrBZbvji").to_json());
|
||||
},
|
||||
"Parse mtgox export" : function () {
|
||||
buster.assert.equals(config.accounts["mtgox"].account, UInt160.from_json("mtgox").to_json());
|
||||
|
||||
Reference in New Issue
Block a user