Emit tejSecretUnknown if secret is missing during signing, enhancements for ripple-rest

This commit is contained in:
wltsmrz
2014-03-10 16:28:41 -07:00
parent a7581b1ec8
commit 85f75b4543
2 changed files with 81 additions and 58 deletions

View File

@@ -59,49 +59,50 @@ function Transaction(remote) {
var self = this;
this.remote = remote;
this._secret = void(0);
this.remote = remote;
// Transaction data
this.tx_json = { Flags: 0 };
this.tx_json = { Flags: 0 };
this._build_path = false;
// Index at which transaction was submitted
this.submitIndex = void(0);
this.state = 'unsubmitted';
this.finalized = false;
this._secret = void(0);
this._build_path = false;
this.state = 'unsubmitted';
this.finalized = false;
this.previousSigningHash = void(0);
// Index at which transaction was submitted
this.submitIndex = void(0);
// We aren't clever enough to eschew preventative measures so we keep an array
// of all submitted transactionIDs (which can change due to load_factor
// effecting the Fee amount). This should be populated with a transactionID
// any time it goes on the network
this.submittedIDs = [ ]
this.submittedIDs = [ ]
function finalize(message) {
if (!self.finalized) {
self.finalized = true;
if (self.result) {
self.result.ledger_index = message.ledger_index;
self.result.ledger_hash = message.ledger_hash;
} else {
self.result = message;
self.result.tx_json = self.tx_json;
}
self.emit('cleanup', message);
}
};
this.once('success', function(message) {
finalize(message);
self.setState('validated');
finalize(message);
});
this.once('error', function(message) {
self.setState('failed');
finalize(message);
var prefix = message.engine_result.substring(0, 3);
var offlineError = (prefix === 'tej' && message.engine_result !== 'tejLost');
self.setState(offlineError ? 'failed_offline' : 'failed');
});
this.once('submitted', function() {
@@ -260,8 +261,8 @@ 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);
if (!this._secret && !(this._secret = this._account_secret(this.tx_json.Account))) {
return this.emit('error', new RippleError('tejSecretUnknown', 'Missing secret'));
}
if (this.remote && typeof this.tx_json.Fee === 'undefined') {
@@ -383,8 +384,16 @@ Transaction.prototype.invoiceID = function(id) {
return this;
};
Transaction.prototype.clientID = function(id) {
if (typeof id === 'string') {
this._clientID = id;
}
return this;
};
Transaction.prototype.lastLedger = function(sequence) {
if (typeof sequence === 'number') {
this._setLastLedger = true;
this.tx_json.LastLedgerSequence = sequence;
}
return this;
@@ -787,19 +796,27 @@ Transaction.prototype.summary = function() {
};
Transaction.summary = function() {
return {
tx_json: this.tx_json,
sourceID: this.sourceID,
submittedIDs: this.submittedIDs,
submissionAttempts: this.attempts,
state: this.state,
server: this._server ? this._server._opts.url : void(0),
finalized: this.finalized,
result: {
engine_result: this.result ? this.result.engine_result: void(0),
engine_result_message: this.result ? this.result.engine_result_message: void(0),
var result = {
tx_json: this.tx_json,
clientID: this._clientID,
submittedIDs: this.submittedIDs,
submissionAttempts: this.attempts,
state: this.state,
server: this._server ? this._server._opts.url : void(0),
finalized: this.finalized
}
if (this.result) {
result.result = {
engine_result : this.result.engine_result,
engine_result_message: this.result.engine_result_message,
ledger_hash : this.result.ledger_hash,
ledger_index : this.result.ledger_index,
transaction_hash : this.result.tx_json.hash
}
}
return result;
};
exports.Transaction = Transaction;

View File

@@ -189,8 +189,18 @@ TransactionManager.prototype._fillSequence = function(tx, callback) {
function sequenceLoaded(err, sequence) {
if (typeof sequence !== 'number') {
callback(new Error('Failed to fetch account transaction sequence'));
} else {
submitFill(tx.tx_json.Sequence, callback);
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();
}
});
}
};
@@ -256,9 +266,7 @@ TransactionManager.prototype._resubmit = function(ledgers, pending) {
self._loadSequence();
if (++i < pending.length) {
nextTransaction(i);
}
if (++i < pending.length) nextTransaction(i);
});
resubmitTransaction(transaction);
@@ -309,7 +317,12 @@ TransactionManager.prototype._request = function(tx) {
tx.emit('presubmit');
tx.submitIndex = this._remote._ledger_current_index;
tx.tx_json.LastLedgerSequence = tx.submitIndex + 8;
if (!tx._setLastLedger) {
// Honor LastLedgerSequence set by user of API. If
// left unset by API, bump LastLedgerSequence
tx.tx_json.LastLedgerSequence = tx.submitIndex + 8;
}
var submitRequest = remote.requestSubmit();
@@ -343,19 +356,19 @@ TransactionManager.prototype._request = function(tx) {
};
function transactionFailed(message) {
self._fillSequence(tx, function() {
switch (message.engine_result) {
case 'tefPAST_SEQ':
self._resubmit(1, tx);
break;
default:
tx.emit('error', message);
}
});
switch (message.engine_result) {
case 'tefPAST_SEQ':
self._resubmit(1, tx);
break;
default:
tx.emit('error', message);
}
};
function transactionRetry(message) {
self._resubmit(1, tx);
self._fillSequence(tx, function() {
self._resubmit(1, tx);
});
};
function transactionFeeClaimed(message) {
@@ -455,7 +468,6 @@ TransactionManager.prototype._request = function(tx) {
submitRequest.timeout(self._submissionTimeout, requestTimeout);
submitRequest.request();
tx.attempts++;
tx.emit('save', tx.summary());
tx.emit('postsubmit');
};
@@ -493,6 +505,7 @@ TransactionManager._isTooBusy = function(error) {
TransactionManager.prototype.submit = function(tx) {
var self = this;
var remote = this._remote;
// If sequence number is not yet known, defer until it is.
if (typeof this._nextSequence === 'undefined') {
@@ -506,15 +519,10 @@ TransactionManager.prototype.submit = function(tx) {
// Finalized (e.g. aborted) transactions must stop all activity
if (tx.finalized) return;
if (typeof tx.tx_json.Sequence !== 'number') {
tx.tx_json.Sequence = this._nextSequence++;
}
function cleanup(message) {
// ND: We can just remove this `tx` by identity
self._pending.remove(tx);
tx.emit('final', message);
tx.emit('save');
remote._trace('transactionmanager: finalize_transaction:', tx.tx_json);
};
@@ -536,8 +544,8 @@ TransactionManager.prototype.submit = function(tx) {
tx.emit('error', new RippleError('tejAbort', 'Transaction aborted'));
});
if (typeof tx.clientID === 'string') {
tx.sourceID = [ this._accountID, tx.clientID ].join(':');
if (typeof tx.tx_json.Sequence !== 'number') {
tx.tx_json.Sequence = this._nextSequence++;
}
tx.attempts = 0;
@@ -546,7 +554,6 @@ TransactionManager.prototype.submit = function(tx) {
tx.complete();
var fee = Number(tx.tx_json.Fee);
var remote = this._remote;
if (!tx._secret && !tx.tx_json.TxnSignature) {
tx.emit('error', new RippleError('tejSecretUnknown', 'Missing secret'));
@@ -561,7 +568,6 @@ TransactionManager.prototype.submit = function(tx) {
// validated transaction clearing) to fail.
this._pending.push(tx);
this._request(tx);
tx.emit('save');
}
};