mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-19 03:35:49 +00:00
Update pending transaction fees
This commit is contained in:
@@ -80,9 +80,9 @@ function Remote(opts, trace) {
|
||||
|
||||
var self = this;
|
||||
|
||||
this.trusted = opts.trusted;
|
||||
this.local_sequence = opts.local_sequence; // Locally track sequence numbers
|
||||
this.local_fee = opts.local_fee; // Locally set fees
|
||||
this.trusted = Boolean(opts.trusted);
|
||||
this.local_sequence = Boolean(opts.local_sequence); // Locally track sequence numbers
|
||||
this.local_fee = (typeof opts.local_fee === 'undefined') ? true : Boolean(opts.local_fee); // Locally set fees
|
||||
this.local_signing = (typeof opts.local_signing === 'undefined') ? true : Boolean(opts.local_signing);
|
||||
this.fee_cushion = (typeof opts.fee_cushion === 'undefined') ? 1.5 : Number(opts.fee_cushion);
|
||||
this.max_fee = (typeof opts.max_fee === 'undefined') ? Infinity : Number(opts.max_fee);
|
||||
@@ -110,6 +110,7 @@ function Remote(opts, trace) {
|
||||
this._connection_count = 0;
|
||||
this._connected = false;
|
||||
this._connection_offset = 1000 * (Number(opts.connection_offset) || 5);
|
||||
this._submission_timeout = 1000 * (Number(opts.submission_timeout) || 10);
|
||||
|
||||
this._last_tx = null;
|
||||
this._cur_path_find = null;
|
||||
@@ -477,7 +478,13 @@ Remote.prototype._handle_message = function (message, server) {
|
||||
if (load_changed) {
|
||||
self._load_base = message.load_base;
|
||||
self._load_factor = message.load_factor;
|
||||
self.emit('load', { 'load_base' : self._load_base, 'load_factor' : self.load_factor });
|
||||
var obj = {
|
||||
load_base: self._load_base,
|
||||
load_factor: self._load_factor,
|
||||
fee_units: self.fee_tx_unit()
|
||||
}
|
||||
self.emit('load', obj);
|
||||
self.emit('load_changed', obj);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -564,7 +564,7 @@ Transaction.prototype.submit = function (callback) {
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
exports.Transaction = Transaction;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ var util = require('util');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var RippleError = require('./rippleerror').RippleError;
|
||||
var Queue = require('./transactionqueue').TransactionQueue;
|
||||
var Amount = require('./amount');
|
||||
|
||||
/**
|
||||
* @constructor TransactionManager
|
||||
@@ -11,32 +12,38 @@ var Queue = require('./transactionqueue').TransactionQueue;
|
||||
function TransactionManager(account) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
var self = this;
|
||||
var self = this;
|
||||
|
||||
this.account = account;
|
||||
this.remote = account._remote;
|
||||
this._timeout = void(0);
|
||||
this._resubmitting = false;
|
||||
this._pending = new Queue;
|
||||
this._next_sequence = void(0);
|
||||
this._cache = { };
|
||||
|
||||
//XX Fee units
|
||||
this._max_fee = Number(this.remote.max_fee) || Infinity;
|
||||
this._max_fee = this.remote.max_fee;
|
||||
|
||||
this._submission_timeout = this.remote._submission_timeout;
|
||||
|
||||
function remote_reconnected() {
|
||||
self.account.get_next_sequence(function(err, sequence) {
|
||||
sequence_loaded(err, sequence);
|
||||
self._resubmit(3);
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
function sequence_loaded(err, sequence, callback) {
|
||||
self._next_sequence = sequence;
|
||||
self.emit('sequence_loaded', sequence);
|
||||
};
|
||||
callback && callback();
|
||||
}
|
||||
|
||||
this.account.get_next_sequence(sequence_loaded);
|
||||
|
||||
@@ -54,7 +61,18 @@ function TransactionManager(account) {
|
||||
self._cache[message.transaction.Sequence] = transaction;
|
||||
}
|
||||
|
||||
this.account.on('transaction', cache_transaction);
|
||||
this.account.on('transaction-outbound', cache_transaction);
|
||||
|
||||
function adjust_fees() {
|
||||
self._pending.forEach(function(pending) {
|
||||
if (pending.tx_json.Fee) {
|
||||
var newFee = self.remote.fee_tx(pending.fee_units()).to_json();
|
||||
pending.tx_json.Fee = newFee;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.remote.on('load_changed', adjust_fees);
|
||||
};
|
||||
|
||||
util.inherits(TransactionManager, EventEmitter);
|
||||
@@ -79,14 +97,22 @@ function rewrite_transaction(tx) {
|
||||
hash: tx.hash
|
||||
}
|
||||
}
|
||||
} catch(exception) {
|
||||
}
|
||||
} catch(exception) { }
|
||||
return result || { };
|
||||
};
|
||||
|
||||
TransactionManager.prototype._resubmit = function() {
|
||||
TransactionManager.prototype._resubmit = function(wait_ledgers) {
|
||||
var self = this;
|
||||
|
||||
if (wait_ledgers) {
|
||||
var ledgers = Number(wait_ledgers) || 3;
|
||||
this._wait_ledgers(ledgers, function() {
|
||||
self._pending.forEach(resubmit);
|
||||
});
|
||||
} else {
|
||||
self._pending.forEach(resubmit);
|
||||
}
|
||||
|
||||
function resubmit(pending, index) {
|
||||
if (pending.finalized) {
|
||||
// Transaction has been finalized, nothing to do
|
||||
@@ -109,22 +135,25 @@ TransactionManager.prototype._resubmit = function() {
|
||||
|
||||
function pending_check(err, res) {
|
||||
if (self._is_not_found(err)) {
|
||||
//XX
|
||||
self._request(pending);
|
||||
} else {
|
||||
pending.emit('success', rewrite_transaction(res));
|
||||
}
|
||||
}
|
||||
|
||||
self.remote.request_tx(pending.hash, pending_check);
|
||||
var request = self.remote.request_tx(pending.hash, pending_check);
|
||||
|
||||
request.timeout(self._submission_timeout, function() {
|
||||
if (self.remote._connected) {
|
||||
self._resubmit(1);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self._request(pending);
|
||||
}
|
||||
}
|
||||
|
||||
this._wait_ledgers(3, function() {
|
||||
self._pending.forEach(resubmit);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TransactionManager.prototype._wait_ledgers = function(ledgers, callback) {
|
||||
var self = this;
|
||||
@@ -144,27 +173,6 @@ TransactionManager.prototype._request = function(tx) {
|
||||
var self = this;
|
||||
var remote = this.remote;
|
||||
|
||||
if (!tx._secret && !tx.tx_json.TxnSignature) {
|
||||
tx.emit('error', new RippleError('tejSecretUnknown', 'Missing secret'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!remote.trusted && !remote.local_signing) {
|
||||
tx.emit('error', new RippleError('tejServerUntrusted', 'Attempt to give secret to untrusted server'));
|
||||
return;
|
||||
}
|
||||
|
||||
function finalize(message) {
|
||||
if (!tx.finalized) {
|
||||
tx.finalized = true;
|
||||
tx.emit('final', message);
|
||||
self._pending.removeSequence(tx.tx_json.Sequence);
|
||||
}
|
||||
}
|
||||
|
||||
tx.once('error', finalize);
|
||||
tx.once('success', finalize);
|
||||
|
||||
// Listen for 'ledger closed' events to verify
|
||||
// that the transaction is discovered in the
|
||||
// ledger before considering the transaction
|
||||
@@ -189,16 +197,9 @@ TransactionManager.prototype._request = function(tx) {
|
||||
tx.set_state('client_proposed');
|
||||
tx.emit('proposed', {
|
||||
tx_json: message.tx_json,
|
||||
|
||||
result: message.engine_result,
|
||||
engine_result: message.engine_result,
|
||||
|
||||
result_code: message.engine_result_code,
|
||||
engine_result_code: message.engine_result_code,
|
||||
|
||||
result_message: message.engine_result_message,
|
||||
engine_result_message: message.engine_result_message,
|
||||
|
||||
// If server is honest, don't expect a final if rejected.
|
||||
rejected: tx.isRejected(message.engine_result_code),
|
||||
});
|
||||
@@ -209,33 +210,56 @@ TransactionManager.prototype._request = function(tx) {
|
||||
|
||||
function transaction_requested(err, res) {
|
||||
if (self._is_not_found(err)) {
|
||||
self._resubmit();
|
||||
self._resubmit(1);
|
||||
} else {
|
||||
//XX
|
||||
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) {
|
||||
function transaction_retry(message) {
|
||||
switch (message.engine_result) {
|
||||
case 'terPRE_SEQ':
|
||||
self._resubmit(1);
|
||||
break;
|
||||
default:
|
||||
submission_error(new RippleError(message));
|
||||
}
|
||||
}
|
||||
|
||||
function submission_error(error) {
|
||||
//Decrement sequence
|
||||
self._next_sequence--;
|
||||
tx.set_state('remoteError');
|
||||
tx.emit('error', new RippleError(err));
|
||||
tx.emit('submitted', error);
|
||||
tx.emit('error', new RippleError(error));
|
||||
}
|
||||
|
||||
function submission_success(message) {
|
||||
tx.emit('submitted', message);
|
||||
|
||||
if (tx.attempts > 5) {
|
||||
tx.emit('error', new RippleError(message));
|
||||
return;
|
||||
}
|
||||
|
||||
var engine_result = message.engine_result || '';
|
||||
|
||||
tx.hash = message.tx_json.hash;
|
||||
|
||||
switch (engine_result.slice(0, 3)) {
|
||||
case 'tes':
|
||||
transaction_proposed(message);
|
||||
break;
|
||||
case 'tef':
|
||||
//tefPAST_SEQ
|
||||
transaction_failed(message);
|
||||
break;
|
||||
case 'tes':
|
||||
transaction_proposed(message);
|
||||
case 'ter':
|
||||
transaction_retry(message);
|
||||
break;
|
||||
default:
|
||||
submission_error(message);
|
||||
@@ -246,14 +270,14 @@ TransactionManager.prototype._request = function(tx) {
|
||||
submit_request.once('error', submission_error);
|
||||
submit_request.request();
|
||||
|
||||
submit_request.timeout(1000 * 10, function() {
|
||||
submit_request.timeout(this._submission_timeout, function() {
|
||||
if (self.remote._connected) {
|
||||
self._resubmit();
|
||||
self._resubmit(1);
|
||||
}
|
||||
});
|
||||
|
||||
tx.set_state('client_submitted');
|
||||
tx.emit('submitted');
|
||||
tx.attempts++;
|
||||
|
||||
return submit_request;
|
||||
};
|
||||
@@ -329,6 +353,7 @@ TransactionManager.prototype._detect_ledger_entry = function(tx) {
|
||||
|
||||
tx.once('proposed', transaction_proposed);
|
||||
tx.once('final', transaction_finalized);
|
||||
tx.once('abort', transaction_finalized);
|
||||
tx.once('resubmit', transaction_finalized);
|
||||
};
|
||||
|
||||
@@ -349,13 +374,31 @@ TransactionManager.prototype.submit = function(tx) {
|
||||
}
|
||||
|
||||
tx.tx_json.Sequence = this._next_sequence++;
|
||||
tx.attempts = 0;
|
||||
tx.complete();
|
||||
|
||||
this._pending.push(tx);
|
||||
function finalize(message) {
|
||||
if (!tx.finalized) {
|
||||
self._pending.removeSequence(tx.tx_json.Sequence);
|
||||
tx.finalized = true;
|
||||
tx.emit('final', message);
|
||||
}
|
||||
}
|
||||
|
||||
tx.once('error', finalize);
|
||||
tx.once('success', finalize);
|
||||
|
||||
var fee = tx.tx_json.Fee;
|
||||
var remote = this.remote;
|
||||
|
||||
if (fee === void(0) || fee <= this._max_fee) {
|
||||
if (!tx._secret && !tx.tx_json.TxnSignature) {
|
||||
tx.emit('error', new RippleError('tejSecretUnknown', 'Missing secret'));
|
||||
} else if (!remote.trusted && !remote.local_signing) {
|
||||
tx.emit('error', new RippleError('tejServerUntrusted', 'Attempt to give secret to untrusted server'));
|
||||
} else if (fee && fee > this._max_fee) {
|
||||
tx.emit('error', new RippleError('tejMaxFeeExceeded', 'Max fee exceeded'));
|
||||
} else {
|
||||
this._pending.push(tx);
|
||||
this._request(tx);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user