mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-19 19:55:51 +00:00
Fixes and cleanup for Remote, update readme
This commit is contained in:
103
README.md
103
README.md
@@ -3,9 +3,108 @@ Ripple JavaScript Library - ripple-lib
|
||||
|
||||
This library can connect to the Ripple network via the WebSocket protocol and runs in Node.js as well as in the browser.
|
||||
|
||||
Build instructions:
|
||||
##Building
|
||||
|
||||
* https://ripple.com/wiki/Ripple_JavaScript_library
|
||||
|
||||
For more information:
|
||||
##See also
|
||||
|
||||
* https://ripple.com
|
||||
* https://ripple.com/wiki
|
||||
|
||||
##Initializing a remote connection
|
||||
|
||||
[ripple-lib.remote](https://github.com/ripple/ripple-lib/blob/develop/src/js/ripple/remote.js) is responsible for managing connections to rippled servers.
|
||||
|
||||
```js
|
||||
var remote = require('ripple-lib').Remote({
|
||||
servers: [
|
||||
{
|
||||
host: ''
|
||||
, port: 1111,
|
||||
, secure: true
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
##Remote functions
|
||||
|
||||
Each remote function returns a `Request` object. This object is an `EventEmitter`. You may listen for success or failure events from each request, or provide a callback. Example:
|
||||
|
||||
```js
|
||||
var request = remote.request_server_info();
|
||||
request.on('success', function(res) {
|
||||
//handle success conditions
|
||||
});
|
||||
request.on('error', function(err) {
|
||||
//handle error conditions
|
||||
});
|
||||
request.request();
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```js
|
||||
remote.request_server_info(function(err, res) {
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
**remote.request_server_info([callback])**
|
||||
|
||||
**remote.request_ledger(ledger, [opts], [callback])**
|
||||
|
||||
**remote.request_ledger_hash([callback])**
|
||||
|
||||
**remote.request_ledger_header([callback])**
|
||||
|
||||
**remote.request_ledger_current([callback])**
|
||||
|
||||
**remote.request_ledger_entry(type, [callback])**
|
||||
|
||||
**remote.request_subscribe(streams, [callback])**
|
||||
|
||||
**remote.request_unsubscribe(streams, [callback])**
|
||||
|
||||
**remote.request_transaction_entry(hash, [callback])**
|
||||
|
||||
**remote.request_tx(hash, [callback])**
|
||||
|
||||
**remote.request_account_info(accountID, [callback])**
|
||||
|
||||
**remote.request_account_lines(accountID, account_index, current, [callback])**
|
||||
|
||||
**remote.request_account_offers(accountID, account_index, current, [callback])**
|
||||
|
||||
**remote.request_account_tx(opts, [callback])**
|
||||
|
||||
**remote.request_book_offers(gets, pays, taker, [callback])**
|
||||
|
||||
**remote.request_wallet_accounts(seed, [callback])**
|
||||
|
||||
**remote.request_sign(secret, tx_json, [callback])**
|
||||
|
||||
**remote.request_submit([callback])**
|
||||
|
||||
**remote.request_account_balance(account, current, [callback])**
|
||||
|
||||
**remote.request_account_flags(account, current, [callback])**
|
||||
|
||||
**remote.request_owner_count(account, current, [callback])**
|
||||
|
||||
**remote.request_ripple_balance(account, issuer, currency, current, [callback])**
|
||||
|
||||
**remote.request_ripple_path_find(src_account, dst_account, dst_amount, src_currencies, [callback])**
|
||||
|
||||
**remote.request_unl_list([callback])**
|
||||
|
||||
**remote.request_unl_add(addr, comment, [callback])**
|
||||
|
||||
**remote.request_unl_delete(node, [callback])**
|
||||
|
||||
**remote.request_peers([callback])**
|
||||
|
||||
**remote.request_connect(ip, port, [callback])**
|
||||
|
||||
**remote.transaction()**
|
||||
|
||||
@@ -9,35 +9,32 @@
|
||||
// var network = require("./network.js");
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var util = require('util');
|
||||
|
||||
var Amount = require('./amount').Amount;
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Currency = require('./currency').Currency;
|
||||
var Amount = require('./amount').Amount;
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Currency = require('./currency').Currency;
|
||||
|
||||
var extend = require('extend');
|
||||
var extend = require('extend');
|
||||
|
||||
var OrderBook = function (remote,
|
||||
currency_gets, issuer_gets,
|
||||
currency_pays, issuer_pays) {
|
||||
var OrderBook = function (remote, currency_gets, issuer_gets, currency_pays, issuer_pays) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
var self = this;
|
||||
var self = this;
|
||||
|
||||
this._remote = remote;
|
||||
this._remote = remote;
|
||||
this._currency_gets = currency_gets;
|
||||
this._issuer_gets = issuer_gets;
|
||||
this._issuer_gets = issuer_gets;
|
||||
this._currency_pays = currency_pays;
|
||||
this._issuer_pays = issuer_pays;
|
||||
|
||||
this._subs = 0;
|
||||
this._issuer_pays = issuer_pays;
|
||||
this._subs = 0;
|
||||
|
||||
// We consider ourselves synchronized if we have a current copy of the offers,
|
||||
// we are online and subscribed to updates.
|
||||
this._sync = false;
|
||||
this._sync = false;
|
||||
|
||||
// Offers
|
||||
this._offers = [];
|
||||
this._offers = [];
|
||||
|
||||
this.on('newListener', function (type, listener) {
|
||||
if (OrderBook.subscribe_events.indexOf(type) !== -1) {
|
||||
@@ -49,10 +46,9 @@ var OrderBook = function (remote,
|
||||
});
|
||||
|
||||
this.on('removeListener', function (type, listener) {
|
||||
if (OrderBook.subscribe_events.indexOf(type) !== -1) {
|
||||
if (~OrderBook.subscribe_events.indexOf(type)) {
|
||||
self._subs -= 1;
|
||||
|
||||
if (!self._subs && 'open' === self._remote._online_state) {
|
||||
if (!self._subs && self._remote._connected) {
|
||||
self._sync = false;
|
||||
self._remote.request_unsubscribe()
|
||||
.books([self.to_json()])
|
||||
@@ -86,8 +82,7 @@ OrderBook.subscribe_events = ['transaction', 'model', 'trade'];
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
OrderBook.prototype._subscribe = function ()
|
||||
{
|
||||
OrderBook.prototype._subscribe = function () {
|
||||
var self = this;
|
||||
self._remote.request_subscribe()
|
||||
.books([self.to_json()], true)
|
||||
@@ -95,26 +90,28 @@ OrderBook.prototype._subscribe = function ()
|
||||
// XXX What now?
|
||||
})
|
||||
.on('success', function (res) {
|
||||
self._sync = true;
|
||||
self._sync = true;
|
||||
self._offers = res.offers;
|
||||
self.emit('model', self._offers);
|
||||
})
|
||||
.request();
|
||||
};
|
||||
|
||||
OrderBook.prototype.to_json = function ()
|
||||
{
|
||||
OrderBook.prototype.to_json = function () {
|
||||
var json = {
|
||||
"taker_gets": {
|
||||
"currency": this._currency_gets
|
||||
'taker_gets': {
|
||||
'currency': this._currency_gets
|
||||
},
|
||||
"taker_pays": {
|
||||
"currency": this._currency_pays
|
||||
'taker_pays': {
|
||||
'currency': this._currency_pays
|
||||
}
|
||||
};
|
||||
|
||||
if (this._currency_gets !== "XRP") json["taker_gets"]["issuer"] = this._issuer_gets;
|
||||
if (this._currency_pays !== "XRP") json["taker_pays"]["issuer"] = this._issuer_pays;
|
||||
if (this._currency_gets !== 'XRP')
|
||||
json['taker_gets']['issuer'] = this._issuer_gets;
|
||||
|
||||
if (this._currency_pays !== 'XRP')
|
||||
json['taker_pays']['issuer'] = this._issuer_pays;
|
||||
|
||||
return json;
|
||||
};
|
||||
@@ -125,78 +122,88 @@ OrderBook.prototype.to_json = function ()
|
||||
* Note: This only checks whether the parameters (currencies and issuer) are
|
||||
* syntactically valid. It does not check anything against the ledger.
|
||||
*/
|
||||
OrderBook.prototype.is_valid = function ()
|
||||
{
|
||||
OrderBook.prototype.is_valid = function () {
|
||||
// XXX Should check for same currency (non-native) && same issuer
|
||||
return (
|
||||
Currency.is_valid(this._currency_pays) &&
|
||||
(this._currency_pays === "XRP" || UInt160.is_valid(this._issuer_pays)) &&
|
||||
(this._currency_pays === 'XRP' || UInt160.is_valid(this._issuer_pays)) &&
|
||||
Currency.is_valid(this._currency_gets) &&
|
||||
(this._currency_gets === "XRP" || UInt160.is_valid(this._issuer_gets)) &&
|
||||
!(this._currency_pays === "XRP" && this._currency_gets === "XRP")
|
||||
(this._currency_gets === 'XRP' || UInt160.is_valid(this._issuer_gets)) &&
|
||||
!(this._currency_pays === 'XRP' && this._currency_gets === 'XRP')
|
||||
);
|
||||
};
|
||||
|
||||
OrderBook.prototype.trade = function(type) {
|
||||
var tradeStr = '0'
|
||||
+ (this['_currency_' + type] === 'XRP') ? '' : '/'
|
||||
+ this['_currency_' + type ] + '/'
|
||||
+ this['_issuer_' + type];
|
||||
return Amount.from_json(tradeStr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Notify object of a relevant transaction.
|
||||
*
|
||||
* This is only meant to be called by the Remote class. You should never have to
|
||||
* call this yourself.
|
||||
*/
|
||||
OrderBook.prototype.notifyTx = function (message)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
var changed = false;
|
||||
|
||||
var trade_gets = Amount.from_json("0" + ((this._currency_gets === 'XRP') ? "" :
|
||||
"/" + this._currency_gets +
|
||||
"/" + this._issuer_gets));
|
||||
var trade_pays = Amount.from_json("0" + ((this._currency_pays === 'XRP') ? "" :
|
||||
"/" + this._currency_pays +
|
||||
"/" + this._issuer_pays));
|
||||
OrderBook.prototype.notifyTx = function (message) {
|
||||
var self = this;
|
||||
var changed = false;
|
||||
var trade_gets = this.trade('gets');
|
||||
var trade_pays = this.trade('pays');
|
||||
|
||||
message.mmeta.each(function (an) {
|
||||
if (an.entryType !== 'Offer') return;
|
||||
|
||||
var i, l, offer;
|
||||
if (an.diffType === 'DeletedNode' ||
|
||||
an.diffType === 'ModifiedNode') {
|
||||
for (i = 0, l = self._offers.length; i < l; i++) {
|
||||
offer = self._offers[i];
|
||||
if (offer.index === an.ledgerIndex) {
|
||||
if (an.diffType === 'DeletedNode') {
|
||||
self._offers.splice(i, 1);
|
||||
|
||||
switch(an.diffType) {
|
||||
case 'DeletedNode':
|
||||
case 'ModifiedNode':
|
||||
var deletedNode = an.diffType === 'DeletedNode';
|
||||
|
||||
for (i = 0, l = self._offers.length; i < l; i++) {
|
||||
offer = self._offers[i];
|
||||
if (offer.index === an.ledgerIndex) {
|
||||
if (deletedNode) {
|
||||
self._offers.splice(i, 1);
|
||||
} else {
|
||||
extend(offer, an.fieldsFinal);
|
||||
}
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
else extend(offer, an.fieldsFinal);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't want to count a OfferCancel as a trade
|
||||
if (message.transaction.TransactionType === "OfferCancel") return;
|
||||
// We don't want to count a OfferCancel as a trade
|
||||
if (message.transaction.TransactionType === 'OfferCancel') return;
|
||||
|
||||
trade_gets = trade_gets.add(an.fieldsPrev.TakerGets);
|
||||
trade_pays = trade_pays.add(an.fieldsPrev.TakerPays);
|
||||
if (an.diffType === 'ModifiedNode') {
|
||||
trade_gets = trade_gets.subtract(an.fieldsFinal.TakerGets);
|
||||
trade_pays = trade_pays.subtract(an.fieldsFinal.TakerPays);
|
||||
}
|
||||
} else if (an.diffType === 'CreatedNode') {
|
||||
var price = Amount.from_json(an.fields.TakerPays).ratio_human(an.fields.TakerGets);
|
||||
for (i = 0, l = self._offers.length; i < l; i++) {
|
||||
offer = self._offers[i];
|
||||
var priceItem = Amount.from_json(offer.TakerPays).ratio_human(offer.TakerGets);
|
||||
trade_gets = trade_gets.add(an.fieldsPrev.TakerGets);
|
||||
trade_pays = trade_pays.add(an.fieldsPrev.TakerPays);
|
||||
|
||||
if (price.compareTo(priceItem) <= 0) {
|
||||
var obj = an.fields;
|
||||
obj.index = an.ledgerIndex;
|
||||
self._offers.splice(i, 0, an.fields);
|
||||
changed = true;
|
||||
break;
|
||||
if (!deletedNode) {
|
||||
trade_gets = trade_gets.subtract(an.fieldsFinal.TakerGets);
|
||||
trade_pays = trade_pays.subtract(an.fieldsFinal.TakerPays);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'CreatedNode':
|
||||
var price = Amount.from_json(an.fields.TakerPays).ratio_human(an.fields.TakerGets);
|
||||
|
||||
for (i = 0, l = self._offers.length; i < l; i++) {
|
||||
offer = self._offers[i];
|
||||
var priceItem = Amount.from_json(offer.TakerPays).ratio_human(offer.TakerGets);
|
||||
|
||||
if (price.compareTo(priceItem) <= 0) {
|
||||
var obj = an.fields;
|
||||
obj.index = an.ledgerIndex;
|
||||
self._offers.splice(i, 0, an.fields);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -218,17 +225,13 @@ OrderBook.prototype.notifyTx = function (message)
|
||||
*
|
||||
* If the data is available immediately, the callback may be called synchronously.
|
||||
*/
|
||||
OrderBook.prototype.offers = function (callback)
|
||||
{
|
||||
OrderBook.prototype.offers = function (callback) {
|
||||
var self = this;
|
||||
|
||||
if ("function" === typeof callback) {
|
||||
if (typeof callback === 'function') {
|
||||
if (this._sync) {
|
||||
callback(this._offers);
|
||||
} else {
|
||||
this.once('model', function (offers) {
|
||||
callback(offers);
|
||||
});
|
||||
this.once('model', callback);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
@@ -240,11 +243,10 @@ OrderBook.prototype.offers = function (callback)
|
||||
* Usually, this will just be an empty array if the order book hasn't been
|
||||
* loaded yet. But this accessor may be convenient in some circumstances.
|
||||
*/
|
||||
OrderBook.prototype.offersSync = function ()
|
||||
{
|
||||
OrderBook.prototype.offersSync = function () {
|
||||
return this._offers;
|
||||
};
|
||||
|
||||
exports.OrderBook = OrderBook;
|
||||
exports.OrderBook = OrderBook;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
@@ -37,16 +37,13 @@ var sjcl = require('../../../build/sjcl');
|
||||
// 'remoteError'
|
||||
// 'remoteUnexpected'
|
||||
// 'remoteDisconnected'
|
||||
var Request = function (remote, command) {
|
||||
function Request(remote, command) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
var self = this;
|
||||
|
||||
this.remote = remote;
|
||||
this.requested = false;
|
||||
this.message = {
|
||||
'command' : command,
|
||||
'id' : undefined,
|
||||
command : command,
|
||||
id : void(0)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -67,6 +64,7 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
||||
this.once(errorEvent || 'error', callback);
|
||||
this.request();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -143,8 +141,8 @@ Request.prototype.index = function (hash) {
|
||||
// --> seq : sequence number of transaction creating offer (integer)
|
||||
Request.prototype.offer_id = function (account, seq) {
|
||||
this.message.offer = {
|
||||
'account' : UInt160.json_rewrite(account),
|
||||
'seq' : seq
|
||||
account: UInt160.json_rewrite(account),
|
||||
seq: seq
|
||||
};
|
||||
|
||||
return this;
|
||||
@@ -228,20 +226,20 @@ Request.prototype.books = function (books, snapshot) {
|
||||
function processSide(side) {
|
||||
if (!book[side]) throw new Error('Missing '+side);
|
||||
|
||||
var obj = {};
|
||||
obj['currency'] = Currency.json_rewrite(book[side]['currency']);
|
||||
if (obj['currency'] !== 'XRP') {
|
||||
obj.issuer = UInt160.json_rewrite(book[side]['issuer']);
|
||||
var obj = json[side] = {
|
||||
currency: Currency.json_rewrite(book[side].currency)
|
||||
};
|
||||
|
||||
if (obj.currency !== 'XRP') {
|
||||
obj.issuer = UInt160.json_rewrite(book[side].issuer);
|
||||
}
|
||||
|
||||
json[side] = obj;
|
||||
}
|
||||
|
||||
processSide('taker_gets');
|
||||
processSide('taker_pays');
|
||||
|
||||
if (snapshot || book['snapshot']) json['snapshot'] = true;
|
||||
if (book['both']) json['both'] = true;
|
||||
if (snapshot) json.snapshot = true;
|
||||
if (book.both) json.both = true;
|
||||
|
||||
procBooks.push(json);
|
||||
}
|
||||
@@ -286,7 +284,7 @@ Request.prototype.books = function (books, snapshot) {
|
||||
@param trace
|
||||
*/
|
||||
|
||||
var Remote = function (opts, trace) {
|
||||
function Remote(opts, trace) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
var self = this;
|
||||
@@ -321,7 +319,6 @@ var Remote = function (opts, trace) {
|
||||
this._connection_count = 0;
|
||||
this._connected = false;
|
||||
|
||||
|
||||
this._last_tx = null;
|
||||
|
||||
// Local signing implies local fees and sequences
|
||||
@@ -661,6 +658,7 @@ Remote.prototype._server_is_available = function (server) {
|
||||
|
||||
Remote.prototype._next_server = function () {
|
||||
var result = null;
|
||||
|
||||
for (var i=0; i<this._servers.length; i++) {
|
||||
var server = this._servers[i];
|
||||
if (this._server_is_available(server)) {
|
||||
@@ -668,17 +666,20 @@ Remote.prototype._next_server = function () {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Remote.prototype._get_server = function () {
|
||||
var server;
|
||||
|
||||
if (this._server_is_available(this._primary_server)) {
|
||||
server = this._primary_server;
|
||||
} else {
|
||||
server = this._next_server();
|
||||
if (server) this._set_primary_server(server);
|
||||
}
|
||||
|
||||
return server;
|
||||
};
|
||||
|
||||
@@ -716,7 +717,7 @@ Remote.prototype.request_ledger = function (ledger, opts, callback) {
|
||||
request.message.ledger = ledger;
|
||||
}
|
||||
|
||||
if ('object' == typeof opts) {
|
||||
if (typeof opts === 'object') {
|
||||
if (opts.full)
|
||||
request.message.full = true;
|
||||
|
||||
@@ -728,9 +729,7 @@ Remote.prototype.request_ledger = function (ledger, opts, callback) {
|
||||
|
||||
if (opts.accounts)
|
||||
request.message.accounts = true;
|
||||
}
|
||||
// DEPRECATED:
|
||||
else if (opts) {
|
||||
} else if (opts) { // DEPRECATED:
|
||||
console.log('request_ledger: full parameter is deprecated');
|
||||
request.message.full = true;
|
||||
}
|
||||
@@ -841,10 +840,7 @@ Remote.prototype.request_subscribe = function (streams, callback) {
|
||||
var request = new Request(this, 'subscribe');
|
||||
|
||||
if (streams) {
|
||||
if (!Array.isArray(streams)) {
|
||||
streams = [ streams ];
|
||||
}
|
||||
request.message.streams = streams;
|
||||
request.message.streams = Array.isArray(streams) ? streams : [ streams ];
|
||||
}
|
||||
|
||||
return request.callback(callback);
|
||||
@@ -855,10 +851,7 @@ Remote.prototype.request_unsubscribe = function (streams, callback) {
|
||||
var request = new Request(this, 'unsubscribe');
|
||||
|
||||
if (streams) {
|
||||
if (!Array.isArray(streams)) {
|
||||
streams = [ streams ];
|
||||
}
|
||||
request.message.streams = streams;
|
||||
request.message.streams = Array.isArray(streams) ? streams : [ streams ];
|
||||
}
|
||||
|
||||
return request.callback(callback);
|
||||
@@ -1247,7 +1240,7 @@ Remote.prototype.account_seq_cache = function (account, current, callback) {
|
||||
|
||||
// Mark an account's root node as dirty.
|
||||
Remote.prototype.dirty_account_root = function (account) {
|
||||
var account = UInt160.json_rewrite(account);
|
||||
var account = UInt160.json_rewrite(account);
|
||||
|
||||
delete this.ledgers.current.account_root[account];
|
||||
};
|
||||
@@ -1349,8 +1342,8 @@ Remote.prototype.request_unl_delete = function (node, callback) {
|
||||
return request.callback(callback);
|
||||
};
|
||||
|
||||
Remote.prototype.request_peers = function () {
|
||||
return new Request(this, 'peers');
|
||||
Remote.prototype.request_peers = function (callback) {
|
||||
return new Request(this, 'peers').callback(callback);
|
||||
};
|
||||
|
||||
Remote.prototype.request_connect = function (ip, port, callback) {
|
||||
|
||||
@@ -184,6 +184,10 @@ Server.prototype.disconnect = function () {
|
||||
}
|
||||
};
|
||||
|
||||
Server.prototype.send_message = function (message) {
|
||||
this._ws.send(JSON.stringify(message));
|
||||
};
|
||||
|
||||
/**
|
||||
* Submit a Request object to this server.
|
||||
*/
|
||||
@@ -199,20 +203,19 @@ Server.prototype.request = function (request) {
|
||||
// Advance message ID
|
||||
self._id++;
|
||||
|
||||
if (self._state === 'online' ||
|
||||
(request.message.command === 'subscribe' && self._ws.readyState === 1)) {
|
||||
if (self._connected || (request.message.command === 'subscribe' && self._ws.readyState === 1)) {
|
||||
if (self._remote.trace) {
|
||||
utils.logObject('server: request: %s', request.message);
|
||||
}
|
||||
|
||||
self._ws.send(JSON.stringify(request.message));
|
||||
self.send_message(request.message);
|
||||
} else {
|
||||
// XXX There are many ways to make self smarter.
|
||||
self.once('connect', function () {
|
||||
if (self._remote.trace) {
|
||||
utils.logObject('server: request: %s', request.message);
|
||||
}
|
||||
self._ws.send(JSON.stringify(request.message));
|
||||
self.send_message(request.message);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -206,6 +206,8 @@ Transaction.prototype.complete = function () {
|
||||
var key = seed.get_key(this.tx_json.Account);
|
||||
tx_json.SigningPubKey = key.to_hex_pub();
|
||||
}
|
||||
|
||||
return this.tx_json;
|
||||
};
|
||||
|
||||
Transaction.prototype.serialize = function () {
|
||||
@@ -250,14 +252,22 @@ Transaction.prototype._hasTransactionListeners = function() {
|
||||
// case 'tejLost': locally gave up looking
|
||||
// default: some other TER
|
||||
// }
|
||||
|
||||
Transaction.prototype.submit = function (callback) {
|
||||
var self = this;
|
||||
var tx_json = this.tx_json;
|
||||
|
||||
this.callback = callback;
|
||||
this.callback = typeof callback === 'function'
|
||||
? callback
|
||||
: function(){};
|
||||
|
||||
function finish(err) {
|
||||
self.emit('error', err);
|
||||
self.callback('error', err);
|
||||
}
|
||||
|
||||
if (typeof tx_json.Account !== 'string') {
|
||||
(this.callback || this.emit)('error', {
|
||||
finish({
|
||||
'error' : 'tejInvalidAccount',
|
||||
'error_message' : 'Bad account.'
|
||||
});
|
||||
@@ -268,72 +278,72 @@ Transaction.prototype.submit = function (callback) {
|
||||
|
||||
this.complete();
|
||||
|
||||
if (this.callback || this._hasTransactionListeners()) {
|
||||
// There are listeners for callback, 'final', 'lost', or 'pending' arrange to emit them.
|
||||
//console.log('Callback or has listeners');
|
||||
|
||||
this.submit_index = this.remote._ledger_current_index;
|
||||
// There are listeners for callback, 'final', 'lost', or 'pending' arrange to emit them.
|
||||
|
||||
// When a ledger closes, look for the result.
|
||||
function on_ledger_closed(message) {
|
||||
var ledger_hash = message.ledger_hash;
|
||||
var ledger_index = message.ledger_index;
|
||||
var stop = false;
|
||||
this.submit_index = this.remote._ledger_current_index;
|
||||
|
||||
// XXX make sure self.hash is available.
|
||||
var transaction_entry = self.remote.request_transaction_entry(self.hash)
|
||||
transaction_entry.ledger_hash(ledger_hash)
|
||||
transaction_entry.on('success', function (message) {
|
||||
if (self.finalized) return;
|
||||
self.set_state(message.metadata.TransactionResult);
|
||||
self.remote.removeListener('ledger_closed', on_ledger_closed);
|
||||
self.emit('final', message);
|
||||
self.finalized = true;
|
||||
if (self.callback) {
|
||||
self.callback(message.metadata.TransactionResult, message);
|
||||
// When a ledger closes, look for the result.
|
||||
function on_ledger_closed(message) {
|
||||
var ledger_hash = message.ledger_hash;
|
||||
var ledger_index = message.ledger_index;
|
||||
var stop = false;
|
||||
|
||||
// XXX make sure self.hash is available.
|
||||
var transaction_entry = self.remote.request_transaction_entry(self.hash)
|
||||
|
||||
transaction_entry.ledger_hash(ledger_hash)
|
||||
|
||||
transaction_entry.on('success', function (message) {
|
||||
if (self.finalized) return;
|
||||
self.set_state(message.metadata.TransactionResult);
|
||||
self.remote.removeListener('ledger_closed', on_ledger_closed);
|
||||
self.emit('final', message);
|
||||
self.finalized = true;
|
||||
self.callback(message.metadata.TransactionResult, message);
|
||||
});
|
||||
|
||||
transaction_entry.on('error', function (message) {
|
||||
if (self.finalized) return;
|
||||
|
||||
if (message.error === 'remoteError' && message.remote.error === 'transactionNotFound') {
|
||||
if (self.submit_index + SUBMIT_LOST < ledger_index) {
|
||||
self.set_state('client_lost'); // Gave up.
|
||||
self.emit('lost');
|
||||
self.callback('tejLost', message);
|
||||
self.remote.removeListener('ledger_closed', on_ledger_closed);
|
||||
self.emit('final', message);
|
||||
self.finalized = true;
|
||||
} 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');
|
||||
} else {
|
||||
self.emit('pending');
|
||||
}
|
||||
});
|
||||
transaction_entry.on('error', function (message) {
|
||||
if (self.finalized) return;
|
||||
}
|
||||
// XXX Could log other unexpectedness.
|
||||
});
|
||||
|
||||
if (message.error === 'remoteError' && message.remote.error === 'transactionNotFound') {
|
||||
if (self.submit_index + SUBMIT_LOST < ledger_index) {
|
||||
self.set_state('client_lost'); // Gave up.
|
||||
self.emit('lost');
|
||||
if (self.callback) {
|
||||
self.callback('tejLost', message);
|
||||
}
|
||||
self.remote.removeListener('ledger_closed', on_ledger_closed);
|
||||
self.emit('final', message);
|
||||
self.finalized = true;
|
||||
} 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');
|
||||
} else {
|
||||
self.emit('pending');
|
||||
}
|
||||
}
|
||||
// XXX Could log other unexpectedness.
|
||||
});
|
||||
transaction_entry.request();
|
||||
};
|
||||
|
||||
transaction_entry.request();
|
||||
};
|
||||
this.remote.on('ledger_closed', on_ledger_closed);
|
||||
|
||||
this.remote.on('ledger_closed', on_ledger_closed);
|
||||
|
||||
if (this.callback) {
|
||||
this.once('error', function (message) {
|
||||
self.callback(message.error, message);
|
||||
});
|
||||
}
|
||||
}
|
||||
this.once('error', function (message) {
|
||||
self.callback(message.error, message);
|
||||
});
|
||||
|
||||
this.set_state('client_submitted');
|
||||
|
||||
if (self.remote.local_sequence && !self.tx_json.Sequence) {
|
||||
self.tx_json.Sequence = this.remote.account_seq(self.tx_json.Account, 'ADVANCE');
|
||||
|
||||
self.tx_json.Sequence = this.remote.account_seq(self.tx_json.Account, 'ADVANCE');
|
||||
// console.log("Sequence: %s", self.tx_json.Sequence);
|
||||
|
||||
if (!self.tx_json.Sequence) {
|
||||
//console.log('NO SEQUENCE');
|
||||
|
||||
// Look in the last closed ledger.
|
||||
var account_seq = this.remote.account_seq_cache(self.tx_json.Account, false)
|
||||
|
||||
@@ -364,8 +374,8 @@ Transaction.prototype.submit = function (callback) {
|
||||
|
||||
// If the transaction fails we want to either undo incrementing the sequence
|
||||
// or submit a noop transaction to consume the sequence remotely.
|
||||
this.on('success', function (res) {
|
||||
if (res && typeof res.engine_result === 'string') {
|
||||
this.once('success', function (res) {
|
||||
if (typeof res.engine_result === 'string') {
|
||||
switch (res.engine_result.slice(0, 3)) {
|
||||
// Synchronous local error
|
||||
case 'tej':
|
||||
@@ -401,7 +411,7 @@ Transaction.prototype.submit = function (callback) {
|
||||
request.emit = this.emit.bind(this);
|
||||
|
||||
if (!this._secret && !this.tx_json.Signature) {
|
||||
this.emit('error', {
|
||||
finish({
|
||||
'result' : 'tejSecretUnknown',
|
||||
'result_message' : "Could not sign transactions because we."
|
||||
});
|
||||
@@ -411,11 +421,10 @@ Transaction.prototype.submit = function (callback) {
|
||||
request.tx_blob(this.serialize().to_hex());
|
||||
} else {
|
||||
if (!this.remote.trusted) {
|
||||
this.emit('error', {
|
||||
finish({
|
||||
'result' : 'tejServerUntrusted',
|
||||
'result_message' : "Attempt to give a secret to an untrusted server."
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
request.secret(this._secret);
|
||||
|
||||
Reference in New Issue
Block a user