mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 20:25:48 +00:00
Update everything
This commit is contained in:
@@ -110,7 +110,7 @@ Account.prototype.is_valid = function () {
|
||||
return this._account.is_valid();
|
||||
};
|
||||
|
||||
Account.prototype.get_account_info = function(callback) {
|
||||
Account.prototype.get_info = function(callback) {
|
||||
var callback = typeof callback === 'function' ? callback : function(){};
|
||||
this._remote.request_account_info(this._account_id, callback);
|
||||
};
|
||||
@@ -127,7 +127,7 @@ Account.prototype.entry = function (callback) {
|
||||
var self = this;
|
||||
var callback = typeof callback === 'function' ? callback : function(){};
|
||||
|
||||
this.get_account_info(function account_info(err, info) {
|
||||
this.get_info(function account_info(err, info) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
@@ -143,7 +143,7 @@ Account.prototype.entry = function (callback) {
|
||||
Account.prototype.get_next_sequence = function(callback) {
|
||||
var callback = typeof callback === 'function' ? callback : function(){};
|
||||
|
||||
this.get_account_info(function account_info(err, info) {
|
||||
this.get_info(function account_info(err, info) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
|
||||
@@ -28,6 +28,7 @@ var Account = require('./account').Account;
|
||||
var Meta = require('./meta').Meta;
|
||||
var OrderBook = require('./orderbook').OrderBook;
|
||||
var PathFind = require('./pathfind').PathFind;
|
||||
var RippleError = require('./rippleerror').RippleError;
|
||||
|
||||
var utils = require('./utils');
|
||||
var config = require('./config');
|
||||
@@ -253,12 +254,11 @@ Remote.create_remote = function(options, callback) {
|
||||
Remote.prototype.add_server = function (opts) {
|
||||
var self = this;
|
||||
|
||||
var url = ((opts.secure || opts.websocket_ssl) ? 'wss://' : 'ws://') +
|
||||
(opts.host || opts.websocket_ip) + ':' +
|
||||
(opts.port || opts.websocket_port)
|
||||
;
|
||||
|
||||
var server = new Server(this, { url: url });
|
||||
var server = new Server(this, {
|
||||
host : opts.host || opts.websocket_ip,
|
||||
port : opts.port || opts.websocket_port,
|
||||
secure : opts.secure || opts.websocket_ssl
|
||||
});
|
||||
|
||||
function server_message(data) {
|
||||
self._handle_message(data, server);
|
||||
@@ -338,25 +338,23 @@ Remote.prototype._trace = function() {
|
||||
* Connect to the Ripple network.
|
||||
*/
|
||||
Remote.prototype.connect = function (online) {
|
||||
// Downwards compatibility
|
||||
if (!this._servers.length) {
|
||||
throw new Error('No servers available.');
|
||||
}
|
||||
|
||||
switch (typeof online) {
|
||||
case 'undefined':
|
||||
break;
|
||||
|
||||
case 'function':
|
||||
this.once('connect', online);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Downwards compatibility
|
||||
if (!Boolean(online)) {
|
||||
return this.disconnect();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!this._servers.length) {
|
||||
throw new Error('No servers available.');
|
||||
} else {
|
||||
var self = this;
|
||||
|
||||
;(function nextServer(i) {
|
||||
@@ -370,7 +368,6 @@ Remote.prototype.connect = function (online) {
|
||||
}, self._connection_offset);
|
||||
}
|
||||
})(0);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -379,6 +376,10 @@ Remote.prototype.connect = function (online) {
|
||||
* Disconnect from the Ripple network.
|
||||
*/
|
||||
Remote.prototype.disconnect = function (online) {
|
||||
if (!this._servers.length) {
|
||||
throw new Error('No servers available, not disconnecting');
|
||||
}
|
||||
|
||||
this._servers.forEach(function(server) {
|
||||
server.disconnect();
|
||||
});
|
||||
@@ -398,10 +399,7 @@ Remote.prototype._handle_message = function (message, server) {
|
||||
|
||||
if (unexpected) {
|
||||
// Unexpected response from remote.
|
||||
this.emit('error', {
|
||||
error: 'remoteUnexpected',
|
||||
error_message: 'Unexpected response from remote.'
|
||||
});
|
||||
this.emit('error', new RippleError('remoteUnexpected', 'Unexpected response from remote'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -544,8 +542,10 @@ Remote.prototype.request = function (request) {
|
||||
request.emit('error', new Error('No servers available'));
|
||||
} else if (!this._connected) {
|
||||
this.once('connect', this.request.bind(this, request));
|
||||
} else if (request.server === null) {
|
||||
this.emit('error', new Error('Server does not exist'));
|
||||
} else {
|
||||
var server = this._get_server();
|
||||
var server = request.server || this._get_server();
|
||||
if (server) {
|
||||
server.request(request);
|
||||
} else {
|
||||
@@ -739,9 +739,9 @@ Remote.prototype.request_transaction_entry = function (tx_hash, ledger_hash, cal
|
||||
case 'string':
|
||||
request.ledger_hash(ledger_hash);
|
||||
break;
|
||||
case 'function':
|
||||
default:
|
||||
request.ledger_index('validated');
|
||||
callback = ledger_hash;
|
||||
break;
|
||||
}
|
||||
|
||||
request.callback(callback);
|
||||
@@ -752,20 +752,16 @@ Remote.prototype.request_transaction_entry = function (tx_hash, ledger_hash, cal
|
||||
// DEPRECATED: use request_transaction_entry
|
||||
Remote.prototype.request_tx = function (hash, callback) {
|
||||
var request = new Request(this, 'tx');
|
||||
|
||||
request.message.transaction = hash;
|
||||
request.callback(callback);
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
Remote.prototype.request_account_info = function (accountID, callback) {
|
||||
var request = new Request(this, 'account_info');
|
||||
|
||||
request.message.ident = UInt160.json_rewrite(accountID); // DEPRECATED
|
||||
request.message.account = UInt160.json_rewrite(accountID);
|
||||
request.callback(callback);
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
@@ -875,32 +871,23 @@ Remote.prototype.request_book_offers = function (gets, pays, taker, callback) {
|
||||
|
||||
Remote.prototype.request_wallet_accounts = function (seed, callback) {
|
||||
utils.assert(this.trusted); // Don't send secrets.
|
||||
|
||||
var request = new Request(this, 'wallet_accounts');
|
||||
|
||||
request.message.seed = seed;
|
||||
|
||||
return request.callback(callback);
|
||||
};
|
||||
|
||||
Remote.prototype.request_sign = function (secret, tx_json, callback) {
|
||||
utils.assert(this.trusted); // Don't send secrets.
|
||||
|
||||
var request = new Request(this, 'sign');
|
||||
|
||||
request.message.secret = secret;
|
||||
request.message.tx_json = tx_json;
|
||||
|
||||
request.callback(callback);
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
// Submit a transaction.
|
||||
Remote.prototype.request_submit = function (callback) {
|
||||
var request = new Request(this, 'submit');
|
||||
request.callback(callback);
|
||||
return request;
|
||||
return new Request(this, 'submit').callback(callback);
|
||||
};
|
||||
|
||||
//
|
||||
@@ -926,7 +913,7 @@ Remote.prototype._server_prepare_subscribe = function (callback) {
|
||||
|
||||
var request = this.request_subscribe(feeds);
|
||||
|
||||
request.on('success', function (message) {
|
||||
request.once('success', function (message) {
|
||||
self._stand_alone = !!message.stand_alone;
|
||||
self._testnet = !!message.testnet;
|
||||
|
||||
@@ -949,7 +936,7 @@ Remote.prototype._server_prepare_subscribe = function (callback) {
|
||||
// XXX When we have multiple server support, most of this should be tracked
|
||||
// by the Server objects and then aggregated/interpreted by Remote.
|
||||
self._load_base = message.load_base || 256;
|
||||
self._load_factor = message.load_factor || 1.0;
|
||||
self._load_factor = message.load_factor || 256;
|
||||
self._fee_ref = message.fee_ref;
|
||||
self._fee_base = message.fee_base;
|
||||
self._reserve_base = message.reserve_base;
|
||||
@@ -979,52 +966,42 @@ Remote.prototype.ledger_accept = function (callback) {
|
||||
} else {
|
||||
this.emit('error', { error : 'notStandAlone' });
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Return a request to refresh the account balance.
|
||||
Remote.prototype.request_account_balance = function (account, current, callback) {
|
||||
var request = this.request_ledger_entry('account_root');
|
||||
|
||||
request.account_root(account);
|
||||
request.ledger_choose(current);
|
||||
request.once('success', function (message) {
|
||||
request.emit('account_balance', Amount.from_json(message.node.Balance));
|
||||
});
|
||||
|
||||
request.callback(callback, 'account_balance');
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
// Return a request to return the account flags.
|
||||
Remote.prototype.request_account_flags = function (account, current, callback) {
|
||||
var request = this.request_ledger_entry('account_root');
|
||||
|
||||
request.account_root(account);
|
||||
request.ledger_choose(current);
|
||||
request.on('success', function (message) {
|
||||
request.emit('account_flags', message.node.Flags);
|
||||
});
|
||||
|
||||
request.callback(callback, 'account_flags');
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
// Return a request to emit the owner count.
|
||||
Remote.prototype.request_owner_count = function (account, current, callback) {
|
||||
var request = this.request_ledger_entry('account_root');
|
||||
|
||||
request.account_root(account);
|
||||
request.ledger_choose(current);
|
||||
request.on('success', function (message) {
|
||||
request.emit('owner_count', message.node.OwnerCount);
|
||||
});
|
||||
|
||||
request.callback(callback, 'owner_count');
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
@@ -1082,7 +1059,7 @@ Remote.prototype.account_seq = function (account, advance) {
|
||||
|
||||
if (account_info && account_info.seq) {
|
||||
seq = account_info.seq;
|
||||
account_info.seq += { ADVANCE: 1, REWIND: -1 }[advance] || 0;
|
||||
account_info.seq += { ADVANCE: 1, REWIND: -1 }[advance.toUpperCase()] || 0;
|
||||
}
|
||||
|
||||
return seq;
|
||||
@@ -1103,7 +1080,7 @@ Remote.prototype.account_seq_cache = function (account, current, callback) {
|
||||
var self = this;
|
||||
|
||||
if (!this.accounts.hasOwnProperty(account)) {
|
||||
self.accounts[account] = { };
|
||||
this.accounts[account] = { };
|
||||
}
|
||||
|
||||
var account_info = this.accounts[account];
|
||||
@@ -1198,6 +1175,20 @@ Remote.prototype.request_ripple_balance = function (account, issuer, currency, c
|
||||
return request;
|
||||
};
|
||||
|
||||
function prepare_currencies(ci) {
|
||||
var ci_new = { };
|
||||
|
||||
if (ci.hasOwnProperty('issuer')) {
|
||||
ci_new.issuer = UInt160.json_rewrite(ci.issuer);
|
||||
}
|
||||
|
||||
if (ci.hasOwnProperty('currency')) {
|
||||
ci_new.currency = Currency.json_rewrite(ci.currency);
|
||||
}
|
||||
|
||||
return ci_new;
|
||||
}
|
||||
|
||||
Remote.prototype.request_ripple_path_find = function (src_account, dst_account, dst_amount, src_currencies, callback) {
|
||||
var request = new Request(this, 'ripple_path_find');
|
||||
|
||||
@@ -1206,19 +1197,7 @@ Remote.prototype.request_ripple_path_find = function (src_account, dst_account,
|
||||
request.message.destination_amount = Amount.json_rewrite(dst_amount);
|
||||
|
||||
if (src_currencies) {
|
||||
request.message.source_currencies = src_currencies.map(function (ci) {
|
||||
var ci_new = { };
|
||||
|
||||
if (ci.hasOwnProperty('issuer')) {
|
||||
ci_new.issuer = UInt160.json_rewrite(ci.issuer);
|
||||
}
|
||||
|
||||
if (ci.hasOwnProperty('currency')) {
|
||||
ci_new.currency = Currency.json_rewrite(ci.currency);
|
||||
}
|
||||
|
||||
return ci_new;
|
||||
});
|
||||
request.message.source_currencies = src_currencies.map(prepare_currencies);
|
||||
}
|
||||
|
||||
request.callback(callback);
|
||||
@@ -1227,7 +1206,6 @@ Remote.prototype.request_ripple_path_find = function (src_account, dst_account,
|
||||
};
|
||||
|
||||
Remote.prototype.request_path_find_create = function (src_account, dst_account, dst_amount, src_currencies, callback) {
|
||||
var self = this;
|
||||
var request = new Request(this, 'path_find');
|
||||
|
||||
request.message.subcommand = 'create';
|
||||
@@ -1236,19 +1214,7 @@ Remote.prototype.request_path_find_create = function (src_account, dst_account,
|
||||
request.message.destination_amount = Amount.json_rewrite(dst_amount);
|
||||
|
||||
if (src_currencies) {
|
||||
request.message.source_currencies = src_currencies.map(function (ci) {
|
||||
var ci_new = {};
|
||||
|
||||
if (ci.hasOwnProperty('issuer')) {
|
||||
ci_new.issuer = UInt160.json_rewrite(ci.issuer);
|
||||
}
|
||||
|
||||
if (ci.hasOwnProperty('currency')) {
|
||||
ci_new.currency = Currency.json_rewrite(ci.currency);
|
||||
}
|
||||
|
||||
return ci_new;
|
||||
});
|
||||
request.message.source_currencies = src_currencies.map(prepare_currencies);
|
||||
}
|
||||
|
||||
request.callback(callback);
|
||||
@@ -1263,9 +1229,7 @@ Remote.prototype.request_path_find_close = function () {
|
||||
};
|
||||
|
||||
Remote.prototype.request_unl_list = function (callback) {
|
||||
var request = new Request(this, 'unl_list');
|
||||
request.callback(callback);
|
||||
return request;
|
||||
return new Request(this, 'unl_list').callback(callback);
|
||||
};
|
||||
|
||||
Remote.prototype.request_unl_add = function (addr, comment, callback) {
|
||||
@@ -1291,9 +1255,7 @@ Remote.prototype.request_unl_delete = function (node, callback) {
|
||||
};
|
||||
|
||||
Remote.prototype.request_peers = function (callback) {
|
||||
var request = new Request(this, 'peers');
|
||||
request.callback(callback);
|
||||
return request;
|
||||
return new Request(this, 'peers').callback(callback);
|
||||
};
|
||||
|
||||
Remote.prototype.request_connect = function (ip, port, callback) {
|
||||
@@ -1372,6 +1334,36 @@ Remote.prototype.reserve = function (owner_count) {
|
||||
return reserve_base.add(reserve_inc.product_human(owner_count));
|
||||
};
|
||||
|
||||
Remote.prototype.ping = function(host, callback) {
|
||||
var request = new Request(this, 'ping');
|
||||
|
||||
switch (typeof host) {
|
||||
case 'function':
|
||||
callback = host;
|
||||
break;
|
||||
case 'string':
|
||||
var server = null;
|
||||
for (var i=0, s; s=this._servers[i]; i++) {
|
||||
if (s._host === host) {
|
||||
server = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
request.set_server(server);
|
||||
break;
|
||||
}
|
||||
|
||||
var then = Date.now();
|
||||
|
||||
request.once('success', function() {
|
||||
request.emit('pong', Date.now() - then);
|
||||
});
|
||||
|
||||
request.callback(callback, 'pong');
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
exports.Remote = Remote;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
@@ -6,6 +6,7 @@ var Transaction = require('./transaction').Transaction;
|
||||
var Account = require('./account').Account;
|
||||
var Meta = require('./meta').Meta;
|
||||
var OrderBook = require('./orderbook').OrderBook;
|
||||
var RippleError = require('./rippleerror').RippleError;
|
||||
|
||||
// Request events emitted:
|
||||
// 'success' : Request successful.
|
||||
@@ -15,6 +16,7 @@ var OrderBook = require('./orderbook').OrderBook;
|
||||
// 'remoteDisconnected'
|
||||
function Request(remote, command) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
this.remote = remote;
|
||||
this.requested = false;
|
||||
this.message = {
|
||||
@@ -36,8 +38,19 @@ Request.prototype.request = function (remote) {
|
||||
|
||||
Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
||||
if (callback && typeof callback === 'function') {
|
||||
this.once(successEvent || 'success', callback.bind(this, null));
|
||||
this.once(errorEvent || 'error' , callback.bind(this));
|
||||
function request_success(message) {
|
||||
callback.call(this, null, message);
|
||||
}
|
||||
|
||||
function request_error(error) {
|
||||
if (!(error instanceof RippleError)) {
|
||||
error = new RippleError(error);
|
||||
}
|
||||
callback.call(this, error);
|
||||
}
|
||||
|
||||
this.once(successEvent || 'success', request_success);
|
||||
this.once(errorEvent || 'error' , request_error);
|
||||
this.request();
|
||||
}
|
||||
|
||||
@@ -45,12 +58,16 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
||||
};
|
||||
|
||||
Request.prototype.timeout = function(duration, callback) {
|
||||
if (!this.requested) {
|
||||
this.once('request', this.timeout.bind(this, duration, callback));
|
||||
return;
|
||||
};
|
||||
|
||||
var self = this;
|
||||
|
||||
if (!this.requested) {
|
||||
function requested() {
|
||||
self.timeout(duration, callback);
|
||||
}
|
||||
this.once('request', requested);
|
||||
return;
|
||||
}
|
||||
|
||||
var emit = this.emit;
|
||||
var timed_out = false;
|
||||
|
||||
@@ -61,19 +78,23 @@ Request.prototype.timeout = function(duration, callback) {
|
||||
}, duration);
|
||||
|
||||
this.emit = function() {
|
||||
if (timed_out) return;
|
||||
else clearTimeout(timeout);
|
||||
if (!timed_out) {
|
||||
clearTimeout(timeout);
|
||||
emit.apply(self, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.set_server = function(server) {
|
||||
this.server = server;
|
||||
};
|
||||
|
||||
Request.prototype.build_path = function (build) {
|
||||
if (build) {
|
||||
this.message.build_path = true;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -83,16 +104,14 @@ Request.prototype.ledger_choose = function (current) {
|
||||
} else {
|
||||
this.message.ledger_hash = this.remote._ledger_hash;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Set the ledger for a request.
|
||||
// - ledger_entry
|
||||
// - transaction_entry
|
||||
Request.prototype.ledger_hash = function (h) {
|
||||
this.message.ledger_hash = h;
|
||||
|
||||
Request.prototype.ledger_hash = function (hash) {
|
||||
this.message.ledger_hash = hash;
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -100,7 +119,6 @@ Request.prototype.ledger_hash = function (h) {
|
||||
// - ledger_entry
|
||||
Request.prototype.ledger_index = function (ledger_index) {
|
||||
this.message.ledger_index = ledger_index;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -114,10 +132,10 @@ Request.prototype.ledger_select = function (ledger_spec) {
|
||||
|
||||
default:
|
||||
// XXX Better test needed
|
||||
if (String(ledger_spec).length > 12) {
|
||||
this.message.ledger_hash = ledger_spec;
|
||||
} else {
|
||||
if (Number(ledger_spec)) {
|
||||
this.message.ledger_index = ledger_spec;
|
||||
} else {
|
||||
this.message.ledger_hash = ledger_spec;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -127,13 +145,11 @@ Request.prototype.ledger_select = function (ledger_spec) {
|
||||
|
||||
Request.prototype.account_root = function (account) {
|
||||
this.message.account_root = UInt160.json_rewrite(account);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.index = function (hash) {
|
||||
this.message.index = hash;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -145,52 +161,45 @@ Request.prototype.offer_id = function (account, seq) {
|
||||
account: UInt160.json_rewrite(account),
|
||||
seq: seq
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// --> index : ledger entry index.
|
||||
Request.prototype.offer_index = function (index) {
|
||||
this.message.offer = index;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.secret = function (s) {
|
||||
if (s) {
|
||||
this.message.secret = s;
|
||||
Request.prototype.secret = function (secret) {
|
||||
if (secret) {
|
||||
this.message.secret = secret;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.tx_hash = function (h) {
|
||||
this.message.tx_hash = h;
|
||||
|
||||
Request.prototype.tx_hash = function (hash) {
|
||||
this.message.tx_hash = hash;
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.tx_json = function (j) {
|
||||
this.message.tx_json = j;
|
||||
|
||||
Request.prototype.tx_json = function (json) {
|
||||
this.message.tx_json = json;
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.tx_blob = function (j) {
|
||||
this.message.tx_blob = j;
|
||||
|
||||
Request.prototype.tx_blob = function (json) {
|
||||
this.message.tx_blob = json;
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.ripple_state = function (account, issuer, currency) {
|
||||
this.message.ripple_state = {
|
||||
'accounts' : [
|
||||
currency : currency,
|
||||
accounts : [
|
||||
UInt160.json_rewrite(account),
|
||||
UInt160.json_rewrite(issuer)
|
||||
],
|
||||
'currency' : currency
|
||||
]
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -200,14 +209,14 @@ Request.prototype.accounts = function (accounts, realtime) {
|
||||
}
|
||||
|
||||
// Process accounts parameters
|
||||
var procAccounts = accounts.map(function(account) {
|
||||
var processedAccounts = accounts.map(function(account) {
|
||||
return UInt160.json_rewrite(account);
|
||||
});
|
||||
|
||||
if (realtime) {
|
||||
this.message.rt_accounts = procAccounts;
|
||||
this.message.rt_accounts = processedAccounts;
|
||||
} else {
|
||||
this.message.accounts = procAccounts;
|
||||
this.message.accounts = processedAccounts;
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -218,14 +227,16 @@ Request.prototype.rt_accounts = function (accounts) {
|
||||
};
|
||||
|
||||
Request.prototype.books = function (books, snapshot) {
|
||||
var procBooks = [];
|
||||
var processedBooks = [ ];
|
||||
|
||||
for (var i = 0, l = books.length; i < l; i++) {
|
||||
var book = books[i];
|
||||
var json = { };
|
||||
|
||||
function processSide(side) {
|
||||
if (!book[side]) throw new Error('Missing '+side);
|
||||
if (!book[side]) {
|
||||
throw new Error('Missing ' + side);
|
||||
}
|
||||
|
||||
var obj = json[side] = {
|
||||
currency: Currency.json_rewrite(book[side].currency)
|
||||
@@ -239,13 +250,18 @@ Request.prototype.books = function (books, snapshot) {
|
||||
processSide('taker_gets');
|
||||
processSide('taker_pays');
|
||||
|
||||
if (snapshot) json.snapshot = true;
|
||||
if (book.both) json.both = true;
|
||||
|
||||
procBooks.push(json);
|
||||
if (snapshot) {
|
||||
json.snapshot = true;
|
||||
}
|
||||
|
||||
this.message.books = procBooks;
|
||||
if (book.both) {
|
||||
json.both = true;
|
||||
}
|
||||
|
||||
processedBooks.push(json);
|
||||
}
|
||||
|
||||
this.message.books = processedBooks;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -6,8 +6,8 @@ function RippleError(code, message) {
|
||||
extend(this, code);
|
||||
} else {
|
||||
this.result = code;
|
||||
this.result_message = message;
|
||||
this.message = message;
|
||||
this.result_message = message;
|
||||
}
|
||||
|
||||
this.message = this.result_message || 'Error';
|
||||
|
||||
@@ -182,9 +182,11 @@ Transaction.prototype.get_fee = function() {
|
||||
Transaction.prototype.complete = function () {
|
||||
var tx_json = this.tx_json;
|
||||
|
||||
if (typeof tx_json.Fee === 'undefined' && this.remote.local_fee) {
|
||||
if (typeof tx_json.Fee === 'undefined') {
|
||||
if (this.remote.local_fee || !this.remote.trusted) {
|
||||
this.tx_json.Fee = this.remote.fee_tx(this.fee_units()).to_json();
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof tx_json.SigningPubKey === 'undefined' && (!this.remote || this.remote.local_signing)) {
|
||||
var seed = Seed.from_json(this._secret);
|
||||
@@ -200,10 +202,7 @@ Transaction.prototype.serialize = function () {
|
||||
};
|
||||
|
||||
Transaction.prototype.signing_hash = function () {
|
||||
var prefix = config.testnet
|
||||
? Transaction.HASH_SIGN_TESTNET
|
||||
: Transaction.HASH_SIGN;
|
||||
|
||||
var prefix = Transaction[config.testnet ? 'HASH_SIGN_TESTNET' : 'HASH_SIGN'];
|
||||
return SerializedObject.from_json(this.tx_json).signing_hash(prefix);
|
||||
};
|
||||
|
||||
@@ -223,13 +222,6 @@ Transaction.prototype.sign = function () {
|
||||
this.tx_json.TxnSignature = hex;
|
||||
};
|
||||
|
||||
Transaction.prototype._hasTransactionListeners = function() {
|
||||
return this.listeners('final').length
|
||||
|| this.listeners('lost').length
|
||||
|| this.listeners('pending').length
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Set options for Transactions
|
||||
//
|
||||
@@ -239,7 +231,6 @@ Transaction.prototype._hasTransactionListeners = function() {
|
||||
// "blindly" because the sender has no idea of the actual cost except that is must be less than send max.
|
||||
Transaction.prototype.build_path = function (build) {
|
||||
this._build_path = build;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -249,28 +240,27 @@ Transaction.prototype.destination_tag = function (tag) {
|
||||
if (tag !== void(0)) {
|
||||
this.tx_json.DestinationTag = tag;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Transaction._path_rewrite = function (path) {
|
||||
var path_new = [];
|
||||
var props = [
|
||||
'account'
|
||||
, 'issuer'
|
||||
, 'currency'
|
||||
]
|
||||
|
||||
for (var i=0, l=path.length; i<l; i++) {
|
||||
var node = path[i];
|
||||
var path_new = path.map(function(node) {
|
||||
var node_new = { };
|
||||
|
||||
if ('account' in node)
|
||||
node_new.account = UInt160.json_rewrite(node.account);
|
||||
|
||||
if ('issuer' in node)
|
||||
node_new.issuer = UInt160.json_rewrite(node.issuer);
|
||||
|
||||
if ('currency' in node)
|
||||
node_new.currency = Currency.json_rewrite(node.currency);
|
||||
|
||||
path_new.push(node_new);
|
||||
for (var prop in node) {
|
||||
if (~props.indexOf(prop)) {
|
||||
node_new[prop] = UInt160.json_rewrite(node[prop]);
|
||||
}
|
||||
}
|
||||
|
||||
return node_new;
|
||||
});
|
||||
|
||||
return path_new;
|
||||
}
|
||||
@@ -278,7 +268,6 @@ Transaction._path_rewrite = function (path) {
|
||||
Transaction.prototype.path_add = function (path) {
|
||||
this.tx_json.Paths = this.tx_json.Paths || [];
|
||||
this.tx_json.Paths.push(Transaction._path_rewrite(path));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -288,22 +277,20 @@ Transaction.prototype.paths = function (paths) {
|
||||
for (var i=0, l=paths.length; i<l; i++) {
|
||||
this.path_add(paths[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// If the secret is in the config object, it does not need to be provided.
|
||||
Transaction.prototype.secret = function (secret) {
|
||||
this._secret = secret;
|
||||
}
|
||||
};
|
||||
|
||||
Transaction.prototype.send_max = function (send_max) {
|
||||
if (send_max) {
|
||||
this.tx_json.SendMax = Amount.json_rewrite(send_max);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// tag should be undefined or a 32 bit integer.
|
||||
// YYY Add range checking for tag.
|
||||
@@ -311,9 +298,8 @@ Transaction.prototype.source_tag = function (tag) {
|
||||
if (tag) {
|
||||
this.tx_json.SourceTag = tag;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// --> rate: In billionths.
|
||||
Transaction.prototype.transfer_rate = function (rate) {
|
||||
@@ -324,7 +310,7 @@ Transaction.prototype.transfer_rate = function (rate) {
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// Add flags to a transaction.
|
||||
// --> flags: undefined, _flag_, or [ _flags_ ]
|
||||
@@ -339,12 +325,9 @@ Transaction.prototype.set_flags = function (flags) {
|
||||
|
||||
var flag_set = Array.isArray(flags) ? flags : [ flags ];
|
||||
|
||||
for (var index in flag_set) {
|
||||
if (!flag_set.hasOwnProperty(index)) continue;
|
||||
|
||||
var flag = flag_set[index];
|
||||
|
||||
if (flag in transaction_flags) {
|
||||
for (var i=0, l=flag_set.length; i<l; i++) {
|
||||
var flag = flag_set[i];
|
||||
if (transaction_flags.hasOwnProperty(flag)) {
|
||||
this.tx_json.Flags += transaction_flags[flag];
|
||||
} else {
|
||||
// XXX Immediately report an error or mark it.
|
||||
@@ -353,7 +336,7 @@ Transaction.prototype.set_flags = function (flags) {
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Transactions
|
||||
@@ -375,7 +358,6 @@ Transaction.prototype.account_set = function (src) {
|
||||
this._secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'AccountSet';
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -385,7 +367,6 @@ Transaction.prototype.claim = function (src, generator, public_key, signature) {
|
||||
this.tx_json.Generator = generator;
|
||||
this.tx_json.PublicKey = public_key;
|
||||
this.tx_json.Signature = signature;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -394,7 +375,6 @@ Transaction.prototype.offer_cancel = function (src, sequence) {
|
||||
this.tx_json.TransactionType = 'OfferCancel';
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
this.tx_json.OfferSequence = Number(sequence);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -430,7 +410,6 @@ Transaction.prototype.password_fund = function (src, dst) {
|
||||
this._secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'PasswordFund';
|
||||
this.tx_json.Destination = UInt160.json_rewrite(dst);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -441,7 +420,6 @@ Transaction.prototype.password_set = function (src, authorized_key, generator, p
|
||||
this.tx_json.Generator = generator;
|
||||
this.tx_json.PublicKey = public_key;
|
||||
this.tx_json.Signature = signature;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -463,6 +441,14 @@ Transaction.prototype.password_set = function (src, authorized_key, generator, p
|
||||
// .set_flags()
|
||||
// .source_tag()
|
||||
Transaction.prototype.payment = function (src, dst, deliver_amount) {
|
||||
if (!UInt160.is_valid(src)) {
|
||||
throw new Error('Payment source address invalid');
|
||||
}
|
||||
|
||||
if (!UInt160.is_valid(dst)) {
|
||||
throw new Error('Payment destination address invalid');
|
||||
}
|
||||
|
||||
this._secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'Payment';
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
@@ -478,14 +464,17 @@ Transaction.prototype.ripple_line_set = function (src, limit, quality_in, qualit
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
|
||||
// Allow limit of 0 through.
|
||||
if (limit !== void(0))
|
||||
if (limit !== void(0)) {
|
||||
this.tx_json.LimitAmount = Amount.json_rewrite(limit);
|
||||
}
|
||||
|
||||
if (quality_in)
|
||||
if (quality_in) {
|
||||
this.tx_json.QualityIn = quality_in;
|
||||
}
|
||||
|
||||
if (quality_out)
|
||||
if (quality_out) {
|
||||
this.tx_json.QualityOut = quality_out;
|
||||
}
|
||||
|
||||
// XXX Throw an error if nothing is set.
|
||||
|
||||
@@ -499,7 +488,6 @@ Transaction.prototype.wallet_add = function (src, amount, authorized_key, public
|
||||
this.tx_json.RegularKey = authorized_key;
|
||||
this.tx_json.PublicKey = public_key;
|
||||
this.tx_json.Signature = signature;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -519,20 +507,6 @@ Transaction.prototype.fee_units = function () {
|
||||
};
|
||||
|
||||
// Submit a transaction to the network.
|
||||
// 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.
|
||||
// callback = function (status, info) {
|
||||
// // status is final status. Only works under a ledger_accepting conditions.
|
||||
// switch status:
|
||||
// case 'tesSUCCESS': all is well.
|
||||
// case 'tejSecretUnknown': unable to sign transaction - secret unknown
|
||||
// case 'tejServerUntrusted': sending secret to untrusted server.
|
||||
// case 'tejInvalidAccount': locally detected error.
|
||||
// case 'tejLost': locally gave up looking
|
||||
// default: some other TER
|
||||
// }
|
||||
|
||||
Transaction.prototype.submit = function (callback) {
|
||||
var self = this;
|
||||
|
||||
@@ -540,9 +514,9 @@ Transaction.prototype.submit = function (callback) {
|
||||
|
||||
function submission_error(error, message) {
|
||||
if (!(error instanceof RippleError)) {
|
||||
error = new RippleError(error);
|
||||
error = new RippleError(error, message);
|
||||
}
|
||||
self.callback(error, message);
|
||||
self.callback(error);
|
||||
}
|
||||
|
||||
function submission_success(message) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var RippleError = require('./rippleerror').RippleError;
|
||||
var Queue = require('./transactionqueue').TransactionQueue;
|
||||
|
||||
/**
|
||||
* @constructor TransactionManager
|
||||
@@ -16,84 +17,128 @@ function TransactionManager(account) {
|
||||
this.remote = account._remote;
|
||||
this._timeout = void(0);
|
||||
this._resubmitting = false;
|
||||
this._pending = new Queue;
|
||||
this._next_sequence = void(0);
|
||||
this._config = { max_fee: self.remote.max_fee };
|
||||
this._cache = { };
|
||||
|
||||
//XX Fee units
|
||||
this._max_fee = Number(this.remote.max_fee) || Infinity;
|
||||
|
||||
function remote_disconnected() {
|
||||
function remote_reconnected() {
|
||||
self._resubmit();
|
||||
};
|
||||
self.remote.once('connect', remote_reconnected);
|
||||
};
|
||||
|
||||
this.remote.on('disconnect', remote_disconnected);
|
||||
|
||||
function sequence_loaded(err, sequence) {
|
||||
self._next_sequence = sequence;
|
||||
self.emit('sequence_loaded', sequence);
|
||||
};
|
||||
|
||||
this.account.get_next_sequence(sequence_loaded);
|
||||
|
||||
function cache_transaction(message) {
|
||||
var transaction = {
|
||||
ledger_hash: message.ledger_hash,
|
||||
ledger_index: message.ledger_index,
|
||||
metadata: message.meta,
|
||||
tx_json: message.transaction
|
||||
}
|
||||
|
||||
account.get_next_sequence(sequence_loaded);
|
||||
transaction.tx_json.ledger_index = transaction.ledger_index;
|
||||
transaction.tx_json.inLedger = transaction.ledger_index;
|
||||
|
||||
self._cache[message.transaction.Sequence] = transaction;
|
||||
}
|
||||
|
||||
this.account.on('transaction', cache_transaction);
|
||||
};
|
||||
|
||||
util.inherits(TransactionManager, EventEmitter);
|
||||
|
||||
/**
|
||||
* @param {Object} tx
|
||||
*/
|
||||
// request_tx presents transactions in
|
||||
// a format slightly different from
|
||||
// request_transaction_entry
|
||||
function rewrite_transaction(tx) {
|
||||
try {
|
||||
var result = {
|
||||
ledger_index: tx.ledger_index,
|
||||
metadata: tx.meta,
|
||||
tx_json: {
|
||||
Account: tx.Account,
|
||||
Amount: tx.Amount,
|
||||
Destination: tx.Destination,
|
||||
Fee: tx.Fee,
|
||||
Flags: tx.Flags,
|
||||
Sequence: tx.Sequence,
|
||||
SigningPubKey: tx.SigningPubKey,
|
||||
TransactionType: tx.TransactionType,
|
||||
hash: tx.hash
|
||||
}
|
||||
}
|
||||
} catch(exception) {
|
||||
}
|
||||
return result || { };
|
||||
};
|
||||
|
||||
//called whenever we get a transaction for an account whose transactions we're managing.
|
||||
//TransactionManager.prototype.update = function(tx) {
|
||||
// this._next_sequence_number = Math.max(tx.meta.account_next_seq, this._next_sequence_number);
|
||||
// var queued;
|
||||
//
|
||||
// if (queued = this.queue.get('hash', tx.hash)) {
|
||||
// this.queue.remove('hash', queued.hash);
|
||||
// } else if (queued = this.queue.get('sequence', tx.seq)) {
|
||||
// if (queued.nullified) {
|
||||
// //Figures out new sequence number, signs, and sends to network
|
||||
// this.submit(queued);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
TransactionManager.prototype._resubmit = function() {
|
||||
var self = this;
|
||||
|
||||
/**
|
||||
* User has given up, replace transaction with a null transaction
|
||||
*
|
||||
* @param {Object} tx
|
||||
*/
|
||||
function resubmit(pending, index) {
|
||||
if (pending.finalized) {
|
||||
// Transaction has been finalized, nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
//TransactionManager.prototype._nullify = function(tx) {
|
||||
// this.queue.remove('hash', tx.hash);
|
||||
//}
|
||||
var sequence = pending.tx_json.Sequence;
|
||||
var cached = self._cache[sequence];
|
||||
|
||||
/**
|
||||
*/
|
||||
pending.emit('resubmit');
|
||||
|
||||
//TransactionManager.prototype._timeout = function() {
|
||||
// var transactions = this.queue.get();
|
||||
// for (var i=0; i<transactions.length; i++) {
|
||||
// this.remote.submit(transactions[i].blob);
|
||||
// }
|
||||
// //restart the timer
|
||||
// this._timeout = setTimeout(function(){}, 10000);
|
||||
//}
|
||||
if (cached) {
|
||||
// Transaction was received while waiting for
|
||||
// resubmission
|
||||
pending.emit('success', cached);
|
||||
delete self._cache[sequence];
|
||||
} else if (pending.hash) {
|
||||
// Transaction was successfully submitted, and
|
||||
// its hash discovered, but not validated
|
||||
|
||||
/**
|
||||
* @param {Number} oldFee
|
||||
* @param {Number} newFee
|
||||
*/
|
||||
function pending_check(err, res) {
|
||||
if (self._is_not_found(err)) {
|
||||
self._request(pending);
|
||||
} else {
|
||||
pending.emit('success', rewrite_transaction(res));
|
||||
}
|
||||
}
|
||||
|
||||
//TransactionManager.prototype._fee_change = function(oldFee, newFee) {
|
||||
// if (newFee > this._config.maxFee) {
|
||||
// if (this._timeout) clearTimeout(this._timeout);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // resubmit everything raising fee if needed
|
||||
// for (var i=0; i<transactions.length; i++) {
|
||||
// var tx = transactions[i];
|
||||
//
|
||||
// if (tx.fee < newFee) {
|
||||
// tx.fee = newFee;
|
||||
// //tx.blob = signTransaction(tx, tx.seq, newFee);
|
||||
// //this.queue.add(tx);
|
||||
// }
|
||||
//
|
||||
// this.remote.submit(tx.blob);
|
||||
// }
|
||||
//}
|
||||
self.remote.request_tx(pending.hash, pending_check);
|
||||
} else {
|
||||
self._request(pending);
|
||||
}
|
||||
}
|
||||
|
||||
this._wait_ledgers(3, function() {
|
||||
self._pending.forEach(resubmit);
|
||||
});
|
||||
}
|
||||
|
||||
TransactionManager.prototype._wait_ledgers = function(ledgers, callback) {
|
||||
var self = this;
|
||||
var closes = 0;
|
||||
|
||||
function ledger_closed() {
|
||||
if (++closes === ledgers) {
|
||||
callback();
|
||||
self.remote.removeListener('ledger_closed', ledger_closed);
|
||||
}
|
||||
}
|
||||
|
||||
this.remote.on('ledger_closed', ledger_closed);
|
||||
}
|
||||
|
||||
TransactionManager.prototype._request = function(tx) {
|
||||
var self = this;
|
||||
@@ -109,11 +154,12 @@ TransactionManager.prototype._request = function(tx) {
|
||||
return;
|
||||
}
|
||||
|
||||
tx.submit_index = remote._ledger_current_index;
|
||||
|
||||
function finalize(message) {
|
||||
if (!tx.finalized) {
|
||||
tx.finalized = true;
|
||||
tx.emit('final', message);
|
||||
self._pending.removeSequence(tx.tx_json.Sequence);
|
||||
}
|
||||
}
|
||||
|
||||
tx.once('error', finalize);
|
||||
@@ -136,11 +182,9 @@ TransactionManager.prototype._request = function(tx) {
|
||||
submit_request.tx_json(tx.tx_json);
|
||||
}
|
||||
|
||||
// Handle insufficient fee
|
||||
function submission_success(message) {
|
||||
if (!message.engine_result) {
|
||||
submission_error(message);
|
||||
} else {
|
||||
tx.submit_index = remote._ledger_current_index;
|
||||
|
||||
function transaction_proposed(message) {
|
||||
tx.hash = message.tx_json.hash;
|
||||
tx.set_state('client_proposed');
|
||||
tx.emit('proposed', {
|
||||
@@ -159,6 +203,20 @@ TransactionManager.prototype._request = function(tx) {
|
||||
rejected: tx.isRejected(message.engine_result_code),
|
||||
});
|
||||
}
|
||||
|
||||
function transaction_failed(message) {
|
||||
if (!tx.hash) tx.hash = message.tx_json.hash;
|
||||
|
||||
function transaction_requested(err, res) {
|
||||
if (self._is_not_found(err)) {
|
||||
self._resubmit();
|
||||
} else {
|
||||
tx.emit('error', new RippleError(message));
|
||||
self._pending.removeSequence(tx.tx_json.Sequence);
|
||||
}
|
||||
}
|
||||
|
||||
self.remote.request_tx(tx.hash, transaction_requested);
|
||||
}
|
||||
|
||||
function submission_error(err) {
|
||||
@@ -166,17 +224,34 @@ TransactionManager.prototype._request = function(tx) {
|
||||
tx.emit('error', new RippleError(err));
|
||||
}
|
||||
|
||||
function submission_success(message) {
|
||||
var engine_result = message.engine_result || '';
|
||||
|
||||
tx.hash = message.tx_json.hash;
|
||||
|
||||
switch (engine_result.slice(0, 3)) {
|
||||
case 'tef':
|
||||
//tefPAST_SEQ
|
||||
transaction_failed(message);
|
||||
break;
|
||||
case 'tes':
|
||||
transaction_proposed(message);
|
||||
break;
|
||||
default:
|
||||
submission_error(message);
|
||||
}
|
||||
}
|
||||
|
||||
submit_request.once('success', submission_success);
|
||||
submit_request.once('error', submission_error);
|
||||
|
||||
// submit_request.timeout(1000 * 2, function() {
|
||||
// tx.emit('error', new Error('Timeout'));
|
||||
// });
|
||||
|
||||
//submit_request.emit = function() {}
|
||||
|
||||
submit_request.request();
|
||||
|
||||
submit_request.timeout(1000 * 10, function() {
|
||||
if (self.remote._connected) {
|
||||
self._resubmit();
|
||||
}
|
||||
});
|
||||
|
||||
tx.set_state('client_submitted');
|
||||
tx.emit('submitted');
|
||||
|
||||
@@ -184,12 +259,11 @@ TransactionManager.prototype._request = function(tx) {
|
||||
};
|
||||
|
||||
TransactionManager.prototype._is_not_found = function(error) {
|
||||
return !!error && typeof error === 'object'
|
||||
&& typeof error.remote === 'object'
|
||||
var not_found_re = /^(txnNotFound|transactionNotFound)$/;
|
||||
return error && typeof error === 'object'
|
||||
&& error.error === 'remoteError'
|
||||
&& (error.remote.error === 'transactionNotFound'
|
||||
|| error.remote.error === 'ledgerNotFound')
|
||||
;
|
||||
&& typeof error.remote === 'object'
|
||||
&& not_found_re.test(error.remote.error);
|
||||
};
|
||||
|
||||
TransactionManager.prototype._detect_ledger_entry = function(tx) {
|
||||
@@ -197,29 +271,21 @@ TransactionManager.prototype._detect_ledger_entry = function(tx) {
|
||||
var remote = this.remote;
|
||||
var checked_ledgers = { };
|
||||
|
||||
function ledger_closed(message) {
|
||||
if (tx.finalized) {
|
||||
// Transaction has already erred or
|
||||
// been detected in the ledger
|
||||
return;
|
||||
}
|
||||
function entry_callback(err, message) {
|
||||
if (typeof message !== 'object') return;
|
||||
|
||||
var ledger_hash = message.ledger_hash;
|
||||
var ledger_index = message.ledger_index;
|
||||
|
||||
if (checked_ledgers.hasOwnProperty(ledger_hash)) {
|
||||
// Ledger with this hash has already been
|
||||
// checked to contain transaction
|
||||
if (tx.finalized || checked_ledgers[ledger_hash]) {
|
||||
// Transaction submission has already erred or
|
||||
// this ledger has already been checked for
|
||||
// transaction
|
||||
return;
|
||||
}
|
||||
|
||||
checked_ledgers[ledger_hash] = true;
|
||||
|
||||
var request_transaction = remote.request_transaction_entry(tx.hash, ledger_hash);
|
||||
|
||||
request_transaction.callback(function(err, message) {
|
||||
if (tx.finalized) return;
|
||||
|
||||
if (self._is_not_found(err)) {
|
||||
var dif = ledger_index - tx.submit_index;
|
||||
if (dif >= 8) {
|
||||
@@ -229,7 +295,7 @@ TransactionManager.prototype._detect_ledger_entry = function(tx) {
|
||||
} else if (dif >= 4) {
|
||||
// Missing
|
||||
tx.set_state('client_missing');
|
||||
tx.emit('pending', message);
|
||||
tx.emit('missing', message);
|
||||
} else {
|
||||
// Pending
|
||||
tx.emit('pending', message);
|
||||
@@ -242,7 +308,12 @@ TransactionManager.prototype._detect_ledger_entry = function(tx) {
|
||||
}
|
||||
tx.emit('success', message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function ledger_closed(message) {
|
||||
if (!tx.finalized && !checked_ledgers[message.ledger_hash]) {
|
||||
remote.request_transaction_entry(tx.hash, message.ledger_hash, entry_callback);
|
||||
}
|
||||
}
|
||||
|
||||
function transaction_proposed() {
|
||||
@@ -253,10 +324,12 @@ TransactionManager.prototype._detect_ledger_entry = function(tx) {
|
||||
function transaction_finalized() {
|
||||
// Stop checking the ledger
|
||||
remote.removeListener('ledger_closed', ledger_closed);
|
||||
tx.removeListener('proposed', transaction_proposed);
|
||||
}
|
||||
|
||||
tx.once('proposed', transaction_proposed);
|
||||
tx.once('final', transaction_finalized);
|
||||
tx.once('resubmit', transaction_finalized);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -265,19 +338,24 @@ TransactionManager.prototype._detect_ledger_entry = function(tx) {
|
||||
|
||||
TransactionManager.prototype.submit = function(tx) {
|
||||
// If sequence number is not yet known, defer until it is.
|
||||
var self = this;
|
||||
|
||||
if (!this._next_sequence) {
|
||||
this.once('sequence_loaded', this.submit.bind(this, tx));
|
||||
function resubmit_transaction() {
|
||||
self.submit(tx);
|
||||
}
|
||||
this.once('sequence_loaded', resubmit_transaction);
|
||||
return;
|
||||
}
|
||||
|
||||
var seq = this._next_sequence++;
|
||||
var fee = tx.fee_units();
|
||||
|
||||
if (fee <= this._config.max_fee) {
|
||||
tx.tx_json.Sequence = seq;
|
||||
tx.tx_json.Fee = fee;
|
||||
tx.tx_json.Sequence = this._next_sequence++;
|
||||
tx.complete();
|
||||
|
||||
this._pending.push(tx);
|
||||
|
||||
var fee = tx.tx_json.Fee;
|
||||
|
||||
if (fee === void(0) || fee <= this._max_fee) {
|
||||
this._request(tx);
|
||||
}
|
||||
};
|
||||
|
||||
59
src/js/ripple/transactionqueue.js
Normal file
59
src/js/ripple/transactionqueue.js
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
function TransactionQueue() {
|
||||
this._queue = [ ];
|
||||
}
|
||||
|
||||
TransactionQueue.prototype.length = function() {
|
||||
return this._queue.length;
|
||||
};
|
||||
|
||||
TransactionQueue.prototype.push = function(o) {
|
||||
return this._queue.push(o);
|
||||
};
|
||||
|
||||
TransactionQueue.prototype.hasHash = function(hash) {
|
||||
return this.indexOf('hash', hash) !== -1;
|
||||
};
|
||||
|
||||
TransactionQueue.prototype.hasSequence = function(sequence) {
|
||||
return this.indexOf('sequence', sequence) !== -1;
|
||||
};
|
||||
|
||||
TransactionQueue.prototype.indexOf = function(prop, val) {
|
||||
var index = -1;
|
||||
for (var i=0, tx; tx=this._queue[i]; i++) {
|
||||
if (tx[prop] === val) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
};
|
||||
|
||||
TransactionQueue.prototype.removeSequence = function(sequence) {
|
||||
var result = [ ];
|
||||
for (var i=0, tx; tx=this._queue[i]; i++) {
|
||||
if (!tx.tx_json) continue;
|
||||
if (tx.tx_json.Sequence !== sequence)
|
||||
result.push(tx);
|
||||
}
|
||||
this._queue = result;
|
||||
};
|
||||
|
||||
TransactionQueue.prototype.removeHash = function(hash) {
|
||||
var result = [ ];
|
||||
for (var i=0, tx; tx=this._queue[i]; i++) {
|
||||
if (!tx.tx_json) continue;
|
||||
if (tx.hash !== hash)
|
||||
result.push(tx);
|
||||
}
|
||||
this._queue = result;
|
||||
};
|
||||
|
||||
TransactionQueue.prototype.forEach = function(fn) {
|
||||
for (var i=0, tx; tx=this._queue[i]; i++) {
|
||||
fn(tx, i);
|
||||
}
|
||||
};
|
||||
|
||||
exports.TransactionQueue = TransactionQueue;
|
||||
Reference in New Issue
Block a user