Fixes and cleanup for Remote, update readme

This commit is contained in:
wltsmrz
2013-07-13 05:31:40 +09:00
parent 9ec72ee8c5
commit 9550edab9b
5 changed files with 292 additions and 186 deletions

103
README.md
View File

@@ -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. 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 * https://ripple.com/wiki/Ripple_JavaScript_library
For more information: ##See also
* https://ripple.com * https://ripple.com
* https://ripple.com/wiki * 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()**

View File

@@ -9,35 +9,32 @@
// var network = require("./network.js"); // var network = require("./network.js");
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var util = require('util'); var util = require('util');
var Amount = require('./amount').Amount; var Amount = require('./amount').Amount;
var UInt160 = require('./uint160').UInt160; var UInt160 = require('./uint160').UInt160;
var Currency = require('./currency').Currency; var Currency = require('./currency').Currency;
var extend = require('extend'); var extend = require('extend');
var OrderBook = function (remote, var OrderBook = function (remote, currency_gets, issuer_gets, currency_pays, issuer_pays) {
currency_gets, issuer_gets,
currency_pays, issuer_pays) {
EventEmitter.call(this); EventEmitter.call(this);
var self = this; var self = this;
this._remote = remote; this._remote = remote;
this._currency_gets = currency_gets; this._currency_gets = currency_gets;
this._issuer_gets = issuer_gets; this._issuer_gets = issuer_gets;
this._currency_pays = currency_pays; this._currency_pays = currency_pays;
this._issuer_pays = issuer_pays; this._issuer_pays = issuer_pays;
this._subs = 0;
this._subs = 0;
// We consider ourselves synchronized if we have a current copy of the offers, // We consider ourselves synchronized if we have a current copy of the offers,
// we are online and subscribed to updates. // we are online and subscribed to updates.
this._sync = false; this._sync = false;
// Offers // Offers
this._offers = []; this._offers = [];
this.on('newListener', function (type, listener) { this.on('newListener', function (type, listener) {
if (OrderBook.subscribe_events.indexOf(type) !== -1) { if (OrderBook.subscribe_events.indexOf(type) !== -1) {
@@ -49,10 +46,9 @@ var OrderBook = function (remote,
}); });
this.on('removeListener', function (type, listener) { this.on('removeListener', function (type, listener) {
if (OrderBook.subscribe_events.indexOf(type) !== -1) { if (~OrderBook.subscribe_events.indexOf(type)) {
self._subs -= 1; self._subs -= 1;
if (!self._subs && self._remote._connected) {
if (!self._subs && 'open' === self._remote._online_state) {
self._sync = false; self._sync = false;
self._remote.request_unsubscribe() self._remote.request_unsubscribe()
.books([self.to_json()]) .books([self.to_json()])
@@ -86,8 +82,7 @@ OrderBook.subscribe_events = ['transaction', 'model', 'trade'];
* *
* @private * @private
*/ */
OrderBook.prototype._subscribe = function () OrderBook.prototype._subscribe = function () {
{
var self = this; var self = this;
self._remote.request_subscribe() self._remote.request_subscribe()
.books([self.to_json()], true) .books([self.to_json()], true)
@@ -95,26 +90,28 @@ OrderBook.prototype._subscribe = function ()
// XXX What now? // XXX What now?
}) })
.on('success', function (res) { .on('success', function (res) {
self._sync = true; self._sync = true;
self._offers = res.offers; self._offers = res.offers;
self.emit('model', self._offers); self.emit('model', self._offers);
}) })
.request(); .request();
}; };
OrderBook.prototype.to_json = function () OrderBook.prototype.to_json = function () {
{
var json = { var json = {
"taker_gets": { 'taker_gets': {
"currency": this._currency_gets 'currency': this._currency_gets
}, },
"taker_pays": { 'taker_pays': {
"currency": this._currency_pays 'currency': this._currency_pays
} }
}; };
if (this._currency_gets !== "XRP") json["taker_gets"]["issuer"] = this._issuer_gets; if (this._currency_gets !== 'XRP')
if (this._currency_pays !== "XRP") json["taker_pays"]["issuer"] = this._issuer_pays; json['taker_gets']['issuer'] = this._issuer_gets;
if (this._currency_pays !== 'XRP')
json['taker_pays']['issuer'] = this._issuer_pays;
return json; return json;
}; };
@@ -125,78 +122,88 @@ OrderBook.prototype.to_json = function ()
* Note: This only checks whether the parameters (currencies and issuer) are * Note: This only checks whether the parameters (currencies and issuer) are
* syntactically valid. It does not check anything against the ledger. * 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 // XXX Should check for same currency (non-native) && same issuer
return ( return (
Currency.is_valid(this._currency_pays) && 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) && Currency.is_valid(this._currency_gets) &&
(this._currency_gets === "XRP" || UInt160.is_valid(this._issuer_gets)) && (this._currency_gets === 'XRP' || UInt160.is_valid(this._issuer_gets)) &&
!(this._currency_pays === "XRP" && this._currency_gets === "XRP") !(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. * Notify object of a relevant transaction.
* *
* This is only meant to be called by the Remote class. You should never have to * This is only meant to be called by the Remote class. You should never have to
* call this yourself. * call this yourself.
*/ */
OrderBook.prototype.notifyTx = function (message) OrderBook.prototype.notifyTx = function (message) {
{ var self = this;
var self = this; var changed = false;
var trade_gets = this.trade('gets');
var changed = false; var trade_pays = this.trade('pays');
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));
message.mmeta.each(function (an) { message.mmeta.each(function (an) {
if (an.entryType !== 'Offer') return; if (an.entryType !== 'Offer') return;
var i, l, offer; var i, l, offer;
if (an.diffType === 'DeletedNode' ||
an.diffType === 'ModifiedNode') { switch(an.diffType) {
for (i = 0, l = self._offers.length; i < l; i++) { case 'DeletedNode':
offer = self._offers[i]; case 'ModifiedNode':
if (offer.index === an.ledgerIndex) { var deletedNode = an.diffType === 'DeletedNode';
if (an.diffType === 'DeletedNode') {
self._offers.splice(i, 1); 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 // We don't want to count a OfferCancel as a trade
if (message.transaction.TransactionType === "OfferCancel") return; if (message.transaction.TransactionType === 'OfferCancel') return;
trade_gets = trade_gets.add(an.fieldsPrev.TakerGets); trade_gets = trade_gets.add(an.fieldsPrev.TakerGets);
trade_pays = trade_pays.add(an.fieldsPrev.TakerPays); 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);
if (price.compareTo(priceItem) <= 0) { if (!deletedNode) {
var obj = an.fields; trade_gets = trade_gets.subtract(an.fieldsFinal.TakerGets);
obj.index = an.ledgerIndex; trade_pays = trade_pays.subtract(an.fieldsFinal.TakerPays);
self._offers.splice(i, 0, an.fields);
changed = true;
break;
} }
} 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. * 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; var self = this;
if (typeof callback === 'function') {
if ("function" === typeof callback) {
if (this._sync) { if (this._sync) {
callback(this._offers); callback(this._offers);
} else { } else {
this.once('model', function (offers) { this.once('model', callback);
callback(offers);
});
} }
} }
return this; 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 * 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. * loaded yet. But this accessor may be convenient in some circumstances.
*/ */
OrderBook.prototype.offersSync = function () OrderBook.prototype.offersSync = function () {
{
return this._offers; return this._offers;
}; };
exports.OrderBook = OrderBook; exports.OrderBook = OrderBook;
// vim:sw=2:sts=2:ts=8:et // vim:sw=2:sts=2:ts=8:et

View File

@@ -37,16 +37,13 @@ var sjcl = require('../../../build/sjcl');
// 'remoteError' // 'remoteError'
// 'remoteUnexpected' // 'remoteUnexpected'
// 'remoteDisconnected' // 'remoteDisconnected'
var Request = function (remote, command) { function Request(remote, command) {
EventEmitter.call(this); EventEmitter.call(this);
var self = this;
this.remote = remote; this.remote = remote;
this.requested = false; this.requested = false;
this.message = { this.message = {
'command' : command, command : command,
'id' : undefined, id : void(0)
}; };
}; };
@@ -67,6 +64,7 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
this.once(errorEvent || 'error', callback); this.once(errorEvent || 'error', callback);
this.request(); this.request();
} }
return this; return this;
}; };
@@ -143,8 +141,8 @@ Request.prototype.index = function (hash) {
// --> seq : sequence number of transaction creating offer (integer) // --> seq : sequence number of transaction creating offer (integer)
Request.prototype.offer_id = function (account, seq) { Request.prototype.offer_id = function (account, seq) {
this.message.offer = { this.message.offer = {
'account' : UInt160.json_rewrite(account), account: UInt160.json_rewrite(account),
'seq' : seq seq: seq
}; };
return this; return this;
@@ -228,20 +226,20 @@ Request.prototype.books = function (books, snapshot) {
function processSide(side) { function processSide(side) {
if (!book[side]) throw new Error('Missing '+side); if (!book[side]) throw new Error('Missing '+side);
var obj = {}; var obj = json[side] = {
obj['currency'] = Currency.json_rewrite(book[side]['currency']); currency: Currency.json_rewrite(book[side].currency)
if (obj['currency'] !== 'XRP') { };
obj.issuer = UInt160.json_rewrite(book[side]['issuer']);
if (obj.currency !== 'XRP') {
obj.issuer = UInt160.json_rewrite(book[side].issuer);
} }
json[side] = obj;
} }
processSide('taker_gets'); processSide('taker_gets');
processSide('taker_pays'); processSide('taker_pays');
if (snapshot || book['snapshot']) json['snapshot'] = true; if (snapshot) json.snapshot = true;
if (book['both']) json['both'] = true; if (book.both) json.both = true;
procBooks.push(json); procBooks.push(json);
} }
@@ -286,7 +284,7 @@ Request.prototype.books = function (books, snapshot) {
@param trace @param trace
*/ */
var Remote = function (opts, trace) { function Remote(opts, trace) {
EventEmitter.call(this); EventEmitter.call(this);
var self = this; var self = this;
@@ -321,7 +319,6 @@ var Remote = function (opts, trace) {
this._connection_count = 0; this._connection_count = 0;
this._connected = false; this._connected = false;
this._last_tx = null; this._last_tx = null;
// Local signing implies local fees and sequences // Local signing implies local fees and sequences
@@ -661,6 +658,7 @@ Remote.prototype._server_is_available = function (server) {
Remote.prototype._next_server = function () { Remote.prototype._next_server = function () {
var result = null; var result = null;
for (var i=0; i<this._servers.length; i++) { for (var i=0; i<this._servers.length; i++) {
var server = this._servers[i]; var server = this._servers[i];
if (this._server_is_available(server)) { if (this._server_is_available(server)) {
@@ -668,17 +666,20 @@ Remote.prototype._next_server = function () {
break; break;
} }
} }
return result; return result;
}; };
Remote.prototype._get_server = function () { Remote.prototype._get_server = function () {
var server; var server;
if (this._server_is_available(this._primary_server)) { if (this._server_is_available(this._primary_server)) {
server = this._primary_server; server = this._primary_server;
} else { } else {
server = this._next_server(); server = this._next_server();
if (server) this._set_primary_server(server); if (server) this._set_primary_server(server);
} }
return server; return server;
}; };
@@ -716,7 +717,7 @@ Remote.prototype.request_ledger = function (ledger, opts, callback) {
request.message.ledger = ledger; request.message.ledger = ledger;
} }
if ('object' == typeof opts) { if (typeof opts === 'object') {
if (opts.full) if (opts.full)
request.message.full = true; request.message.full = true;
@@ -728,9 +729,7 @@ Remote.prototype.request_ledger = function (ledger, opts, callback) {
if (opts.accounts) if (opts.accounts)
request.message.accounts = true; request.message.accounts = true;
} } else if (opts) { // DEPRECATED:
// DEPRECATED:
else if (opts) {
console.log('request_ledger: full parameter is deprecated'); console.log('request_ledger: full parameter is deprecated');
request.message.full = true; request.message.full = true;
} }
@@ -841,10 +840,7 @@ Remote.prototype.request_subscribe = function (streams, callback) {
var request = new Request(this, 'subscribe'); var request = new Request(this, 'subscribe');
if (streams) { if (streams) {
if (!Array.isArray(streams)) { request.message.streams = Array.isArray(streams) ? streams : [ streams ];
streams = [ streams ];
}
request.message.streams = streams;
} }
return request.callback(callback); return request.callback(callback);
@@ -855,10 +851,7 @@ Remote.prototype.request_unsubscribe = function (streams, callback) {
var request = new Request(this, 'unsubscribe'); var request = new Request(this, 'unsubscribe');
if (streams) { if (streams) {
if (!Array.isArray(streams)) { request.message.streams = Array.isArray(streams) ? streams : [ streams ];
streams = [ streams ];
}
request.message.streams = streams;
} }
return request.callback(callback); 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. // Mark an account's root node as dirty.
Remote.prototype.dirty_account_root = function (account) { 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]; delete this.ledgers.current.account_root[account];
}; };
@@ -1349,8 +1342,8 @@ Remote.prototype.request_unl_delete = function (node, callback) {
return request.callback(callback); return request.callback(callback);
}; };
Remote.prototype.request_peers = function () { Remote.prototype.request_peers = function (callback) {
return new Request(this, 'peers'); return new Request(this, 'peers').callback(callback);
}; };
Remote.prototype.request_connect = function (ip, port, callback) { Remote.prototype.request_connect = function (ip, port, callback) {

View File

@@ -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. * Submit a Request object to this server.
*/ */
@@ -199,20 +203,19 @@ Server.prototype.request = function (request) {
// Advance message ID // Advance message ID
self._id++; self._id++;
if (self._state === 'online' || if (self._connected || (request.message.command === 'subscribe' && self._ws.readyState === 1)) {
(request.message.command === 'subscribe' && self._ws.readyState === 1)) {
if (self._remote.trace) { if (self._remote.trace) {
utils.logObject('server: request: %s', request.message); utils.logObject('server: request: %s', request.message);
} }
self._ws.send(JSON.stringify(request.message)); self.send_message(request.message);
} else { } else {
// XXX There are many ways to make self smarter. // XXX There are many ways to make self smarter.
self.once('connect', function () { self.once('connect', function () {
if (self._remote.trace) { if (self._remote.trace) {
utils.logObject('server: request: %s', request.message); utils.logObject('server: request: %s', request.message);
} }
self._ws.send(JSON.stringify(request.message)); self.send_message(request.message);
}); });
} }
} else { } else {

View File

@@ -206,6 +206,8 @@ Transaction.prototype.complete = function () {
var key = seed.get_key(this.tx_json.Account); var key = seed.get_key(this.tx_json.Account);
tx_json.SigningPubKey = key.to_hex_pub(); tx_json.SigningPubKey = key.to_hex_pub();
} }
return this.tx_json;
}; };
Transaction.prototype.serialize = function () { Transaction.prototype.serialize = function () {
@@ -250,14 +252,22 @@ Transaction.prototype._hasTransactionListeners = function() {
// case 'tejLost': locally gave up looking // case 'tejLost': locally gave up looking
// default: some other TER // default: some other TER
// } // }
Transaction.prototype.submit = function (callback) { Transaction.prototype.submit = function (callback) {
var self = this; var self = this;
var tx_json = this.tx_json; 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') { if (typeof tx_json.Account !== 'string') {
(this.callback || this.emit)('error', { finish({
'error' : 'tejInvalidAccount', 'error' : 'tejInvalidAccount',
'error_message' : 'Bad account.' 'error_message' : 'Bad account.'
}); });
@@ -268,72 +278,72 @@ Transaction.prototype.submit = function (callback) {
this.complete(); this.complete();
if (this.callback || this._hasTransactionListeners()) { //console.log('Callback or has listeners');
// There are listeners for callback, 'final', 'lost', or 'pending' arrange to emit them.
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. this.submit_index = this.remote._ledger_current_index;
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. // When a ledger closes, look for the result.
var transaction_entry = self.remote.request_transaction_entry(self.hash) function on_ledger_closed(message) {
transaction_entry.ledger_hash(ledger_hash) var ledger_hash = message.ledger_hash;
transaction_entry.on('success', function (message) { var ledger_index = message.ledger_index;
if (self.finalized) return; var stop = false;
self.set_state(message.metadata.TransactionResult);
self.remote.removeListener('ledger_closed', on_ledger_closed); // XXX make sure self.hash is available.
self.emit('final', message); var transaction_entry = self.remote.request_transaction_entry(self.hash)
self.finalized = true;
if (self.callback) { transaction_entry.ledger_hash(ledger_hash)
self.callback(message.metadata.TransactionResult, message);
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) { // XXX Could log other unexpectedness.
if (self.finalized) return; });
if (message.error === 'remoteError' && message.remote.error === 'transactionNotFound') { transaction_entry.request();
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(); this.remote.on('ledger_closed', on_ledger_closed);
};
this.remote.on('ledger_closed', on_ledger_closed); this.once('error', function (message) {
self.callback(message.error, message);
if (this.callback) { });
this.once('error', function (message) {
self.callback(message.error, message);
});
}
}
this.set_state('client_submitted'); this.set_state('client_submitted');
if (self.remote.local_sequence && !self.tx_json.Sequence) { 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); // console.log("Sequence: %s", self.tx_json.Sequence);
if (!self.tx_json.Sequence) { if (!self.tx_json.Sequence) {
//console.log('NO SEQUENCE');
// Look in the last closed ledger. // Look in the last closed ledger.
var account_seq = this.remote.account_seq_cache(self.tx_json.Account, false) 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 // If the transaction fails we want to either undo incrementing the sequence
// or submit a noop transaction to consume the sequence remotely. // or submit a noop transaction to consume the sequence remotely.
this.on('success', function (res) { this.once('success', function (res) {
if (res && typeof res.engine_result === 'string') { if (typeof res.engine_result === 'string') {
switch (res.engine_result.slice(0, 3)) { switch (res.engine_result.slice(0, 3)) {
// Synchronous local error // Synchronous local error
case 'tej': case 'tej':
@@ -401,7 +411,7 @@ Transaction.prototype.submit = function (callback) {
request.emit = this.emit.bind(this); request.emit = this.emit.bind(this);
if (!this._secret && !this.tx_json.Signature) { if (!this._secret && !this.tx_json.Signature) {
this.emit('error', { finish({
'result' : 'tejSecretUnknown', 'result' : 'tejSecretUnknown',
'result_message' : "Could not sign transactions because we." 'result_message' : "Could not sign transactions because we."
}); });
@@ -411,11 +421,10 @@ Transaction.prototype.submit = function (callback) {
request.tx_blob(this.serialize().to_hex()); request.tx_blob(this.serialize().to_hex());
} else { } else {
if (!this.remote.trusted) { if (!this.remote.trusted) {
this.emit('error', { finish({
'result' : 'tejServerUntrusted', 'result' : 'tejServerUntrusted',
'result_message' : "Attempt to give a secret to an untrusted server." 'result_message' : "Attempt to give a secret to an untrusted server."
}); });
return this;
} }
request.secret(this._secret); request.secret(this._secret);