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