Fixes for per-transaction defined secret and offline errors

This commit is contained in:
wltsmrz
2014-04-23 14:19:02 -07:00
parent 18efa5d742
commit 52e1665e72
3 changed files with 54 additions and 81 deletions

View File

@@ -281,8 +281,25 @@ Transaction.prototype._getServer = function() {
Transaction.prototype.complete = function() {
// Try to auto-fill the secret
if (!this._secret && !(this._secret = this._account_secret(this.tx_json.Account))) {
return this.emit('error', new RippleError('tejSecretUnknown', 'Missing secret'));
if (!this._secret && !(this._secret = this._accountSecret(this.tx_json.Account))) {
this.emit('error', new RippleError('tejSecretUnknown', 'Missing secret'));
return false;
}
if (typeof this.tx_json.SigningPubKey === 'undefined') {
try {
var seed = Seed.from_json(this._secret);
var key = seed.get_key(this.tx_json.Account);
this.tx_json.SigningPubKey = key.to_hex_pub();
} catch(e) {
this.emit('error', new RippleError('tejSecretInvalid', 'Invalid secret'));
return false;
}
}
if (!this.remote.trusted && !this.remote.local_signing) {
this.emit('error', new RippleError('tejServerUntrusted', 'Attempt to give secret to untrusted server'));
return false;
}
// If the Fee hasn't been set, one needs to be computed by
@@ -294,14 +311,9 @@ Transaction.prototype.complete = function() {
}
}
if (typeof this.tx_json.SigningPubKey === 'undefined') {
try {
var seed = Seed.from_json(this._secret);
var key = seed.get_key(this.tx_json.Account);
this.tx_json.SigningPubKey = key.to_hex_pub();
} catch(e) {
return this.emit('error', new RippleError('tejSecretInvalid', 'Invalid secret'));
}
if (Number(this.tx_json.Fee) > this._maxFee) {
tx.emit('error', new RippleError('tejMaxFeeExceeded', 'Max fee exceeded'));
return false;
}
// Set canonical flag - this enables canonicalized signature checking

View File

@@ -184,24 +184,20 @@ TransactionManager.prototype._fillSequence = function(tx, callback) {
fill.account_set(self._accountID);
fill.tx_json.Sequence = sequence;
fill.once('submitted', callback);
// Secrets may be set on a per-transaction basis
if (tx._secret) {
fill.secret(tx._secret);
}
fill.submit();
};
function sequenceLoaded(err, sequence) {
if (typeof sequence !== 'number') {
callback(new Error('Failed to fetch account transaction sequence'));
return;
}
var sequenceDif = tx.tx_json.Sequence - sequence;
var submitted = 0;
for (var i=sequence; i<tx.tx_json.Sequence; i++) {
submitFill(i, function() {
if (++submitted === sequenceDif) {
callback();
}
});
} else {
submitFill(sequence, callback);
}
};
@@ -378,7 +374,11 @@ TransactionManager.prototype._request = function(tx) {
function transactionRetry(message) {
if (tx.finalized) return;
console.log('TER, submitting fill');
self._fillSequence(tx, function() {
console.log('FILL COMPLETE, resubmitting');
self._resubmit(1, tx);
});
};
@@ -580,27 +580,21 @@ TransactionManager.prototype.submit = function(tx) {
tx.tx_json.Sequence = this._nextSequence++;
}
// Attach secret, associate transaction with a server, attach fee.
// If the transaction can't complete, decrement sequence so that
// subsequent transactions
if (!tx.complete()) {
return;
}
tx.attempts = 0;
// Attach secret, associate transaction with a server, attach fee
tx.complete();
var fee = Number(tx.tx_json.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._maxFee) {
tx.emit('error', new RippleError('tejMaxFeeExceeded', 'Max fee exceeded'));
} else {
// ND: this is the ONLY place we put the tx into the queue. The
// TransactionQueue queue is merely a list, so any mutations to tx._hash
// will cause subsequent look ups (eg. inside 'transaction-outbound'
// validated transaction clearing) to fail.
this._pending.push(tx);
this._request(tx);
}
// ND: this is the ONLY place we put the tx into the queue. The
// TransactionQueue queue is merely a list, so any mutations to tx._hash
// will cause subsequent look ups (eg. inside 'transaction-outbound'
// validated transaction clearing) to fail.
this._pending.push(tx);
this._request(tx);
};
exports.TransactionManager = TransactionManager;

View File

@@ -4,46 +4,17 @@
*/
var Transaction = require('./transaction').Transaction;
var LRU = require('lru-cache');
function TransactionQueue() {
var self = this;
this._queue = [ ];
this._idCache = { };
this._sequenceCache = { };
this._idCache = LRU({ max: 100 });
this._sequenceCache = LRU({ max: 100 });
this._save = void(0);
};
TransactionQueue.prototype.clearCache = function() {
this._idCache = { };
this._sequenceCache = { };
};
TransactionQueue.prototype.getMinLedger = function() {
var minLedger = Infinity;
for (var i=0; i<this._queue.length; i++) {
var submitIndex = this._queue[i].submitIndex;
if (typeof submitIndex !== 'number') {
// If any pending transactions don't have a submit index,
// return -1 for scanning all previous transactions
minLedger = -1;
break;
}
if (submitIndex < minLedger) {
minLedger = submitIndex;
}
};
if (!isFinite(minLedger)) minLedger = -1;
if (minLedger !== -1) minLedger -= 1;
return minLedger;
};
TransactionQueue.prototype.save = function() {
if (typeof this._save !== 'function') return;
@@ -60,7 +31,7 @@ TransactionQueue.prototype.save = function() {
*/
TransactionQueue.prototype.addReceivedSequence = function(sequence) {
this._sequenceCache[sequence] = true;
this._sequenceCache.set(String(sequence), true);
};
/**
@@ -68,7 +39,7 @@ TransactionQueue.prototype.addReceivedSequence = function(sequence) {
*/
TransactionQueue.prototype.addReceivedId = function(id, transaction) {
this._idCache[id] = transaction;
this._idCache.set(id, transaction);
};
/**
@@ -76,7 +47,7 @@ TransactionQueue.prototype.addReceivedId = function(id, transaction) {
*/
TransactionQueue.prototype.getReceived = function(id) {
return this._idCache[id];
return this._idCache.get(id);
};
/**
@@ -85,7 +56,7 @@ TransactionQueue.prototype.getReceived = function(id) {
*/
TransactionQueue.prototype.hasSequence = function(sequence) {
return this._sequenceCache[sequence] || false;
return this._sequenceCache.has(String(sequence));
};
/**
@@ -121,10 +92,6 @@ TransactionQueue.prototype.remove = function(tx) {
}
}
if (!this._queue.length) {
this.clearCache();
}
this.save();
};