mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-30 18:40:28 +00:00
Merge branch 'master' of https://github.com/jedmccaleb/NewCoin
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -23,3 +23,6 @@ node_modules
|
||||
|
||||
# Ignore tmp directory.
|
||||
tmp
|
||||
|
||||
# Ignore database directory.
|
||||
db/*.db
|
||||
@@ -181,15 +181,21 @@ X'53514C697465'
|
||||
*/
|
||||
void SqliteDatabase::escape(const unsigned char* start, int size, std::string& retStr)
|
||||
{
|
||||
retStr="X'";
|
||||
static const char toHex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
char buf[3];
|
||||
for(int n=0; n<size; n++)
|
||||
retStr.resize(3 + (size * 2));
|
||||
|
||||
int pos = 0;
|
||||
retStr[pos++] = 'X';
|
||||
retStr[pos++] = '\'';
|
||||
|
||||
for (int n = 0; n < size; ++n)
|
||||
{
|
||||
sprintf(buf, "%02X", start[n]);
|
||||
retStr.append(buf);
|
||||
|
||||
retStr[pos++] = toHex[start[n] >> 4];
|
||||
retStr[pos++] = toHex[start[n] & 0x0f];
|
||||
}
|
||||
retStr.push_back('\'');
|
||||
retStr[pos] = '\'';
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -408,6 +408,10 @@ Amount.prototype.canonicalize = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
Amount.prototype.is_native = function () {
|
||||
return this.is_native;
|
||||
};
|
||||
|
||||
// Return a new value.
|
||||
Amount.prototype.negate = function () {
|
||||
return this.clone('NEGATE');
|
||||
|
||||
260
js/remote.js
260
js/remote.js
@@ -65,7 +65,7 @@ Request.prototype.ledger_choose = function (current) {
|
||||
this.message.ledger_index = this.remote.ledger_current_index;
|
||||
}
|
||||
else {
|
||||
this.message.ledger = this.remote.ledger_closed;
|
||||
this.message.ledger_hash = this.remote.ledger_hash;
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -74,8 +74,8 @@ Request.prototype.ledger_choose = function (current) {
|
||||
// Set the ledger for a request.
|
||||
// - ledger_entry
|
||||
// - transaction_entry
|
||||
Request.prototype.ledger_closed = function (ledger) {
|
||||
this.message.ledger_closed = ledger;
|
||||
Request.prototype.ledger_hash = function (h) {
|
||||
this.message.ledger_hash = h;
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -107,8 +107,14 @@ Request.prototype.secret = function (s) {
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.transaction = function (t) {
|
||||
this.message.transaction = t;
|
||||
Request.prototype.tx_hash = function (h) {
|
||||
this.message.tx_hash = h;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.tx_json = function (j) {
|
||||
this.message.tx_json = j;
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -145,7 +151,7 @@ var Remote = function (trusted, websocket_ip, websocket_port, trace) {
|
||||
this.websocket_port = websocket_port;
|
||||
this.id = 0;
|
||||
this.trace = trace;
|
||||
this.ledger_closed = undefined;
|
||||
this.ledger_hash = undefined;
|
||||
this.ledger_current_index = undefined;
|
||||
this.stand_alone = undefined;
|
||||
this.online_target = false;
|
||||
@@ -410,10 +416,11 @@ Remote.prototype._connect_message = function (ws, json, flags) {
|
||||
// XXX Be more defensive fields could be missing or of wrong type.
|
||||
// YYY Might want to do some cache management.
|
||||
|
||||
this.ledger_closed = message.ledger_closed;
|
||||
this.ledger_current_index = message.ledger_closed_index + 1;
|
||||
this.ledger_time = message.ledger_time;
|
||||
this.ledger_hash = message.ledger_hash;
|
||||
this.ledger_current_index = message.ledger_index + 1;
|
||||
|
||||
this.emit('ledger_closed', message.ledger_closed, message.ledger_closed_index);
|
||||
this.emit('ledger_closed', message.ledger_hash, message.ledger_index);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -466,16 +473,25 @@ Remote.prototype.request = function (request) {
|
||||
}
|
||||
};
|
||||
|
||||
Remote.prototype.request_ledger_closed = function () {
|
||||
// Only for unit testing.
|
||||
Remote.prototype.request_ledger_hash = function () {
|
||||
assert(this.trusted); // If not trusted, need to check proof.
|
||||
|
||||
return new Request(this, 'ledger_closed');
|
||||
var request = new Request(this, 'rpc');
|
||||
|
||||
request.message.rpc_command = 'ledger_closed';
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
// Get the current proposed ledger entry. May be closed (and revised) at any time (even before returning).
|
||||
// Only for use by unit tests.
|
||||
// Only for unit testing.
|
||||
Remote.prototype.request_ledger_current = function () {
|
||||
return new Request(this, 'ledger_current');
|
||||
var request = new Request(this, 'rpc');
|
||||
|
||||
request.message.rpc_command = 'ledger_current';
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
// --> ledger : optional
|
||||
@@ -484,14 +500,16 @@ Remote.prototype.request_ledger_entry = function (type) {
|
||||
assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol.
|
||||
|
||||
var self = this;
|
||||
var request = new Request(this, 'ledger_entry');
|
||||
var request = new Request(this, 'rpc');
|
||||
|
||||
request.message.rpc_command = 'ledger_entry';
|
||||
|
||||
if (type)
|
||||
this.type = type;
|
||||
|
||||
// Transparent caching:
|
||||
request.on('request', function (remote) { // Intercept default request.
|
||||
if (this.ledger_closed) {
|
||||
if (this.ledger_hash) {
|
||||
// XXX Add caching.
|
||||
}
|
||||
// else if (req.ledger_index)
|
||||
@@ -537,18 +555,30 @@ Remote.prototype.request_ledger_entry = function (type) {
|
||||
return request;
|
||||
};
|
||||
|
||||
Remote.prototype.request_subscribe = function () {
|
||||
var request = new Request(this, 'subscribe');
|
||||
|
||||
request.message.streams = [ 'ledger', 'server' ];
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
Remote.prototype.request_transaction_entry = function (hash) {
|
||||
assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol.
|
||||
|
||||
return (new Request(this, 'transaction_entry'))
|
||||
.transaction(hash);
|
||||
var request = new Request(this, 'rpc');
|
||||
|
||||
request.message.rpc_command = 'transaction_entry';
|
||||
|
||||
return request
|
||||
.tx_hash(hash);
|
||||
};
|
||||
|
||||
// Submit a transaction.
|
||||
Remote.prototype.submit = function (transaction) {
|
||||
var self = this;
|
||||
|
||||
if (this.trace) console.log("remote: submit: %s", JSON.stringify(transaction.transaction));
|
||||
if (this.trace) console.log("remote: submit: %s", JSON.stringify(transaction.tx_json));
|
||||
|
||||
if (transaction.secret && !this.trusted)
|
||||
{
|
||||
@@ -558,14 +588,14 @@ Remote.prototype.submit = function (transaction) {
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (!transaction.transaction.Sequence) {
|
||||
transaction.transaction.Sequence = this.account_seq(transaction.transaction.Account, 'ADVANCE');
|
||||
// console.log("Sequence: %s", transaction.transaction.Sequence);
|
||||
if (!transaction.tx_json.Sequence) {
|
||||
transaction.tx_json.Sequence = this.account_seq(transaction.tx_json.Account, 'ADVANCE');
|
||||
// console.log("Sequence: %s", transaction.tx_json.Sequence);
|
||||
}
|
||||
|
||||
if (!transaction.transaction.Sequence) {
|
||||
if (!transaction.tx_json.Sequence) {
|
||||
// Look in the last closed ledger.
|
||||
this.account_seq_cache(transaction.transaction.Account, false)
|
||||
this.account_seq_cache(transaction.tx_json.Account, false)
|
||||
.on('success_account_seq_cache', function () {
|
||||
// Try again.
|
||||
self.submit(transaction);
|
||||
@@ -574,7 +604,7 @@ Remote.prototype.submit = function (transaction) {
|
||||
// XXX Maybe be smarter about this. Don't want to trust an untrusted server for this seq number.
|
||||
|
||||
// Look in the current ledger.
|
||||
self.account_seq_cache(transaction.transaction.Account, 'CURRENT')
|
||||
self.account_seq_cache(transaction.tx_json.Account, 'CURRENT')
|
||||
.on('success_account_seq_cache', function () {
|
||||
// Try again.
|
||||
self.submit(transaction);
|
||||
@@ -588,11 +618,16 @@ Remote.prototype.submit = function (transaction) {
|
||||
.request();
|
||||
}
|
||||
else {
|
||||
var submit_request = new Request(this, 'submit');
|
||||
var submit_request = new Request(this, 'rpc');
|
||||
|
||||
submit_request.transaction(transaction.transaction);
|
||||
submit_request.message.rpc_command = 'submit_json';
|
||||
|
||||
submit_request.tx_json(transaction.tx_json);
|
||||
submit_request.secret(transaction.secret);
|
||||
|
||||
if (transaction.build_path)
|
||||
submit_request.build_path = true;
|
||||
|
||||
// Forward successes and errors.
|
||||
submit_request.on('success', function (message) { transaction.emit('success', message); });
|
||||
submit_request.on('error', function (message) { transaction.emit('error', message); });
|
||||
@@ -612,15 +647,16 @@ Remote.prototype.submit = function (transaction) {
|
||||
Remote.prototype._server_subscribe = function () {
|
||||
var self = this;
|
||||
|
||||
(new Request(this, 'server_subscribe'))
|
||||
this.request_subscribe()
|
||||
.on('success', function (message) {
|
||||
self.stand_alone = !!message.stand_alone;
|
||||
|
||||
if (message.ledger_closed && message.ledger_current_index) {
|
||||
self.ledger_closed = message.ledger_closed;
|
||||
self.ledger_current_index = message.ledger_current_index;
|
||||
if (message.ledger_hash && message.ledger_index) {
|
||||
self.ledger_time = message.ledger_time;
|
||||
self.ledger_hash = message.ledger_hash;
|
||||
self.ledger_current_index = message.ledger_index+1;
|
||||
|
||||
self.emit('ledger_closed', self.ledger_closed, self.ledger_current_index-1);
|
||||
self.emit('ledger_closed', self.ledger_hash, self.ledger_current_index-1);
|
||||
}
|
||||
|
||||
self.emit('subscribed');
|
||||
@@ -633,13 +669,17 @@ Remote.prototype._server_subscribe = function () {
|
||||
};
|
||||
|
||||
// Ask the remote to accept the current ledger.
|
||||
// - To be notified when the ledger is accepted, server_subscribe() then listen to 'ledger_closed' events.
|
||||
// - To be notified when the ledger is accepted, server_subscribe() then listen to 'ledger_hash' events.
|
||||
// A good way to be notified of the result of this is:
|
||||
// remote.once('ledger_closed', function (ledger_closed, ledger_closed_index) { ... } );
|
||||
// remote.once('ledger_closed', function (ledger_closed, ledger_index) { ... } );
|
||||
Remote.prototype.ledger_accept = function () {
|
||||
if (this.stand_alone || undefined === this.stand_alone)
|
||||
{
|
||||
(new Request(this, 'ledger_accept'))
|
||||
var request = new Request(this, 'rpc');
|
||||
|
||||
request.message.rpc_command = 'ledger_accept';
|
||||
|
||||
request
|
||||
.request();
|
||||
}
|
||||
else {
|
||||
@@ -837,7 +877,8 @@ var Transaction = function (remote) {
|
||||
|
||||
this.remote = remote;
|
||||
this.secret = undefined;
|
||||
this.transaction = { // Transaction data.
|
||||
this.build_path = true;
|
||||
this.tx_json = { // Transaction data.
|
||||
'Flags' : 0, // XXX Would be nice if server did not require this.
|
||||
};
|
||||
this.hash = undefined;
|
||||
@@ -846,12 +887,12 @@ var Transaction = function (remote) {
|
||||
|
||||
this.on('success', function (message) {
|
||||
if (message.engine_result) {
|
||||
self.hash = message.transaction.hash;
|
||||
self.hash = message.tx_json.hash;
|
||||
|
||||
self.set_state('client_proposed');
|
||||
|
||||
self.emit('proposed', {
|
||||
'transaction' : message.transaction,
|
||||
'tx_json' : message.tx_json,
|
||||
'result' : message.engine_result,
|
||||
'result_code' : message.engine_result_code,
|
||||
'result_message' : message.engine_result_message,
|
||||
@@ -913,14 +954,14 @@ Transaction.prototype.set_state = function (state) {
|
||||
};
|
||||
|
||||
// Submit a transaction to the network.
|
||||
// XXX Don't allow a submit without knowing ledger_closed_index.
|
||||
// XXX Don't allow a submit without knowing ledger_index.
|
||||
// XXX Have a network canSubmit(), post events for following.
|
||||
// XXX Also give broader status for tracking through network disconnects.
|
||||
Transaction.prototype.submit = function () {
|
||||
var self = this;
|
||||
var transaction = this.transaction;
|
||||
var self = this;
|
||||
var tx_json = this.tx_json;
|
||||
|
||||
if ('string' !== typeof transaction.Account)
|
||||
if ('string' !== typeof tx_json.Account)
|
||||
{
|
||||
this.emit('error', {
|
||||
'error' : 'invalidAccount',
|
||||
@@ -931,14 +972,14 @@ Transaction.prototype.submit = function () {
|
||||
|
||||
// YYY Might check paths for invalid accounts.
|
||||
|
||||
if (undefined === transaction.Fee) {
|
||||
if ('Payment' === transaction.TransactionType
|
||||
&& transaction.Flags & Remote.flags.Payment.CreateAccount) {
|
||||
if (undefined === tx_json.Fee) {
|
||||
if ('Payment' === tx_json.TransactionType
|
||||
&& tx_json.Flags & Remote.flags.Payment.CreateAccount) {
|
||||
|
||||
transaction.Fee = Remote.fees.account_create.to_json();
|
||||
tx_json.Fee = Remote.fees.account_create.to_json();
|
||||
}
|
||||
else {
|
||||
transaction.Fee = Remote.fees['default'].to_json();
|
||||
tx_json.Fee = Remote.fees['default'].to_json();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,12 +988,12 @@ Transaction.prototype.submit = function () {
|
||||
|
||||
this.submit_index = this.remote.ledger_current_index;
|
||||
|
||||
var on_ledger_closed = function (ledger_closed, ledger_closed_index) {
|
||||
var on_ledger_closed = function (ledger_hash, ledger_index) {
|
||||
var stop = false;
|
||||
|
||||
// XXX make sure self.hash is available.
|
||||
self.remote.request_transaction_entry(self.hash)
|
||||
.ledger_closed(ledger_closed)
|
||||
.ledger_hash(ledger_hash)
|
||||
.on('success', function (message) {
|
||||
self.set_state(message.metadata.TransactionResult);
|
||||
self.emit('final', message);
|
||||
@@ -960,12 +1001,12 @@ Transaction.prototype.submit = function () {
|
||||
.on('error', function (message) {
|
||||
if ('remoteError' === message.error
|
||||
&& 'transactionNotFound' === message.remote.error) {
|
||||
if (self.submit_index + SUBMIT_LOST < ledger_closed_index) {
|
||||
if (self.submit_index + SUBMIT_LOST < ledger_index) {
|
||||
self.set_state('client_lost'); // Gave up.
|
||||
self.emit('lost');
|
||||
stop = true;
|
||||
}
|
||||
else if (self.submit_index + SUBMIT_MISSING < ledger_closed_index) {
|
||||
else if (self.submit_index + SUBMIT_MISSING < ledger_index) {
|
||||
self.set_state('client_missing'); // We don't know what happened to transaction, still might find.
|
||||
self.emit('pending');
|
||||
}
|
||||
@@ -997,6 +1038,12 @@ Transaction.prototype.submit = function () {
|
||||
// Set options for Transactions
|
||||
//
|
||||
|
||||
Transaction.prototype.build_path = function (build) {
|
||||
this.build_path = build;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Transaction._path_rewrite = function (path) {
|
||||
var path_new = [];
|
||||
|
||||
@@ -1020,8 +1067,8 @@ Transaction._path_rewrite = function (path) {
|
||||
}
|
||||
|
||||
Transaction.prototype.path_add = function (path) {
|
||||
this.transaction.Paths = this.transaction.Paths || []
|
||||
this.transaction.Paths.push(Transaction._path_rewrite(path));
|
||||
this.tx_json.Paths = this.tx_json.Paths || []
|
||||
this.tx_json.Paths.push(Transaction._path_rewrite(path));
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -1043,16 +1090,16 @@ Transaction.prototype.secret = function (secret) {
|
||||
|
||||
Transaction.prototype.send_max = function (send_max) {
|
||||
if (send_max)
|
||||
this.transaction.SendMax = Amount.json_rewrite(send_max);
|
||||
this.tx_json.SendMax = Amount.json_rewrite(send_max);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// --> rate: In billionths.
|
||||
Transaction.prototype.transfer_rate = function (rate) {
|
||||
this.transaction.TransferRate = Number(rate);
|
||||
this.tx_json.TransferRate = Number(rate);
|
||||
|
||||
if (this.transaction.TransferRate < 1e9)
|
||||
if (this.tx_json.TransferRate < 1e9)
|
||||
throw 'invalidTransferRate';
|
||||
|
||||
return this;
|
||||
@@ -1062,10 +1109,10 @@ Transaction.prototype.transfer_rate = function (rate) {
|
||||
// --> flags: undefined, _flag_, or [ _flags_ ]
|
||||
Transaction.prototype.set_flags = function (flags) {
|
||||
if (flags) {
|
||||
var transaction_flags = Remote.flags[this.transaction.TransactionType];
|
||||
var transaction_flags = Remote.flags[this.tx_json.TransactionType];
|
||||
|
||||
if (undefined == this.transaction.Flags) // We plan to not define this field on new Transaction.
|
||||
this.transaction.Flags = 0;
|
||||
if (undefined == this.tx_json.Flags) // We plan to not define this field on new Transaction.
|
||||
this.tx_json.Flags = 0;
|
||||
|
||||
var flag_set = 'object' === typeof flags ? flags : [ flags ];
|
||||
|
||||
@@ -1074,15 +1121,15 @@ Transaction.prototype.set_flags = function (flags) {
|
||||
|
||||
if (flag in transaction_flags)
|
||||
{
|
||||
this.transaction.Flags += transaction_flags[flag];
|
||||
this.tx_json.Flags += transaction_flags[flag];
|
||||
}
|
||||
else {
|
||||
// XXX Immediately report an error or mark it.
|
||||
}
|
||||
}
|
||||
|
||||
if (this.transaction.Flags & Remote.flags.Payment.CreateAccount)
|
||||
this.transaction.Fee = Remote.fees.account_create.to_json();
|
||||
if (this.tx_json.Flags & Remote.flags.Payment.CreateAccount)
|
||||
this.tx_json.Fee = Remote.fees.account_create.to_json();
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -1103,43 +1150,43 @@ Transaction.prototype._account_secret = function (account) {
|
||||
// .transfer_rate()
|
||||
// .wallet_locator() NYI
|
||||
Transaction.prototype.account_set = function (src) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'AccountSet';
|
||||
this.transaction.Account = UInt160.json_rewrite(src);
|
||||
this.secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'AccountSet';
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Transaction.prototype.claim = function (src, generator, public_key, signature) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'Claim';
|
||||
this.transaction.Generator = generator;
|
||||
this.transaction.PublicKey = public_key;
|
||||
this.transaction.Signature = signature;
|
||||
this.secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'Claim';
|
||||
this.tx_json.Generator = generator;
|
||||
this.tx_json.PublicKey = public_key;
|
||||
this.tx_json.Signature = signature;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Transaction.prototype.offer_cancel = function (src, sequence) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'OfferCancel';
|
||||
this.transaction.Account = UInt160.json_rewrite(src);
|
||||
this.transaction.OfferSequence = Number(sequence);
|
||||
this.secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'OfferCancel';
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
this.tx_json.OfferSequence = Number(sequence);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// --> expiration : Date or Number
|
||||
Transaction.prototype.offer_create = function (src, taker_pays, taker_gets, expiration) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'OfferCreate';
|
||||
this.transaction.Account = UInt160.json_rewrite(src);
|
||||
this.transaction.Fee = Remote.fees.offer.to_json();
|
||||
this.transaction.TakerPays = Amount.json_rewrite(taker_pays);
|
||||
this.transaction.TakerGets = Amount.json_rewrite(taker_gets);
|
||||
this.secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'OfferCreate';
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
this.tx_json.Fee = Remote.fees.offer.to_json();
|
||||
this.tx_json.TakerPays = Amount.json_rewrite(taker_pays);
|
||||
this.tx_json.TakerGets = Amount.json_rewrite(taker_gets);
|
||||
|
||||
if (expiration)
|
||||
this.transaction.Expiration = Date === expiration.constructor
|
||||
this.tx_json.Expiration = Date === expiration.constructor
|
||||
? expiration.getTime()
|
||||
: Number(expiration);
|
||||
|
||||
@@ -1147,20 +1194,20 @@ Transaction.prototype.offer_create = function (src, taker_pays, taker_gets, expi
|
||||
};
|
||||
|
||||
Transaction.prototype.password_fund = function (src, dst) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'PasswordFund';
|
||||
this.transaction.Destination = UInt160.json_rewrite(dst);
|
||||
this.secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'PasswordFund';
|
||||
this.tx_json.Destination = UInt160.json_rewrite(dst);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Transaction.prototype.password_set = function (src, authorized_key, generator, public_key, signature) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'PasswordSet';
|
||||
this.transaction.AuthorizedKey = authorized_key;
|
||||
this.transaction.Generator = generator;
|
||||
this.transaction.PublicKey = public_key;
|
||||
this.transaction.Signature = signature;
|
||||
this.secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'PasswordSet';
|
||||
this.tx_json.AuthorizedKey = authorized_key;
|
||||
this.tx_json.Generator = generator;
|
||||
this.tx_json.PublicKey = public_key;
|
||||
this.tx_json.Signature = signature;
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -1175,34 +1222,35 @@ Transaction.prototype.password_set = function (src, authorized_key, generator, p
|
||||
//
|
||||
// Options:
|
||||
// .paths()
|
||||
// .build_path()
|
||||
// .path_add()
|
||||
// .secret()
|
||||
// .send_max()
|
||||
// .set_flags()
|
||||
Transaction.prototype.payment = function (src, dst, deliver_amount) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'Payment';
|
||||
this.transaction.Account = UInt160.json_rewrite(src);
|
||||
this.transaction.Amount = Amount.json_rewrite(deliver_amount);
|
||||
this.transaction.Destination = UInt160.json_rewrite(dst);
|
||||
this.secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'Payment';
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
this.tx_json.Amount = Amount.json_rewrite(deliver_amount);
|
||||
this.tx_json.Destination = UInt160.json_rewrite(dst);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Transaction.prototype.ripple_line_set = function (src, limit, quality_in, quality_out) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'CreditSet';
|
||||
this.transaction.Account = UInt160.json_rewrite(src);
|
||||
this.secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'CreditSet';
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
|
||||
// Allow limit of 0 through.
|
||||
if (undefined !== limit)
|
||||
this.transaction.LimitAmount = Amount.json_rewrite(limit);
|
||||
this.tx_json.LimitAmount = Amount.json_rewrite(limit);
|
||||
|
||||
if (quality_in)
|
||||
this.transaction.QualityIn = quality_in;
|
||||
this.tx_json.QualityIn = quality_in;
|
||||
|
||||
if (quality_out)
|
||||
this.transaction.QualityOut = quality_out;
|
||||
this.tx_json.QualityOut = quality_out;
|
||||
|
||||
// XXX Throw an error if nothing is set.
|
||||
|
||||
@@ -1210,12 +1258,12 @@ Transaction.prototype.ripple_line_set = function (src, limit, quality_in, qualit
|
||||
};
|
||||
|
||||
Transaction.prototype.wallet_add = function (src, amount, authorized_key, public_key, signature) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'WalletAdd';
|
||||
this.transaction.Amount = Amount.json_rewrite(amount);
|
||||
this.transaction.AuthorizedKey = authorized_key;
|
||||
this.transaction.PublicKey = public_key;
|
||||
this.transaction.Signature = signature;
|
||||
this.secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'WalletAdd';
|
||||
this.tx_json.Amount = Amount.json_rewrite(amount);
|
||||
this.tx_json.AuthorizedKey = authorized_key;
|
||||
this.tx_json.PublicKey = public_key;
|
||||
this.tx_json.Signature = signature;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -38,11 +38,12 @@ DatabaseCon::~DatabaseCon()
|
||||
}
|
||||
|
||||
Application::Application() :
|
||||
mIOWork(mIOService), mAuxWork(mAuxService), mUNL(mIOService),
|
||||
mNetOps(mIOService, &mMasterLedger), mTempNodeCache("NodeCache", 16384, 90), mHashedObjectStore(16384, 300),
|
||||
mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL),
|
||||
mHashNodeDB(NULL), mNetNodeDB(NULL),
|
||||
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mSweepTimer(mAuxService), mRPCHandler(&mNetOps)
|
||||
mIOWork(mIOService), mAuxWork(mAuxService), mUNL(mIOService), mNetOps(mIOService, &mMasterLedger),
|
||||
mTempNodeCache("NodeCache", 16384, 90), mHashedObjectStore(16384, 300),
|
||||
mSNTPClient(mAuxService), mRPCHandler(&mNetOps),
|
||||
mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL),
|
||||
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mWSPublicDoor(NULL), mWSPrivateDoor(NULL),
|
||||
mSweepTimer(mAuxService)
|
||||
{
|
||||
RAND_bytes(mNonce256.begin(), mNonce256.size());
|
||||
RAND_bytes(reinterpret_cast<unsigned char *>(&mNonceST), sizeof(mNonceST));
|
||||
@@ -146,7 +147,7 @@ void Application::run()
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Peer interface: disabled" << std::endl;
|
||||
cLog(lsINFO) << "Peer interface: disabled";
|
||||
}
|
||||
|
||||
//
|
||||
@@ -158,10 +159,32 @@ void Application::run()
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "RPC interface: disabled" << std::endl;
|
||||
cLog(lsINFO) << "RPC interface: disabled";
|
||||
}
|
||||
|
||||
mWSDoor = WSDoor::createWSDoor();
|
||||
//
|
||||
// Allow private WS connections.
|
||||
//
|
||||
if (!theConfig.WEBSOCKET_IP.empty() && theConfig.WEBSOCKET_PORT)
|
||||
{
|
||||
mWSPrivateDoor = WSDoor::createWSDoor(theConfig.WEBSOCKET_IP, theConfig.WEBSOCKET_PORT, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "WS private interface: disabled";
|
||||
}
|
||||
|
||||
//
|
||||
// Allow public WS connections.
|
||||
//
|
||||
if (!theConfig.WEBSOCKET_PUBLIC_IP.empty() && theConfig.WEBSOCKET_PUBLIC_PORT)
|
||||
{
|
||||
mWSPublicDoor = WSDoor::createWSDoor(theConfig.WEBSOCKET_PUBLIC_IP, theConfig.WEBSOCKET_PUBLIC_PORT, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsINFO) << "WS public interface: disabled";
|
||||
}
|
||||
|
||||
//
|
||||
// Begin connecting to network.
|
||||
@@ -180,9 +203,13 @@ void Application::run()
|
||||
|
||||
mIOService.run(); // This blocks
|
||||
|
||||
mWSDoor->stop();
|
||||
if (mWSPublicDoor)
|
||||
mWSPublicDoor->stop();
|
||||
|
||||
std::cout << "Done." << std::endl;
|
||||
if (mWSPrivateDoor)
|
||||
mWSPrivateDoor->stop();
|
||||
|
||||
cLog(lsINFO) << "Done.";
|
||||
}
|
||||
|
||||
void Application::sweep()
|
||||
|
||||
@@ -62,7 +62,8 @@ class Application
|
||||
ConnectionPool mConnectionPool;
|
||||
PeerDoor* mPeerDoor;
|
||||
RPCDoor* mRPCDoor;
|
||||
WSDoor* mWSDoor;
|
||||
WSDoor* mWSPublicDoor;
|
||||
WSDoor* mWSPrivateDoor;
|
||||
|
||||
uint256 mNonce256;
|
||||
std::size_t mNonceST;
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#define SECTION_UNL_DEFAULT "unl_default"
|
||||
#define SECTION_VALIDATION_QUORUM "validation_quorum"
|
||||
#define SECTION_VALIDATION_SEED "validation_seed"
|
||||
#define SECTION_WEBSOCKET_PUBLIC_IP "websocket_public_ip"
|
||||
#define SECTION_WEBSOCKET_PUBLIC_PORT "websocket_public_port"
|
||||
#define SECTION_WEBSOCKET_IP "websocket_ip"
|
||||
#define SECTION_WEBSOCKET_PORT "websocket_port"
|
||||
#define SECTION_VALIDATORS "validators"
|
||||
@@ -124,6 +126,7 @@ void Config::setup(const std::string& strConf)
|
||||
PEER_PORT = SYSTEM_PEER_PORT;
|
||||
RPC_PORT = 5001;
|
||||
WEBSOCKET_PORT = SYSTEM_WEBSOCKET_PORT;
|
||||
WEBSOCKET_PUBLIC_PORT = SYSTEM_WEBSOCKET_PUBLIC_PORT;
|
||||
NUMBER_CONNECTIONS = 30;
|
||||
|
||||
// a new ledger every minute
|
||||
@@ -235,6 +238,11 @@ void Config::load()
|
||||
if (sectionSingleB(secConfig, SECTION_WEBSOCKET_PORT, strTemp))
|
||||
WEBSOCKET_PORT = boost::lexical_cast<int>(strTemp);
|
||||
|
||||
(void) sectionSingleB(secConfig, SECTION_WEBSOCKET_PUBLIC_IP, WEBSOCKET_PUBLIC_IP);
|
||||
|
||||
if (sectionSingleB(secConfig, SECTION_WEBSOCKET_PUBLIC_PORT, strTemp))
|
||||
WEBSOCKET_PUBLIC_PORT = boost::lexical_cast<int>(strTemp);
|
||||
|
||||
if (sectionSingleB(secConfig, SECTION_VALIDATION_SEED, strTemp))
|
||||
{
|
||||
VALIDATION_SEED.setSeedGeneric(strTemp);
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
#define DEFAULT_VALIDATORS_SITE "redstem.com"
|
||||
#define VALIDATORS_FILE_NAME "validators.txt"
|
||||
|
||||
const int SYSTEM_PEER_PORT = 6561;
|
||||
const int SYSTEM_WEBSOCKET_PORT = 6562;
|
||||
const int SYSTEM_PEER_PORT = 6561;
|
||||
const int SYSTEM_WEBSOCKET_PORT = 6562;
|
||||
const int SYSTEM_WEBSOCKET_PUBLIC_PORT = 6563; // XXX Going away.
|
||||
|
||||
// Allow anonymous DH.
|
||||
#define DEFAULT_PEER_SSL_CIPHER_LIST "ALL:!LOW:!EXP:!MD5:@STRENGTH"
|
||||
@@ -82,6 +83,9 @@ public:
|
||||
unsigned int PEER_CONNECT_LOW_WATER;
|
||||
|
||||
// Websocket networking parameters
|
||||
std::string WEBSOCKET_PUBLIC_IP; // XXX Going away. Merge with the inbound peer connction.
|
||||
int WEBSOCKET_PUBLIC_PORT;
|
||||
|
||||
std::string WEBSOCKET_IP;
|
||||
int WEBSOCKET_PORT;
|
||||
|
||||
|
||||
@@ -110,6 +110,21 @@ bool ConnectionPool::savePeer(const std::string& strIp, int iPort, char code)
|
||||
return bNew;
|
||||
}
|
||||
|
||||
Peer::pointer ConnectionPool::getPeerById(const uint64& id)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
const boost::unordered_map<uint64, Peer::pointer>::iterator& it = mPeerIdMap.find(id);
|
||||
if (it == mPeerIdMap.end())
|
||||
return Peer::pointer();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool ConnectionPool::hasPeer(const uint64& id)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
return mPeerIdMap.find(id) != mPeerIdMap.end();
|
||||
}
|
||||
|
||||
// An available peer is one we had no trouble connect to last time and that we are not currently knowingly connected or connecting
|
||||
// too.
|
||||
//
|
||||
@@ -268,11 +283,11 @@ void ConnectionPool::relayMessageTo(const std::set<uint64>& fromPeers, const Pac
|
||||
{ // Relay message to the specified peers
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
BOOST_FOREACH(naPeer pair, mConnectedMap)
|
||||
BOOST_FOREACH(const uint64& peerID, fromPeers)
|
||||
{
|
||||
Peer::ref peer = pair.second;
|
||||
if (peer->isConnected() && (fromPeers.count(peer->getPeerId()) > 0))
|
||||
peer->sendPacket(msg);
|
||||
const boost::unordered_map<uint64, Peer::pointer>::iterator& it = mPeerIdMap.find(peerID);
|
||||
if ((it != mPeerIdMap.end()) && it->second->isConnected())
|
||||
it->second->sendPacket(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -403,7 +418,7 @@ bool ConnectionPool::peerConnected(Peer::ref peer, const RippleAddress& naPeer,
|
||||
else
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
boost::unordered_map<RippleAddress, Peer::pointer>::iterator itCm = mConnectedMap.find(naPeer);
|
||||
const boost::unordered_map<RippleAddress, Peer::pointer>::iterator& itCm = mConnectedMap.find(naPeer);
|
||||
|
||||
if (itCm == mConnectedMap.end())
|
||||
{
|
||||
@@ -412,6 +427,9 @@ bool ConnectionPool::peerConnected(Peer::ref peer, const RippleAddress& naPeer,
|
||||
|
||||
mConnectedMap[naPeer] = peer;
|
||||
bNew = true;
|
||||
|
||||
assert(peer->getPeerId() != 0);
|
||||
mPeerIdMap.insert(std::make_pair(peer->getPeerId(), peer));
|
||||
}
|
||||
// Found in map, already connected.
|
||||
else if (!strIP.empty())
|
||||
@@ -450,13 +468,11 @@ bool ConnectionPool::peerConnected(Peer::ref peer, const RippleAddress& naPeer,
|
||||
// We maintain a map of public key to peer for connected and verified peers. Maintain it.
|
||||
void ConnectionPool::peerDisconnected(Peer::ref peer, const RippleAddress& naPeer)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
if (naPeer.isValid())
|
||||
{
|
||||
boost::unordered_map<RippleAddress, Peer::pointer>::iterator itCm;
|
||||
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
itCm = mConnectedMap.find(naPeer);
|
||||
const boost::unordered_map<RippleAddress, Peer::pointer>::iterator& itCm = mConnectedMap.find(naPeer);
|
||||
|
||||
if (itCm == mConnectedMap.end())
|
||||
{
|
||||
@@ -482,6 +498,9 @@ void ConnectionPool::peerDisconnected(Peer::ref peer, const RippleAddress& naPee
|
||||
{
|
||||
//cLog(lsINFO) << "Pool: disconnected: anonymous: " << peer->getIP() << " " << peer->getPort();
|
||||
}
|
||||
|
||||
assert(peer->getPeerId() != 0);
|
||||
mPeerIdMap.erase(peer->getPeerId());
|
||||
}
|
||||
|
||||
// Schedule for immediate scanning, if not already scheduled.
|
||||
@@ -553,9 +572,7 @@ void ConnectionPool::peerClosed(Peer::ref peer, const std::string& strIp, int iP
|
||||
bool bRedundant = true;
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
boost::unordered_map<ipPort, Peer::pointer>::iterator itIp;
|
||||
|
||||
itIp = mIpMap.find(ipPeer);
|
||||
const boost::unordered_map<ipPort, Peer::pointer>::iterator& itIp = mIpMap.find(ipPeer);
|
||||
|
||||
if (itIp == mIpMap.end())
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ private:
|
||||
boost::mutex mPeerLock;
|
||||
uint64 mLastPeer;
|
||||
|
||||
typedef std::pair<RippleAddress, Peer::pointer> naPeer;
|
||||
typedef std::pair<RippleAddress, Peer::pointer> naPeer;
|
||||
typedef std::pair<ipPort, Peer::pointer> pipPeer;
|
||||
|
||||
// Peers we are connecting with and non-thin peers we are connected to.
|
||||
@@ -33,6 +33,9 @@ private:
|
||||
// Peers we have the public key for.
|
||||
boost::unordered_map<RippleAddress, Peer::pointer> mConnectedMap;
|
||||
|
||||
// Connections with have a 64-bit identifier
|
||||
boost::unordered_map<uint64, Peer::pointer> mPeerIdMap;
|
||||
|
||||
boost::asio::ssl::context mCtx;
|
||||
|
||||
Peer::pointer mScanning;
|
||||
@@ -94,6 +97,8 @@ public:
|
||||
|
||||
// Peer 64-bit ID function
|
||||
uint64 assignPeerId();
|
||||
Peer::pointer getPeerById(const uint64& id);
|
||||
bool hasPeer(const uint64& id);
|
||||
|
||||
//
|
||||
// Scanning
|
||||
|
||||
@@ -76,7 +76,7 @@ void HashedObjectStore::bulkWrite()
|
||||
return;
|
||||
}
|
||||
}
|
||||
cLog(lsTRACE) << "HOS: writing " << set.size();
|
||||
// cLog(lsTRACE) << "HOS: writing " << set.size();
|
||||
|
||||
static boost::format fExists("SELECT ObjType FROM CommittedObjects WHERE Hash = '%s';");
|
||||
static boost::format
|
||||
|
||||
@@ -36,10 +36,10 @@ public:
|
||||
HashedObject(HashedObjectType type, uint32 index, const std::vector<unsigned char>& data, const uint256& hash) :
|
||||
mType(type), mHash(hash), mLedgerIndex(index), mData(data) { ; }
|
||||
|
||||
const std::vector<unsigned char>& getData() { return mData; }
|
||||
const uint256& getHash() { return mHash; }
|
||||
HashedObjectType getType() { return mType; }
|
||||
uint32 getIndex() { return mLedgerIndex; }
|
||||
const std::vector<unsigned char>& getData() const { return mData; }
|
||||
const uint256& getHash() const { return mHash; }
|
||||
HashedObjectType getType() const { return mType; }
|
||||
uint32 getIndex() const { return mLedgerIndex; }
|
||||
};
|
||||
|
||||
class HashedObjectStore
|
||||
|
||||
@@ -26,42 +26,15 @@ PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterva
|
||||
void PeerSet::peerHas(Peer::ref ptr)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
std::vector< boost::weak_ptr<Peer> >::iterator it = mPeers.begin();
|
||||
while (it != mPeers.end())
|
||||
{
|
||||
Peer::pointer pr = it->lock();
|
||||
if (!pr) // we have a dead entry, remove it
|
||||
it = mPeers.erase(it);
|
||||
else
|
||||
{
|
||||
if (pr->samePeer(ptr))
|
||||
return; // we already have this peer
|
||||
++it;
|
||||
}
|
||||
}
|
||||
mPeers.push_back(ptr);
|
||||
if (!mPeers.insert(std::make_pair(ptr->getPeerId(), 0)).second)
|
||||
return;
|
||||
newPeer(ptr);
|
||||
}
|
||||
|
||||
void PeerSet::badPeer(Peer::ref ptr)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
std::vector< boost::weak_ptr<Peer> >::iterator it = mPeers.begin();
|
||||
while (it != mPeers.end())
|
||||
{
|
||||
Peer::pointer pr = it->lock();
|
||||
if (!pr) // we have a dead entry, remove it
|
||||
it = mPeers.erase(it);
|
||||
else
|
||||
{
|
||||
if (ptr->samePeer(pr))
|
||||
{ // We found a pointer to the bad peer
|
||||
mPeers.erase(it);
|
||||
return;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
mPeers.erase(ptr->getPeerId());
|
||||
}
|
||||
|
||||
void PeerSet::resetTimer()
|
||||
@@ -76,10 +49,13 @@ void PeerSet::invokeOnTimer()
|
||||
{
|
||||
++mTimeouts;
|
||||
cLog(lsWARNING) << "Timeout(" << mTimeouts << ") pc=" << mPeers.size() << " acquiring " << mHash;
|
||||
onTimer(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mProgress = false;
|
||||
onTimer();
|
||||
onTimer(true);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerSet::TimerEntry(boost::weak_ptr<PeerSet> wptr, const boost::system::error_code& result)
|
||||
@@ -138,18 +114,19 @@ bool LedgerAcquire::tryLocal()
|
||||
return mHaveTransactions && mHaveState;
|
||||
}
|
||||
|
||||
void LedgerAcquire::onTimer()
|
||||
void LedgerAcquire::onTimer(bool progress)
|
||||
{
|
||||
if (getTimeouts() > 6)
|
||||
{
|
||||
setFailed();
|
||||
done();
|
||||
}
|
||||
else
|
||||
else if (!progress)
|
||||
{
|
||||
if (!getPeerCount())
|
||||
addPeers();
|
||||
trigger(Peer::pointer(), true);
|
||||
else
|
||||
trigger(Peer::pointer(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,13 +202,13 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
if (sLog(lsTRACE))
|
||||
{
|
||||
if (peer)
|
||||
cLog(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP();
|
||||
cLog(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP();
|
||||
else
|
||||
cLog(lsTRACE) << "Trigger acquiring ledger " << mHash;
|
||||
cLog(lsTRACE) << "Trigger acquiring ledger " << mHash;
|
||||
if (mComplete || mFailed)
|
||||
cLog(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
|
||||
cLog(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed;
|
||||
else
|
||||
cLog(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
|
||||
cLog(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
|
||||
}
|
||||
|
||||
if (!mHaveBase)
|
||||
@@ -281,7 +258,7 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
BOOST_FOREACH(SHAMapNode& it, nodeIDs)
|
||||
*(tmGL.add_nodeids()) = it.getRawString();
|
||||
cLog(lsTRACE) << "Sending TX node " << nodeIDs.size()
|
||||
<< "request to " << (peer ? "selected peer" : "all peers");
|
||||
<< " request to " << (peer ? "selected peer" : "all peers");
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
}
|
||||
@@ -325,7 +302,8 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer)
|
||||
BOOST_FOREACH(SHAMapNode& it, nodeIDs)
|
||||
*(tmGL.add_nodeids()) = it.getRawString();
|
||||
cLog(lsTRACE) << "Sending AS node " << nodeIDs.size()
|
||||
<< "request to " << (peer ? "selected peer" : "all peers");
|
||||
<< " request to " << (peer ? "selected peer" : "all peers");
|
||||
tLog(nodeIDs.size() == 1, lsTRACE) << "AS node: " << nodeIDs[0];
|
||||
sendRequest(tmGL, peer);
|
||||
}
|
||||
}
|
||||
@@ -355,42 +333,32 @@ void PeerSet::sendRequest(const ripple::TMGetLedger& tmGL)
|
||||
return;
|
||||
|
||||
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tmGL, ripple::mtGET_LEDGER);
|
||||
|
||||
std::vector< boost::weak_ptr<Peer> >::iterator it = mPeers.begin();
|
||||
while (it != mPeers.end())
|
||||
for (boost::unordered_map<uint64, int>::iterator it = mPeers.begin(), end = mPeers.end(); it != end; ++it)
|
||||
{
|
||||
if (it->expired())
|
||||
it = mPeers.erase(it);
|
||||
else
|
||||
{
|
||||
// FIXME: Track last peer sent to and time sent
|
||||
Peer::pointer peer = it->lock();
|
||||
if (peer)
|
||||
peer->sendPacket(packet);
|
||||
return;
|
||||
}
|
||||
Peer::pointer peer = theApp->getConnectionPool().getPeerById(it->first);
|
||||
if (peer)
|
||||
peer->sendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
int PeerSet::takePeerSetFrom(const PeerSet& s)
|
||||
int PeerSet::takePeerSetFrom(const PeerSet& s)
|
||||
{
|
||||
int ret = 0;
|
||||
mPeers.clear();
|
||||
mPeers.reserve(s.mPeers.size());
|
||||
BOOST_FOREACH(const boost::weak_ptr<Peer>& p, s.mPeers)
|
||||
if (p.lock())
|
||||
{
|
||||
mPeers.push_back(p);
|
||||
++ret;
|
||||
}
|
||||
for (boost::unordered_map<uint64, int>::const_iterator it = s.mPeers.begin(), end = s.mPeers.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
mPeers.insert(std::make_pair(it->first, 0));
|
||||
++ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PeerSet::getPeerCount() const
|
||||
{
|
||||
int ret = 0;
|
||||
BOOST_FOREACH(const boost::weak_ptr<Peer>& p, mPeers)
|
||||
if (p.lock())
|
||||
for (boost::unordered_map<uint64, int>::const_iterator it = mPeers.begin(), end = mPeers.end(); it != end; ++it)
|
||||
if (theApp->getConnectionPool().hasPeer(it->first))
|
||||
++ret;
|
||||
return ret;
|
||||
}
|
||||
@@ -464,10 +432,15 @@ bool LedgerAcquire::takeTxNode(const std::list<SHAMapNode>& nodeIDs,
|
||||
bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
|
||||
const std::list< std::vector<unsigned char> >& data)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
cLog(lsTRACE) << "got ASdata acquiring ledger " << mHash;
|
||||
#endif
|
||||
if (!mHaveBase) return false;
|
||||
cLog(lsTRACE) << "got ASdata (" << nodeIDs.size() <<") acquiring ledger " << mHash;
|
||||
tLog(nodeIDs.size() == 1, lsTRACE) << "got AS node: " << nodeIDs.front();
|
||||
|
||||
if (!mHaveBase)
|
||||
{
|
||||
cLog(lsWARNING) << "Don't have ledger base";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
|
||||
std::list< std::vector<unsigned char> >::const_iterator nodeDatait = data.begin();
|
||||
AccountStateSF tFilter(mLedger->getHash(), mLedger->getLedgerSeq());
|
||||
@@ -477,10 +450,16 @@ bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
|
||||
{
|
||||
if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(),
|
||||
*nodeDatait, snfWIRE, &tFilter))
|
||||
{
|
||||
cLog(lsWARNING) << "Bad ledger base";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter))
|
||||
{
|
||||
cLog(lsWARNING) << "Unable to add AS node";
|
||||
return false;
|
||||
}
|
||||
++nodeIDit;
|
||||
++nodeDatait;
|
||||
}
|
||||
@@ -564,7 +543,7 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
return false;
|
||||
}
|
||||
memcpy(hash.begin(), packet.ledgerhash().data(), 32);
|
||||
cLog(lsTRACE) << "Got data for acquiring ledger: " << hash;
|
||||
cLog(lsTRACE) << "Got data ( " << packet.nodes().size() << ") for acquiring ledger: " << hash;
|
||||
|
||||
LedgerAcquire::pointer ledger = find(hash);
|
||||
if (!ledger)
|
||||
@@ -582,7 +561,7 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
}
|
||||
if (!ledger->takeBase(packet.nodes(0).nodedata()))
|
||||
{
|
||||
cLog(lsWARNING) << "Got unwanted base data";
|
||||
cLog(lsWARNING) << "Got invalid base data";
|
||||
return false;
|
||||
}
|
||||
if ((packet.nodes().size() > 1) && !ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata())))
|
||||
@@ -611,7 +590,10 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref
|
||||
{
|
||||
const ripple::TMLedgerNode& node = packet.nodes(i);
|
||||
if (!node.has_nodeid() || !node.has_nodedata())
|
||||
{
|
||||
cLog(lsWARNING) << "Got bad node";
|
||||
return false;
|
||||
}
|
||||
|
||||
nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size()));
|
||||
nodeData.push_back(std::vector<unsigned char>(node.nodedata().begin(), node.nodedata().end()));
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
#include "Ledger.h"
|
||||
@@ -28,7 +29,7 @@ protected:
|
||||
|
||||
boost::recursive_mutex mLock;
|
||||
boost::asio::deadline_timer mTimer;
|
||||
std::vector< boost::weak_ptr<Peer> > mPeers;
|
||||
boost::unordered_map<uint64, int> mPeers;
|
||||
|
||||
PeerSet(const uint256& hash, int interval);
|
||||
virtual ~PeerSet() { ; }
|
||||
@@ -53,7 +54,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void newPeer(Peer::ref) = 0;
|
||||
virtual void onTimer(void) = 0;
|
||||
virtual void onTimer(bool progress) = 0;
|
||||
virtual boost::weak_ptr<PeerSet> pmDowncast() = 0;
|
||||
|
||||
void setComplete() { mComplete = true; }
|
||||
@@ -76,7 +77,7 @@ protected:
|
||||
std::vector< boost::function<void (LedgerAcquire::pointer)> > mOnComplete;
|
||||
|
||||
void done();
|
||||
void onTimer();
|
||||
void onTimer(bool progress);
|
||||
|
||||
void newPeer(Peer::ref peer) { trigger(peer, false); }
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ void TransactionAcquire::done()
|
||||
}
|
||||
}
|
||||
|
||||
void TransactionAcquire::onTimer()
|
||||
void TransactionAcquire::onTimer(bool progress)
|
||||
{
|
||||
if (!getPeerCount())
|
||||
{ // out of peers
|
||||
@@ -68,7 +68,7 @@ void TransactionAcquire::onTimer()
|
||||
peerHas(peer);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (!progress)
|
||||
trigger(Peer::pointer(), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ protected:
|
||||
SHAMap::pointer mMap;
|
||||
bool mHaveRoot;
|
||||
|
||||
void onTimer();
|
||||
void onTimer(bool progress);
|
||||
void newPeer(Peer::ref peer) { trigger(peer, false); }
|
||||
|
||||
void done();
|
||||
|
||||
@@ -860,8 +860,6 @@ uint32 LedgerEntrySet::rippleTransferRate(const uint160& uIssuerID)
|
||||
% !!sleAccount
|
||||
% (uQuality/1000000000.0));
|
||||
|
||||
assert(sleAccount);
|
||||
|
||||
return uQuality;
|
||||
}
|
||||
|
||||
|
||||
@@ -917,12 +917,12 @@ Json::Value NetworkOPs::pubBootstrapAccountInfo(Ledger::ref lpAccepted, const Ri
|
||||
{
|
||||
Json::Value jvObj(Json::objectValue);
|
||||
|
||||
jvObj["type"] = "accountInfoBootstrap";
|
||||
jvObj["account"] = naAccountID.humanAccountID();
|
||||
jvObj["owner"] = getOwnerInfo(lpAccepted, naAccountID);
|
||||
jvObj["ledger_closed_index"] = lpAccepted->getLedgerSeq();
|
||||
jvObj["ledger_closed"] = lpAccepted->getHash().ToString();
|
||||
jvObj["ledger_closed_time"] = Json::Value::UInt(utFromSeconds(lpAccepted->getCloseTimeNC()));
|
||||
jvObj["type"] = "accountInfoBootstrap";
|
||||
jvObj["account"] = naAccountID.humanAccountID();
|
||||
jvObj["owner"] = getOwnerInfo(lpAccepted, naAccountID);
|
||||
jvObj["ledger_index"] = lpAccepted->getLedgerSeq();
|
||||
jvObj["ledger_hash"] = lpAccepted->getHash().ToString();
|
||||
jvObj["ledger_time"] = Json::Value::UInt(utFromSeconds(lpAccepted->getCloseTimeNC()));
|
||||
|
||||
return jvObj;
|
||||
}
|
||||
@@ -930,7 +930,7 @@ Json::Value NetworkOPs::pubBootstrapAccountInfo(Ledger::ref lpAccepted, const Ri
|
||||
void NetworkOPs::pubProposedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult)
|
||||
{
|
||||
Json::Value jvObj = transJson(stTxn, terResult, false, lpCurrent, "transaction");
|
||||
|
||||
|
||||
{
|
||||
boost::interprocess::sharable_lock<boost::interprocess::interprocess_upgradable_mutex> sl(mMonitorLock);
|
||||
BOOST_FOREACH(InfoSub* ispListener, mSubRTTransactions)
|
||||
@@ -956,10 +956,10 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
|
||||
{
|
||||
Json::Value jvObj(Json::objectValue);
|
||||
|
||||
jvObj["type"] = "ledgerClosed";
|
||||
jvObj["ledger_closed_index"] = lpAccepted->getLedgerSeq();
|
||||
jvObj["ledger_closed"] = lpAccepted->getHash().ToString();
|
||||
jvObj["ledger_closed_time"] = Json::Value::UInt(utFromSeconds(lpAccepted->getCloseTimeNC()));
|
||||
jvObj["type"] = "ledgerClosed";
|
||||
jvObj["ledger_index"] = lpAccepted->getLedgerSeq();
|
||||
jvObj["ledger_hash"] = lpAccepted->getHash().ToString();
|
||||
jvObj["ledger_time"] = Json::Value::UInt(utFromSeconds(lpAccepted->getCloseTimeNC()));
|
||||
|
||||
BOOST_FOREACH(InfoSub* ispListener, mSubLedger)
|
||||
{
|
||||
@@ -967,7 +967,7 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// we don't lock since pubAcceptedTransaction is locking
|
||||
if (!mSubTransactions.empty() || !mSubRTTransactions.empty() || !mSubAccount.empty() || !mSubRTAccount.empty() || !mSubmitMap.empty() )
|
||||
@@ -986,8 +986,6 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
|
||||
// TODO: remove old entries from the submit map
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terResult, bool bAccepted, Ledger::ref lpCurrent, const std::string& strType)
|
||||
@@ -1001,8 +999,8 @@ Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terRes
|
||||
jvObj["type"] = strType;
|
||||
jvObj["transaction"] = stTxn.getJson(0);
|
||||
if (bAccepted) {
|
||||
jvObj["ledger_closed_index"] = lpCurrent->getLedgerSeq();
|
||||
jvObj["ledger_closed"] = lpCurrent->getHash().ToString();
|
||||
jvObj["ledger_index"] = lpCurrent->getLedgerSeq();
|
||||
jvObj["ledger_hash"] = lpCurrent->getHash().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1032,7 +1030,7 @@ void NetworkOPs::pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedT
|
||||
ispListener->send(jvObj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pubAccountTransaction(lpCurrent,stTxn,terResult,true);
|
||||
}
|
||||
|
||||
@@ -1181,8 +1179,12 @@ void NetworkOPs::unsubAccountChanges(InfoSub* ispListener)
|
||||
#endif
|
||||
|
||||
// <-- bool: true=added, false=already there
|
||||
bool NetworkOPs::subLedger(InfoSub* ispListener)
|
||||
bool NetworkOPs::subLedger(InfoSub* ispListener, Json::Value& jvResult)
|
||||
{
|
||||
jvResult["ledger_index"] = getClosedLedger()->getLedgerSeq();
|
||||
jvResult["ledger_hash"] = getClosedLedger()->getHash().ToString();
|
||||
jvResult["ledger_time"] = Json::Value::UInt(utFromSeconds(getClosedLedger()->getCloseTimeNC()));
|
||||
|
||||
return mSubLedger.insert(ispListener).second;
|
||||
}
|
||||
|
||||
@@ -1193,8 +1195,10 @@ bool NetworkOPs::unsubLedger(InfoSub* ispListener)
|
||||
}
|
||||
|
||||
// <-- bool: true=added, false=already there
|
||||
bool NetworkOPs::subServer(InfoSub* ispListener)
|
||||
bool NetworkOPs::subServer(InfoSub* ispListener, Json::Value& jvResult)
|
||||
{
|
||||
jvResult["stand_alone"] = theConfig.RUN_STANDALONE;
|
||||
|
||||
return mSubServer.insert(ispListener).second;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,8 +74,8 @@ protected:
|
||||
|
||||
// XXX Split into more locks.
|
||||
boost::interprocess::interprocess_upgradable_mutex mMonitorLock;
|
||||
subInfoMapType mSubAccount;
|
||||
subInfoMapType mSubRTAccount;
|
||||
subInfoMapType mSubAccount;
|
||||
subInfoMapType mSubRTAccount;
|
||||
subSubmitMapType mSubmitMap;
|
||||
|
||||
boost::unordered_set<InfoSub*> mSubLedger; // accepted ledgers
|
||||
@@ -111,11 +111,12 @@ public:
|
||||
return mMode >= omTRACKING;
|
||||
}
|
||||
|
||||
Ledger::pointer getClosedLedger() { return mLedgerMaster->getClosedLedger(); }
|
||||
Ledger::pointer getCurrentLedger() { return mLedgerMaster->getCurrentLedger(); }
|
||||
Ledger::pointer getLedgerByHash(const uint256& hash) { return mLedgerMaster->getLedgerByHash(hash); }
|
||||
Ledger::pointer getLedgerBySeq(const uint32 seq) { return mLedgerMaster->getLedgerBySeq(seq); }
|
||||
|
||||
uint256 getClosedLedger()
|
||||
uint256 getClosedLedgerHash()
|
||||
{ return mLedgerMaster->getClosedLedger()->getHash(); }
|
||||
|
||||
SLE::pointer getSLE(Ledger::pointer lpLedger, const uint256& uHash) { return lpLedger->getSLE(uHash); }
|
||||
@@ -224,10 +225,10 @@ public:
|
||||
void subAccount(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs,bool rt);
|
||||
void unsubAccount(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs,bool rt);
|
||||
|
||||
bool subLedger(InfoSub* ispListener);
|
||||
bool subLedger(InfoSub* ispListener, Json::Value& jvResult);
|
||||
bool unsubLedger(InfoSub* ispListener);
|
||||
|
||||
bool subServer(InfoSub* ispListener);
|
||||
bool subServer(InfoSub* ispListener, Json::Value& jvResult);
|
||||
bool unsubServer(InfoSub* ispListener);
|
||||
|
||||
bool subTransactions(InfoSub* ispListener);
|
||||
|
||||
@@ -1172,6 +1172,10 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
|
||||
map = theApp->getOPs().getTXMap(txHash);
|
||||
if (!map)
|
||||
{
|
||||
if (packet.has_querytype() && !packet.has_requestcookie())
|
||||
{
|
||||
// WRITEME: try to route
|
||||
}
|
||||
cLog(lsERROR) << "We do not have the map our peer wants";
|
||||
punishPeer(PP_INVALID_REQUEST);
|
||||
return;
|
||||
@@ -1326,6 +1330,11 @@ void Peer::recvLedger(ripple::TMLedgerData& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.has_requestcookie())
|
||||
{
|
||||
// WRITEME: Route to original requester
|
||||
}
|
||||
|
||||
if (packet.type() == ripple::liTS_CANDIDATE)
|
||||
{ // got data for a candidate transaction set
|
||||
uint256 hash;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "Log.h"
|
||||
#include "NetworkOPs.h"
|
||||
#include "RPCHandler.h"
|
||||
#include "Application.h"
|
||||
#include "Log.h"
|
||||
#include "RippleLines.h"
|
||||
#include "Wallet.h"
|
||||
#include "RippleAddress.h"
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <boost/foreach.hpp>
|
||||
#include <openssl/md5.h>
|
||||
/*
|
||||
carries out the RPC
|
||||
carries out the RPC
|
||||
|
||||
*/
|
||||
|
||||
@@ -326,8 +326,6 @@ Json::Value RPCHandler::doAcceptLedger(const Json::Value ¶ms)
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// account_info <account>|<nickname>|<account_public_key>
|
||||
// account_info <seed>|<pass_phrase>|<key> [<index>]
|
||||
Json::Value RPCHandler::doAccountInfo(const Json::Value ¶ms)
|
||||
@@ -341,7 +339,7 @@ Json::Value RPCHandler::doAccountInfo(const Json::Value ¶ms)
|
||||
|
||||
// Get info on account.
|
||||
|
||||
uint256 uAccepted = mNetOps->getClosedLedger();
|
||||
uint256 uAccepted = mNetOps->getClosedLedgerHash();
|
||||
Json::Value jAccepted = accountFromString(uAccepted, naAccount, bIndex, strIdent, iIndex);
|
||||
|
||||
if (jAccepted.empty())
|
||||
@@ -507,7 +505,7 @@ Json::Value RPCHandler::doOwnerInfo(const Json::Value& params)
|
||||
|
||||
// Get info on account.
|
||||
|
||||
uint256 uAccepted = mNetOps->getClosedLedger();
|
||||
uint256 uAccepted = mNetOps->getClosedLedgerHash();
|
||||
Json::Value jAccepted = accountFromString(uAccepted, naAccount, bIndex, strIdent, iIndex);
|
||||
|
||||
ret["accepted"] = jAccepted.empty() ? mNetOps->getOwnerInfo(uAccepted, naAccount) : jAccepted;
|
||||
@@ -621,7 +619,7 @@ Json::Value RPCHandler::doProfile(const Json::Value ¶ms)
|
||||
// ripple_lines_get <account>|<nickname>|<account_public_key> [<index>]
|
||||
Json::Value RPCHandler::doRippleLinesGet(const Json::Value ¶ms)
|
||||
{
|
||||
// uint256 uAccepted = mNetOps->getClosedLedger();
|
||||
// uint256 uAccepted = mNetOps->getClosedLedgerHash();
|
||||
|
||||
std::string strIdent = params[0u].asString();
|
||||
bool bIndex;
|
||||
@@ -690,24 +688,36 @@ Json::Value RPCHandler::doRippleLinesGet(const Json::Value ¶ms)
|
||||
// submit private_key json
|
||||
Json::Value RPCHandler::doSubmit(const Json::Value& params)
|
||||
{
|
||||
Json::Value txJSON;
|
||||
Json::Reader reader;
|
||||
if(reader.parse(params[1u].asString(),txJSON))
|
||||
Json::Value txJSON;
|
||||
Json::Reader reader;
|
||||
|
||||
if (reader.parse(params[1u].asString(), txJSON))
|
||||
{
|
||||
return handleJSONSubmit(params[0u].asString(), txJSON );
|
||||
Json::Value jvRequest;
|
||||
|
||||
jvRequest["secret"] = params[0u].asString();
|
||||
jvRequest["tx_json"] = txJSON;
|
||||
|
||||
return handleJSONSubmit(jvRequest);
|
||||
}
|
||||
|
||||
return rpcError(rpcSRC_ACT_MALFORMED);
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
}
|
||||
|
||||
Json::Value RPCHandler::doSubmitJson(const Json::Value& jvRequest)
|
||||
{
|
||||
return handleJSONSubmit(jvRequest);
|
||||
}
|
||||
|
||||
|
||||
Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest)
|
||||
{
|
||||
Json::Value jvResult;
|
||||
Json::Value jvResult;
|
||||
RippleAddress naSeed;
|
||||
RippleAddress srcAddress;
|
||||
Json::Value txJSON = jvRequest["tx_json"];
|
||||
|
||||
if (!naSeed.setSeedGeneric(key))
|
||||
if (!naSeed.setSeedGeneric(jvRequest["secret"].asString()))
|
||||
{
|
||||
return rpcError(rpcBAD_SEED);
|
||||
}
|
||||
@@ -723,22 +733,28 @@ Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
AccountState::pointer asSrc = mNetOps->getAccountState(uint256(0), srcAddress);
|
||||
|
||||
if( txJSON["type"]=="Payment")
|
||||
{
|
||||
{
|
||||
txJSON["TransactionType"]=0;
|
||||
|
||||
RippleAddress dstAccountID;
|
||||
|
||||
if (!txJSON.isMember("Destination"))
|
||||
{
|
||||
return rpcError(rpcDST_ACT_MISSING);
|
||||
}
|
||||
if (!dstAccountID.setAccountID(txJSON["Destination"].asString()))
|
||||
{
|
||||
return rpcError(rpcDST_ACT_MALFORMED);
|
||||
}
|
||||
|
||||
|
||||
if(!txJSON.isMember("Fee"))
|
||||
{
|
||||
if(mNetOps->getAccountState(uint256(0), dstAccountID))
|
||||
txJSON["Fee"]=(int)theConfig.FEE_DEFAULT;
|
||||
else txJSON["Fee"]=(int)theConfig.FEE_ACCOUNT_CREATE;
|
||||
}
|
||||
if(!txJSON.isMember("Paths"))
|
||||
|
||||
if(!txJSON.isMember("Paths") && (!jvRequest.isMember("build_path") || jvRequest["build_path"].asBool()))
|
||||
{
|
||||
if(txJSON["Amount"].isObject() || txJSON.isMember("SendMax") )
|
||||
{ // we need a ripple path
|
||||
@@ -746,11 +762,15 @@ Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
uint160 srcCurrencyID;
|
||||
if(txJSON.isMember("SendMax") && txJSON["SendMax"].isMember("currency"))
|
||||
{
|
||||
STAmount::currencyFromString(srcCurrencyID, "XRP");
|
||||
}else STAmount::currencyFromString(srcCurrencyID, txJSON["SendMax"]["currency"].asString());
|
||||
STAmount::currencyFromString(srcCurrencyID, txJSON["SendMax"]["currency"].asString());
|
||||
}
|
||||
else
|
||||
{
|
||||
srcCurrencyID = CURRENCY_XRP;
|
||||
}
|
||||
|
||||
STAmount dstAmount;
|
||||
if(txJSON["Amount"].isObject())
|
||||
if(txJSON["Amount"].isObject())
|
||||
{
|
||||
std::string issuerStr;
|
||||
if( txJSON["Amount"].isMember("issuer")) issuerStr=txJSON["Amount"]["issuer"].asString();
|
||||
@@ -771,7 +791,7 @@ Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
else txJSON["Flags"]=2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}else if( txJSON["type"]=="OfferCreate" )
|
||||
{
|
||||
txJSON["TransactionType"]=7;
|
||||
@@ -789,11 +809,11 @@ Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
txJSON.removeMember("type");
|
||||
|
||||
if(!txJSON.isMember("Sequence")) txJSON["Sequence"]=asSrc->getSeq();
|
||||
if(!txJSON.isMember("Flags")) txJSON["Flags"]=0;
|
||||
|
||||
if(!txJSON.isMember("Flags")) txJSON["Flags"]=0;
|
||||
|
||||
Ledger::pointer lpCurrent = mNetOps->getCurrentLedger();
|
||||
SLE::pointer sleAccountRoot = mNetOps->getSLE(lpCurrent, Ledger::getAccountRootIndex(srcAddress.getAccountID()));
|
||||
|
||||
|
||||
if (!sleAccountRoot)
|
||||
{
|
||||
// XXX Ignore transactions for accounts not created.
|
||||
@@ -804,7 +824,7 @@ Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
RippleAddress naAuthorizedPublic;
|
||||
|
||||
|
||||
RippleAddress naSecret = RippleAddress::createSeedGeneric(key);
|
||||
RippleAddress naSecret = RippleAddress::createSeedGeneric(jvRequest["secret"].asString());
|
||||
RippleAddress naMasterGenerator = RippleAddress::createGeneratorPublic(naSecret);
|
||||
|
||||
// Find the index of Account from the master generator, so we can generate the public and private keys.
|
||||
@@ -858,7 +878,7 @@ Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
{
|
||||
jvResult["error"] = "malformedTransaction";
|
||||
jvResult["error_exception"] = e.what();
|
||||
return(jvResult);
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
sopTrans->setFieldVL(sfSigningPubKey, naAccountPublic.getAccountPublic());
|
||||
@@ -888,7 +908,7 @@ Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
{
|
||||
jvResult["error"] = "internalTransaction";
|
||||
jvResult["error_exception"] = e.what();
|
||||
return(jvResult);
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
try
|
||||
@@ -898,19 +918,19 @@ Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
if (!tpTrans) {
|
||||
jvResult["error"] = "invalidTransaction";
|
||||
jvResult["error_exception"] = "Unable to sterilize transaction.";
|
||||
return(jvResult);
|
||||
return jvResult;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
jvResult["error"] = "internalSubmit";
|
||||
jvResult["error_exception"] = e.what();
|
||||
return(jvResult);
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
jvResult["transaction"] = tpTrans->getJson(0);
|
||||
jvResult["tx_json"] = tpTrans->getJson(0);
|
||||
|
||||
if (temUNCERTAIN != tpTrans->getResult())
|
||||
{
|
||||
@@ -923,15 +943,14 @@ Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
|
||||
jvResult["engine_result_code"] = tpTrans->getResult();
|
||||
jvResult["engine_result_message"] = sHuman;
|
||||
}
|
||||
return(jvResult);
|
||||
return jvResult;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
jvResult["error"] = "internalJson";
|
||||
jvResult["error_exception"] = e.what();
|
||||
return(jvResult);
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Json::Value RPCHandler::doServerInfo(const Json::Value& params)
|
||||
@@ -1005,11 +1024,11 @@ Json::Value RPCHandler::doTx(const Json::Value& params)
|
||||
Json::Value RPCHandler::doLedgerClosed(const Json::Value& params)
|
||||
{
|
||||
Json::Value jvResult;
|
||||
uint256 uLedger = mNetOps->getClosedLedger();
|
||||
uint256 uLedger = mNetOps->getClosedLedgerHash();
|
||||
|
||||
jvResult["ledger_closed_index"] = mNetOps->getLedgerID(uLedger);
|
||||
jvResult["ledger_closed"] = uLedger.ToString();
|
||||
//jvResult["ledger_closed_time"] = uLedger.
|
||||
jvResult["ledger_index"] = mNetOps->getLedgerID(uLedger);
|
||||
jvResult["ledger_hash"] = uLedger.ToString();
|
||||
//jvResult["ledger_time"] = uLedger.
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
@@ -1273,22 +1292,22 @@ Json::Value RPCHandler::doWalletAccounts(const Json::Value& params)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Json::Value RPCHandler::doLogRotate(const Json::Value& params)
|
||||
Json::Value RPCHandler::doLogRotate(const Json::Value& params)
|
||||
{
|
||||
return Log::rotateLog();
|
||||
}
|
||||
|
||||
Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& params,int role)
|
||||
Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& params, int role)
|
||||
{
|
||||
cLog(lsTRACE) << "RPC:" << command;
|
||||
cLog(lsTRACE) << "RPC params:" << params;
|
||||
|
||||
static struct {
|
||||
const char* pCommand;
|
||||
doFuncPtr dfpFunc;
|
||||
int iMinParams;
|
||||
int iMaxParams;
|
||||
bool mAdminRequired;
|
||||
const char* pCommand;
|
||||
doFuncPtr dfpFunc;
|
||||
int iMinParams;
|
||||
int iMaxParams;
|
||||
bool mAdminRequired;
|
||||
unsigned int iOptions;
|
||||
} commandsA[] = {
|
||||
{ "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true },
|
||||
@@ -1300,6 +1319,10 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
|
||||
{ "data_store", &RPCHandler::doDataStore, 2, 2, true },
|
||||
{ "get_counts", &RPCHandler::doGetCounts, 0, 1, true },
|
||||
{ "ledger", &RPCHandler::doLedger, 0, 2, false, optNetwork },
|
||||
{ "ledger_accept", &RPCHandler::doLedgerAccept, 0, 0, true, optCurrent },
|
||||
{ "ledger_closed", &RPCHandler::doLedgerClosed, 0, 0, false, optClosed },
|
||||
{ "ledger_current", &RPCHandler::doLedgerCurrent, 0, 0, false, optCurrent },
|
||||
{ "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, optCurrent },
|
||||
{ "log_level", &RPCHandler::doLogLevel, 0, 2, true },
|
||||
{ "logrotate", &RPCHandler::doLogRotate, 0, 0, true },
|
||||
{ "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, optCurrent },
|
||||
@@ -1308,8 +1331,10 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
|
||||
{ "profile", &RPCHandler::doProfile, 1, 9, false, optCurrent },
|
||||
{ "ripple_lines_get", &RPCHandler::doRippleLinesGet, 1, 2, false, optCurrent },
|
||||
{ "submit", &RPCHandler::doSubmit, 2, 2, false, optCurrent },
|
||||
{ "submit_json", &RPCHandler::doSubmitJson, -1, -1, false, optCurrent },
|
||||
{ "server_info", &RPCHandler::doServerInfo, 0, 0, true },
|
||||
{ "stop", &RPCHandler::doStop, 0, 0, true },
|
||||
{ "transaction_entry", &RPCHandler::doTransactionEntry, -1, -1, false, optCurrent },
|
||||
{ "tx", &RPCHandler::doTx, 1, 1, true },
|
||||
{ "tx_history", &RPCHandler::doTxHistory, 1, 1, false, },
|
||||
|
||||
@@ -1344,8 +1369,12 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
|
||||
{
|
||||
return rpcError(rpcNO_PERMISSION);
|
||||
}
|
||||
else if (params.size() < commandsA[i].iMinParams
|
||||
|| (commandsA[i].iMaxParams >= 0 && params.size() > commandsA[i].iMaxParams))
|
||||
else if (commandsA[i].iMinParams >= 0
|
||||
? commandsA[i].iMaxParams
|
||||
? (params.size() < commandsA[i].iMinParams
|
||||
|| (commandsA[i].iMaxParams >= 0 && params.size() > commandsA[i].iMaxParams))
|
||||
: false
|
||||
: params.isArray())
|
||||
{
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
}
|
||||
@@ -1358,7 +1387,7 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
|
||||
{
|
||||
return rpcError(rpcNO_CURRENT);
|
||||
}
|
||||
else if ((commandsA[i].iOptions & optClosed) && mNetOps->getClosedLedger().isZero())
|
||||
else if ((commandsA[i].iOptions & optClosed) && !mNetOps->getClosedLedger())
|
||||
{
|
||||
return rpcError(rpcNO_CLOSED);
|
||||
}
|
||||
@@ -1590,6 +1619,7 @@ Json::Value RPCHandler::doUnlLoad(const Json::Value& params)
|
||||
Json::Value RPCHandler::doLedgerAccept(const Json::Value& )
|
||||
{
|
||||
Json::Value jvResult;
|
||||
|
||||
if (!theConfig.RUN_STANDALONE)
|
||||
{
|
||||
jvResult["error"] = "notStandAlone";
|
||||
@@ -1600,17 +1630,13 @@ Json::Value RPCHandler::doLedgerAccept(const Json::Value& )
|
||||
|
||||
jvResult["ledger_current_index"] = mNetOps->getCurrentLedgerID();
|
||||
}
|
||||
return(jvResult);
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
|
||||
Json::Value RPCHandler::doTransactionEntry(const Json::Value& params)
|
||||
Json::Value RPCHandler::doTransactionEntry(const Json::Value& jvRequest)
|
||||
{
|
||||
Json::Value jvResult;
|
||||
Json::Value jvRequest;
|
||||
Json::Reader reader;
|
||||
if(!reader.parse(params[0u].asString(),jvRequest))
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
|
||||
if (!jvRequest.isMember("tx_hash"))
|
||||
{
|
||||
@@ -1640,36 +1666,29 @@ Json::Value RPCHandler::doTransactionEntry(const Json::Value& params)
|
||||
Transaction::pointer tpTrans;
|
||||
TransactionMetaSet::pointer tmTrans;
|
||||
|
||||
if (!lpLedger-> getTransaction(uTransID, tpTrans, tmTrans))
|
||||
if (!lpLedger->getTransaction(uTransID, tpTrans, tmTrans))
|
||||
{
|
||||
jvResult["error"] = "transactionNotFound";
|
||||
}
|
||||
else
|
||||
{
|
||||
jvResult["transaction"] = tpTrans->getJson(0);
|
||||
jvResult["metadata"] = tmTrans->getJson(0);
|
||||
jvResult["tx_json"] = tpTrans->getJson(0);
|
||||
jvResult["metadata"] = tmTrans->getJson(0);
|
||||
// 'accounts'
|
||||
// 'engine_...'
|
||||
// 'ledger_...'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Json::Value RPCHandler::doLedgerEntry(const Json::Value& params)
|
||||
Json::Value RPCHandler::doLedgerEntry(const Json::Value& jvRequest)
|
||||
{
|
||||
Json::Value jvResult;
|
||||
Json::Value jvRequest;
|
||||
Json::Reader reader;
|
||||
if(!reader.parse(params[0u].asString(),jvRequest))
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
|
||||
|
||||
uint256 uLedger = jvRequest.isMember("ledger_closed") ? uint256(jvRequest["ledger_closed"].asString()) : 0;
|
||||
uint256 uLedger = jvRequest.isMember("ledger_hash") ? uint256(jvRequest["ledger_hash"].asString()) : 0;
|
||||
uint32 uLedgerIndex = jvRequest.isMember("ledger_index") && jvRequest["ledger_index"].isNumeric() ? jvRequest["ledger_index"].asUInt() : 0;
|
||||
|
||||
Ledger::pointer lpLedger;
|
||||
@@ -1707,9 +1726,9 @@ Json::Value RPCHandler::doLedgerEntry(const Json::Value& params)
|
||||
if (lpLedger->isClosed())
|
||||
{
|
||||
if (!!uLedger)
|
||||
jvResult["ledger_closed"] = uLedger.ToString();
|
||||
jvResult["ledger_hash"] = uLedger.ToString();
|
||||
|
||||
jvResult["ledger_closed_index"] = uLedgerIndex;
|
||||
jvResult["ledger_index"] = uLedgerIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1907,7 +1926,7 @@ Json::Value RPCHandler::doLedgerEntry(const Json::Value& params)
|
||||
jvResult["index"] = uNodeIndex.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class RPCHandler
|
||||
Json::Value accountFromString(const uint256& uLedger, RippleAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex);
|
||||
|
||||
Json::Value doAcceptLedger(const Json::Value ¶ms);
|
||||
|
||||
|
||||
Json::Value doAccountInfo(const Json::Value& params);
|
||||
Json::Value doAccountTransactions(const Json::Value& params);
|
||||
Json::Value doConnect(const Json::Value& params);
|
||||
@@ -39,21 +39,22 @@ class RPCHandler
|
||||
Json::Value doLedger(const Json::Value& params);
|
||||
Json::Value doLogRotate(const Json::Value& params);
|
||||
Json::Value doNicknameInfo(const Json::Value& params);
|
||||
|
||||
|
||||
Json::Value doOwnerInfo(const Json::Value& params);
|
||||
|
||||
|
||||
Json::Value doProfile(const Json::Value& params);
|
||||
Json::Value doPeers(const Json::Value& params);
|
||||
|
||||
|
||||
Json::Value doRippleLinesGet(const Json::Value ¶ms);
|
||||
Json::Value doServerInfo(const Json::Value& params);
|
||||
Json::Value doSessionClose(const Json::Value& params);
|
||||
Json::Value doSessionOpen(const Json::Value& params);
|
||||
Json::Value doLogLevel(const Json::Value& params);
|
||||
Json::Value doStop(const Json::Value& params);
|
||||
Json::Value doSubmit(const Json::Value& params);
|
||||
Json::Value doSubmitJson(const Json::Value& jvRequest);
|
||||
Json::Value doTx(const Json::Value& params);
|
||||
Json::Value doTxHistory(const Json::Value& params);
|
||||
Json::Value doSubmit(const Json::Value& params);
|
||||
|
||||
|
||||
Json::Value doUnlAdd(const Json::Value& params);
|
||||
@@ -154,8 +155,9 @@ public:
|
||||
Json::Value doCommand(const std::string& command, Json::Value& params,int role);
|
||||
Json::Value rpcError(int iError);
|
||||
|
||||
Json::Value handleJSONSubmit(std::string& key, Json::Value& txJSON);
|
||||
Json::Value handleJSONSubmit(const Json::Value& jvRequest);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
|
||||
@@ -286,7 +286,7 @@ TER RippleCalc::calcNodeDeliverRev(
|
||||
|
||||
STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be adjusted.
|
||||
|
||||
saOutAct = 0;
|
||||
saOutAct.zero(saOutReq);
|
||||
|
||||
while (saOutAct != saOutReq) // Did not deliver limit.
|
||||
{
|
||||
@@ -1650,6 +1650,11 @@ PathState::PathState(
|
||||
uInCurrencyID,
|
||||
uSenderID);
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: pushed: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uSenderID)
|
||||
% STAmount::createHumanCurrency(uInCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uSenderID));
|
||||
|
||||
if (tesSUCCESS == terStatus
|
||||
&& !!uInCurrencyID // First was not XRC
|
||||
&& uInIssuerID != uSenderID) { // Issuer was not same as sender
|
||||
@@ -1667,11 +1672,19 @@ PathState::PathState(
|
||||
: uOutIssuerID
|
||||
: ACCOUNT_XRP;
|
||||
|
||||
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 XRC - will have offer next
|
||||
|| uInCurrencyID != uNxtCurrencyID // Next is different current - will have offer next
|
||||
|| uInIssuerID != uNxtAccountID) // Next is not implied issuer
|
||||
{
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uInIssuerID)
|
||||
% RippleAddress::createHumanAccountID(uInCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uInIssuerID));
|
||||
// Add implied account.
|
||||
terStatus = pushNode(
|
||||
STPathElement::typeAccount
|
||||
|
||||
@@ -215,7 +215,10 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigned cha
|
||||
{ // return value: true=okay, false=error
|
||||
assert(!node.isRoot());
|
||||
if (!isSynching())
|
||||
return false;
|
||||
{
|
||||
cLog(lsINFO) << "AddKnownNode while not synching";
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
|
||||
@@ -224,7 +227,10 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigned cha
|
||||
|
||||
std::stack<SHAMapTreeNode::pointer> stack = getStack(node.getNodeID(), true, true);
|
||||
if (stack.empty())
|
||||
{
|
||||
cLog(lsWARNING) << "AddKnownNode with empty stack";
|
||||
return false;
|
||||
}
|
||||
|
||||
SHAMapTreeNode::pointer iNode = stack.top();
|
||||
if (!iNode)
|
||||
@@ -241,7 +247,7 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigned cha
|
||||
|
||||
if (iNode->getDepth() != (node.getDepth() - 1))
|
||||
{ // Either this node is broken or we didn't request it (yet)
|
||||
cLog(lsINFO) << "unable to hook node " << node;
|
||||
cLog(lsWARNING) << "unable to hook node " << node;
|
||||
cLog(lsINFO) << " stuck at " << *iNode;
|
||||
cLog(lsINFO) << "got depth=" << node.getDepth() << ", walked to= " << iNode->getDepth();
|
||||
return false;
|
||||
@@ -254,7 +260,11 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigned cha
|
||||
return false;
|
||||
}
|
||||
uint256 hash = iNode->getChildHash(branch);
|
||||
if (!hash) return false;
|
||||
if (!hash)
|
||||
{
|
||||
cLog(lsWARNING) << "AddKnownNode for empty branch";
|
||||
return false;
|
||||
}
|
||||
|
||||
SHAMapTreeNode::pointer newNode = boost::make_shared<SHAMapTreeNode>(node, rawNode, mSeq, snfWIRE);
|
||||
if (hash != newNode->getNodeHash()) // these aren't the droids we're looking for
|
||||
@@ -293,6 +303,7 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigned cha
|
||||
}
|
||||
iNode->setFullBelow();
|
||||
} while (!stack.empty());
|
||||
|
||||
if (root->isFullBelow())
|
||||
clearSynching();
|
||||
return true;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
//
|
||||
// WSConnection
|
||||
//
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
#include "WSConnection.h"
|
||||
#include "WSHandler.h"
|
||||
|
||||
#include "../json/reader.h"
|
||||
#include "../json/writer.h"
|
||||
//
|
||||
// WSConnection
|
||||
//
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
WSConnection::~WSConnection()
|
||||
{
|
||||
@@ -62,8 +65,6 @@ Json::Value WSConnection::invokeCommand(Json::Value& jvRequest)
|
||||
|
||||
Json::Value jvResult(Json::objectValue);
|
||||
|
||||
jvResult["type"] = "response";
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
jvResult["error"] = "unknownCommand"; // Unknown command.
|
||||
@@ -88,6 +89,8 @@ Json::Value WSConnection::invokeCommand(Json::Value& jvRequest)
|
||||
jvResult["result"] = "success";
|
||||
}
|
||||
|
||||
jvResult["type"] = "response";
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
@@ -131,22 +134,22 @@ void WSConnection::doSubscribe(Json::Value& jvResult, Json::Value& jvRequest)
|
||||
{
|
||||
for (Json::Value::iterator it = jvRequest["streams"].begin(); it != jvRequest["streams"].end(); it++)
|
||||
{
|
||||
if ((*it).isString() )
|
||||
if ((*it).isString())
|
||||
{
|
||||
std::string streamName=(*it).asString();
|
||||
|
||||
if(streamName=="server")
|
||||
{
|
||||
mNetwork.subServer(this);
|
||||
mNetwork.subServer(this, jvResult);
|
||||
}else if(streamName=="ledger")
|
||||
{
|
||||
mNetwork.subLedger(this);
|
||||
mNetwork.subLedger(this, jvResult);
|
||||
}else if(streamName=="transactions")
|
||||
{
|
||||
mNetwork.subTransactions(this);
|
||||
}else if(streamName=="rt_transactions")
|
||||
{
|
||||
mNetwork.subRTTransactions(this);
|
||||
mNetwork.subRTTransactions(this);
|
||||
}else
|
||||
{
|
||||
jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
|
||||
@@ -220,7 +223,7 @@ void WSConnection::doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest)
|
||||
mNetwork.unsubTransactions(this);
|
||||
}else if(streamName=="rt_transactions")
|
||||
{
|
||||
mNetwork.unsubRTTransactions(this);
|
||||
mNetwork.unsubRTTransactions(this);
|
||||
}else
|
||||
{
|
||||
jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
|
||||
@@ -273,16 +276,23 @@ void WSConnection::doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WSConnection::doRPC(Json::Value& jvResult, Json::Value& jvRequest)
|
||||
{
|
||||
if (jvRequest.isMember("rpc_command") )
|
||||
{
|
||||
jvResult=theApp->getRPCHandler().doCommand(jvRequest["rpc_command"].asString(),jvRequest["params"],RPCHandler::GUEST);
|
||||
|
||||
}else jvResult["error"] = "fieldNotCommand";
|
||||
jvResult = theApp->getRPCHandler().doCommand(
|
||||
jvRequest["rpc_command"].asString(),
|
||||
jvRequest.isMember("params")
|
||||
? jvRequest["params"]
|
||||
: jvRequest,
|
||||
mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN);
|
||||
|
||||
jvResult["type"] = "response";
|
||||
}
|
||||
else
|
||||
{
|
||||
jvResult["error"] = "fieldNotCommand";
|
||||
}
|
||||
}
|
||||
|
||||
// XXX Currently requires secret. Allow signed transaction as an alternative.
|
||||
@@ -290,15 +300,16 @@ void WSConnection::doSubmit(Json::Value& jvResult, Json::Value& jvRequest)
|
||||
{
|
||||
if (!jvRequest.isMember("tx_json"))
|
||||
{
|
||||
jvResult["error"] = "fieldNotFoundTransaction";
|
||||
}else if (!jvRequest.isMember("key"))
|
||||
jvResult["error"] = "fieldNotFoundTxJson";
|
||||
}else if (!jvRequest.isMember("secret"))
|
||||
{
|
||||
jvResult["error"] = "fieldNotFoundKey";
|
||||
}else
|
||||
jvResult["error"] = "fieldNotFoundSecret";
|
||||
}else
|
||||
{
|
||||
jvResult=theApp->getRPCHandler().handleJSONSubmit(jvRequest["key"].asString(),jvRequest["tx_json"]);
|
||||
jvResult=theApp->getRPCHandler().handleJSONSubmit(jvRequest);
|
||||
|
||||
// TODO: track the transaction mNetwork.subSubmit(this, jvResult["tx hash"] );
|
||||
}
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -52,4 +52,6 @@ public:
|
||||
void doSubscribe(Json::Value& jvResult, Json::Value& jvRequest);
|
||||
void doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest);
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
|
||||
#include "WSDoor.h"
|
||||
#include "Log.h"
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
#include "Application.h"
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
#include "NetworkOPs.h"
|
||||
#include "utils.h"
|
||||
#include "WSConnection.h"
|
||||
#include "WSHandler.h"
|
||||
|
||||
#include "WSDoor.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
@@ -17,8 +20,6 @@
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
//
|
||||
// This is a light weight, untrusted interface for web clients.
|
||||
// For now we don't provide proof. Later we will.
|
||||
@@ -39,10 +40,6 @@ static DH* handleTmpDh(SSL* ssl, int is_export, int iKeyLength)
|
||||
return 512 == iKeyLength ? theApp->getWallet().getDh512() : theApp->getWallet().getDh1024();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void WSDoor::startListening()
|
||||
{
|
||||
// Generate a single SSL context for use by all connections.
|
||||
@@ -57,7 +54,7 @@ void WSDoor::startListening()
|
||||
SSL_CTX_set_tmp_dh_callback(mCtx->native_handle(), handleTmpDh);
|
||||
|
||||
// Construct a single handler for all requests.
|
||||
websocketpp::WSDOOR_SERVER::handler::ptr handler(new WSServerHandler<websocketpp::WSDOOR_SERVER>(mCtx));
|
||||
websocketpp::WSDOOR_SERVER::handler::ptr handler(new WSServerHandler<websocketpp::WSDOOR_SERVER>(mCtx, mPublic));
|
||||
|
||||
// Construct a websocket server.
|
||||
mEndpoint = new websocketpp::WSDOOR_SERVER(handler);
|
||||
@@ -68,25 +65,22 @@ void WSDoor::startListening()
|
||||
// Call the main-event-loop of the websocket server.
|
||||
mEndpoint->listen(
|
||||
boost::asio::ip::tcp::endpoint(
|
||||
boost::asio::ip::address().from_string(theConfig.WEBSOCKET_IP), theConfig.WEBSOCKET_PORT));
|
||||
boost::asio::ip::address().from_string(mIp), mPort));
|
||||
|
||||
delete mEndpoint;
|
||||
}
|
||||
|
||||
WSDoor* WSDoor::createWSDoor()
|
||||
WSDoor* WSDoor::createWSDoor(const std::string& strIp, const int iPort, bool bPublic)
|
||||
{
|
||||
WSDoor* wdpResult = new WSDoor();
|
||||
WSDoor* wdpResult = new WSDoor(strIp, iPort, bPublic);
|
||||
|
||||
if (!theConfig.WEBSOCKET_IP.empty() && theConfig.WEBSOCKET_PORT)
|
||||
{
|
||||
Log(lsINFO) << "Websocket: Listening: " << theConfig.WEBSOCKET_IP << " " << theConfig.WEBSOCKET_PORT;
|
||||
cLog(lsINFO) <<
|
||||
boost::str(boost::format("Websocket: %s: Listening: %s %d ")
|
||||
% (bPublic ? "Public" : "Private")
|
||||
% strIp
|
||||
% iPort);
|
||||
|
||||
wdpResult->mThread = new boost::thread(boost::bind(&WSDoor::startListening, wdpResult));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsINFO) << "Websocket: Disabled";
|
||||
}
|
||||
wdpResult->mThread = new boost::thread(boost::bind(&WSDoor::startListening, wdpResult));
|
||||
|
||||
return wdpResult;
|
||||
}
|
||||
|
||||
@@ -21,16 +21,19 @@ class WSDoor
|
||||
private:
|
||||
websocketpp::WSDOOR_SERVER* mEndpoint;
|
||||
boost::thread* mThread;
|
||||
bool mPublic;
|
||||
std::string mIp;
|
||||
int mPort;
|
||||
|
||||
void startListening();
|
||||
|
||||
public:
|
||||
|
||||
WSDoor() : mEndpoint(0), mThread(0) { ; }
|
||||
WSDoor(const std::string& strIp, int iPort, bool bPublic) : mEndpoint(0), mThread(0), mPublic(bPublic), mIp(strIp), mPort(iPort) { ; }
|
||||
|
||||
void stop();
|
||||
|
||||
static WSDoor* createWSDoor();
|
||||
static WSDoor* createWSDoor(const std::string& strIp, const int iPort, bool bPublic);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,15 +18,18 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
boost::shared_ptr<boost::asio::ssl::context> mCtx;
|
||||
boost::shared_ptr<boost::asio::ssl::context> mCtx;
|
||||
|
||||
protected:
|
||||
boost::mutex mMapLock;
|
||||
boost::mutex mMapLock;
|
||||
// For each connection maintain an associated object to track subscriptions.
|
||||
boost::unordered_map<connection_ptr, boost::shared_ptr<WSConnection> > mMap;
|
||||
bool mPublic;
|
||||
|
||||
public:
|
||||
WSServerHandler(boost::shared_ptr<boost::asio::ssl::context> spCtx) : mCtx(spCtx) {}
|
||||
WSServerHandler(boost::shared_ptr<boost::asio::ssl::context> spCtx, bool bPublic) : mCtx(spCtx), mPublic(bPublic) {}
|
||||
|
||||
bool getPublic() { return mPublic; };
|
||||
|
||||
boost::shared_ptr<boost::asio::ssl::context> on_tls_init()
|
||||
{
|
||||
@@ -87,6 +90,8 @@ public:
|
||||
Json::Value jvRequest;
|
||||
Json::Reader jrReader;
|
||||
|
||||
cLog(lsDEBUG) << "Ws:: Receiving '" << mpMessage->get_payload() << "'";
|
||||
|
||||
if (mpMessage->get_opcode() != websocketpp::frame::opcode::TEXT)
|
||||
{
|
||||
Json::Value jvResult(Json::objectValue);
|
||||
@@ -122,3 +127,5 @@ public:
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -236,13 +236,18 @@ enum TMLedgerType {
|
||||
ltCLOSED = 2;
|
||||
}
|
||||
|
||||
enum TMQueryType {
|
||||
qtINDIRECT = 0;
|
||||
}
|
||||
|
||||
message TMGetLedger {
|
||||
required TMLedgerInfoType itype = 1;
|
||||
optional TMLedgerType ltype = 2;
|
||||
optional bytes ledgerHash = 3; // Can also be the transaction set hash if liTS_CANDIDATE
|
||||
optional uint32 ledgerSeq = 4;
|
||||
repeated bytes nodeIDs = 5;
|
||||
optional uint32 requestCookie = 6;
|
||||
optional uint64 requestCookie = 6;
|
||||
optional TMQueryType queryType = 7;
|
||||
}
|
||||
|
||||
enum TMReplyError {
|
||||
|
||||
@@ -17,7 +17,7 @@ buster.testCase("Remote functions", {
|
||||
'setUp' : testutils.build_setup(),
|
||||
'tearDown' : testutils.build_teardown(),
|
||||
|
||||
'request_ledger_current' :
|
||||
"request_ledger_current" :
|
||||
function (done) {
|
||||
this.remote.request_ledger_current().on('success', function (m) {
|
||||
// console.log(m);
|
||||
@@ -30,15 +30,16 @@ buster.testCase("Remote functions", {
|
||||
|
||||
buster.assert(false);
|
||||
})
|
||||
|
||||
.request();
|
||||
},
|
||||
|
||||
'request_ledger_closed' :
|
||||
"request_ledger_hash" :
|
||||
function (done) {
|
||||
this.remote.request_ledger_closed().on('success', function (m) {
|
||||
this.remote.request_ledger_hash().on('success', function (m) {
|
||||
// console.log("result: %s", JSON.stringify(m));
|
||||
|
||||
buster.assert.equals(m.ledger_closed_index, 2);
|
||||
buster.assert.equals(m.ledger_index, 2);
|
||||
done();
|
||||
})
|
||||
.on('error', function(m) {
|
||||
@@ -49,16 +50,16 @@ buster.testCase("Remote functions", {
|
||||
.request();
|
||||
},
|
||||
|
||||
'manual account_root success' :
|
||||
"manual account_root success" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
this.remote.request_ledger_closed().on('success', function (r) {
|
||||
this.remote.request_ledger_hash().on('success', function (r) {
|
||||
// console.log("result: %s", JSON.stringify(r));
|
||||
|
||||
self.remote
|
||||
.request_ledger_entry('account_root')
|
||||
.ledger_closed(r.ledger_closed)
|
||||
.ledger_hash(r.ledger_hash)
|
||||
.account_root("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
|
||||
.on('success', function (r) {
|
||||
// console.log("account_root: %s", JSON.stringify(r));
|
||||
@@ -82,16 +83,16 @@ buster.testCase("Remote functions", {
|
||||
},
|
||||
|
||||
// XXX This should be detected locally.
|
||||
'account_root remote malformedAddress' :
|
||||
"account_root remote malformedAddress" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
this.remote.request_ledger_closed().on('success', function (r) {
|
||||
this.remote.request_ledger_hash().on('success', function (r) {
|
||||
// console.log("result: %s", JSON.stringify(r));
|
||||
|
||||
self.remote
|
||||
.request_ledger_entry('account_root')
|
||||
.ledger_closed(r.ledger_closed)
|
||||
.ledger_hash(r.ledger_hash)
|
||||
.account_root("zHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
|
||||
.on('success', function (r) {
|
||||
// console.log("account_root: %s", JSON.stringify(r));
|
||||
@@ -115,16 +116,16 @@ buster.testCase("Remote functions", {
|
||||
.request();
|
||||
},
|
||||
|
||||
'account_root entryNotFound' :
|
||||
"account_root entryNotFound" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
this.remote.request_ledger_closed().on('success', function (r) {
|
||||
this.remote.request_ledger_hash().on('success', function (r) {
|
||||
// console.log("result: %s", JSON.stringify(r));
|
||||
|
||||
self.remote
|
||||
.request_ledger_entry('account_root')
|
||||
.ledger_closed(r.ledger_closed)
|
||||
.ledger_hash(r.ledger_hash)
|
||||
.account_root("alice")
|
||||
.on('success', function (r) {
|
||||
// console.log("account_root: %s", JSON.stringify(r));
|
||||
@@ -147,16 +148,16 @@ buster.testCase("Remote functions", {
|
||||
}).request();
|
||||
},
|
||||
|
||||
'ledger_entry index' :
|
||||
"ledger_entry index" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
this.remote.request_ledger_closed().on('success', function (r) {
|
||||
this.remote.request_ledger_hash().on('success', function (r) {
|
||||
// console.log("result: %s", JSON.stringify(r));
|
||||
|
||||
self.remote
|
||||
.request_ledger_entry('index')
|
||||
.ledger_closed(r.ledger_closed)
|
||||
.ledger_hash(r.ledger_hash)
|
||||
.account_root("alice")
|
||||
.index("2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8")
|
||||
.on('success', function (r) {
|
||||
@@ -180,7 +181,7 @@ buster.testCase("Remote functions", {
|
||||
.request();
|
||||
},
|
||||
|
||||
'create account' :
|
||||
"create account" :
|
||||
function (done) {
|
||||
this.remote.transaction()
|
||||
.payment('root', 'alice', Amount.from_json("10000"))
|
||||
|
||||
Reference in New Issue
Block a user