mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-06 17:27:59 +00:00
Merge pull request #221 from ripple/transaction-updates
Transaction updates
This commit is contained in:
@@ -111,6 +111,7 @@ function Remote(opts, trace) {
|
||||
this._should_connect = true;
|
||||
|
||||
this._submission_timeout = 1000 * (typeof opts.submission_timeout === 'number' ? opts.submission_timeout : 20);
|
||||
this._last_ledger_offset = (typeof opts.last_ledger_offset === 'number') ? opts.last_ledger_offset : 3;
|
||||
|
||||
this._received_tx = LRU({ max: 100 });
|
||||
this._cur_path_find = null;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,20 @@
|
||||
var LRU = require('lru-cache');
|
||||
var Transaction = require('./transaction').Transaction;
|
||||
|
||||
/**
|
||||
* Manager for pending transactions
|
||||
*/
|
||||
|
||||
var LRU = require('lru-cache');
|
||||
var Transaction = require('./transaction').Transaction;
|
||||
|
||||
function TransactionQueue() {
|
||||
this._queue = [ ];
|
||||
this._idCache = LRU();
|
||||
this._sequenceCache = LRU();
|
||||
this._idCache = LRU({ max: 200 });
|
||||
this._sequenceCache = LRU({ max: 200 });
|
||||
};
|
||||
|
||||
/**
|
||||
* Store received (validated) sequence
|
||||
*
|
||||
* @param {Number} sequence
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.addReceivedSequence = function(sequence) {
|
||||
@@ -23,6 +24,9 @@ TransactionQueue.prototype.addReceivedSequence = function(sequence) {
|
||||
/**
|
||||
* Check that sequence number has been consumed by a validated
|
||||
* transaction
|
||||
*
|
||||
* @param {Number} sequence
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.hasSequence = function(sequence) {
|
||||
@@ -31,6 +35,9 @@ TransactionQueue.prototype.hasSequence = function(sequence) {
|
||||
|
||||
/**
|
||||
* Store received (validated) ID transaction
|
||||
*
|
||||
* @param {String} transaction id
|
||||
* @param {Transaction} transaction
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.addReceivedId = function(id, transaction) {
|
||||
@@ -39,6 +46,9 @@ TransactionQueue.prototype.addReceivedId = function(id, transaction) {
|
||||
|
||||
/**
|
||||
* Get received (validated) transaction by ID
|
||||
*
|
||||
* @param {String} transaction id
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getReceived = function(id) {
|
||||
@@ -48,6 +58,9 @@ TransactionQueue.prototype.getReceived = function(id) {
|
||||
/**
|
||||
* Get a submitted transaction by ID. Transactions
|
||||
* may have multiple associated IDs.
|
||||
*
|
||||
* @param {String} transaction id
|
||||
* @return {Transaction}
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getSubmission = function(id) {
|
||||
@@ -63,8 +76,32 @@ TransactionQueue.prototype.getSubmission = function(id) {
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get earliest ledger in the pending queue
|
||||
*
|
||||
* @return {Number} ledger
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getMinLedger = function() {
|
||||
var result = Infinity;
|
||||
|
||||
for (var i=0, tx; (tx=this._queue[i]); i++) {
|
||||
if (tx.initialSubmitIndex < result) {
|
||||
result = tx.initialSubmitIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFinite(result)) {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a transaction from the queue
|
||||
*
|
||||
* @param {String|Transaction} transaction or id
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.remove = function(tx) {
|
||||
@@ -87,14 +124,30 @@ TransactionQueue.prototype.remove = function(tx) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a transaction to pending queue
|
||||
*
|
||||
* @param {Transaction} transaction
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.push = function(tx) {
|
||||
this._queue.push(tx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterate over pending transactions
|
||||
*
|
||||
* @param {Function} iterator
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.forEach = function(fn) {
|
||||
this._queue.forEach(fn);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Number} length of pending queue
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.length =
|
||||
TransactionQueue.prototype.getLength = function() {
|
||||
return this._queue.length;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
var utils = require('./testutils');
|
||||
var assert = require('assert');
|
||||
var Amount = utils.load_module('amount').Amount;
|
||||
var Transaction = utils.load_module('transaction').Transaction;
|
||||
var Remote = utils.load_module('remote').Remote;
|
||||
var Server = utils.load_module('server').Server;
|
||||
var utils = require('./testutils');
|
||||
var assert = require('assert');
|
||||
var Amount = utils.load_module('amount').Amount;
|
||||
var Transaction = utils.load_module('transaction').Transaction;
|
||||
var TransactionQueue = utils.load_module('transactionqueue').TransactionQueue;
|
||||
var Remote = utils.load_module('remote').Remote;
|
||||
var Server = utils.load_module('server').Server;
|
||||
|
||||
var transactionResult = {
|
||||
engine_result: 'tesSUCCESS',
|
||||
@@ -38,7 +39,7 @@ describe('Transaction', function() {
|
||||
it('Success listener', function(done) {
|
||||
var transaction = new Transaction();
|
||||
|
||||
transaction.once('cleanup', function(message) {
|
||||
transaction.once('final', function(message) {
|
||||
assert.deepEqual(message, transactionResult);
|
||||
assert(transaction.finalized);
|
||||
assert.strictEqual(transaction.state, 'validated');
|
||||
@@ -51,7 +52,7 @@ describe('Transaction', function() {
|
||||
it('Error listener', function(done) {
|
||||
var transaction = new Transaction();
|
||||
|
||||
transaction.once('cleanup', function(message) {
|
||||
transaction.once('final', function(message) {
|
||||
assert.deepEqual(message, transactionResult);
|
||||
assert(transaction.finalized);
|
||||
assert.strictEqual(transaction.state, 'failed');
|
||||
@@ -130,25 +131,29 @@ describe('Transaction', function() {
|
||||
|
||||
it('Set state', function(done) {
|
||||
var transaction = new Transaction();
|
||||
transaction.state = 'pending';
|
||||
|
||||
assert.strictEqual(transaction.state, 'unsubmitted');
|
||||
|
||||
var receivedEvents = 0;
|
||||
var events = 2;
|
||||
var events = [
|
||||
'submitted',
|
||||
'pending',
|
||||
'validated'
|
||||
];
|
||||
|
||||
transaction.once('state', function(state) {
|
||||
assert.strictEqual(state, 'validated');
|
||||
if (++receivedEvents === events) {
|
||||
done();
|
||||
}
|
||||
transaction.on('state', function(state) {
|
||||
receivedEvents++;
|
||||
assert(events.indexOf(state) > -1, 'Invalid state: ' + state);
|
||||
});
|
||||
|
||||
transaction.once('save', function() {
|
||||
if (++receivedEvents === events) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
transaction.setState(events[0]);
|
||||
transaction.setState(events[1]);
|
||||
transaction.setState(events[1]);
|
||||
transaction.setState(events[2]);
|
||||
|
||||
transaction.setState('validated');
|
||||
assert.strictEqual(receivedEvents, 3);
|
||||
assert.strictEqual(transaction.state, events[2]);
|
||||
done();
|
||||
});
|
||||
|
||||
it('Finalize submission', function() {
|
||||
@@ -720,47 +725,20 @@ describe('Transaction', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
it('Sign transaction - with callback', function(done) {
|
||||
var transaction = new Transaction();
|
||||
transaction._secret = 'sh2pTicynUEG46jjR4EoexHcQEoij';
|
||||
transaction.tx_json.SigningPubKey = '021FED5FD081CE5C4356431267D04C6E2167E4112C897D5E10335D4E22B4DA49ED';
|
||||
transaction.tx_json.Account = 'rMWwx3Ma16HnqSd4H6saPisihX9aKpXxHJ';
|
||||
transaction.tx_json.Flags = 0;
|
||||
transaction.tx_json.Fee = 10;
|
||||
transaction.tx_json.Sequence = 1;
|
||||
transaction.tx_json.TransactionType = 'AccountSet';
|
||||
|
||||
transaction.sign(function() {
|
||||
var signature = transaction.tx_json.TxnSignature;
|
||||
assert.strictEqual(transaction.previousSigningHash, 'D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE');
|
||||
assert(/^[A-Z0-9]+$/.test(signature));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Add transaction ID', function(done) {
|
||||
var transaction = new Transaction();
|
||||
var saved = 0;
|
||||
|
||||
transaction.on('save', function() {
|
||||
++saved;
|
||||
});
|
||||
|
||||
transaction.once('save', function() {
|
||||
setImmediate(function() {
|
||||
assert.strictEqual(saved, 2);
|
||||
assert.deepEqual(
|
||||
transaction.submittedIDs,
|
||||
[ 'F1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE',
|
||||
'D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE' ]
|
||||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
transaction.addId('D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE');
|
||||
transaction.addId('F1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE');
|
||||
transaction.addId('F1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE');
|
||||
|
||||
assert.deepEqual(
|
||||
transaction.submittedIDs,
|
||||
[ 'F1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE',
|
||||
'D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE' ]
|
||||
);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('Find transaction IDs in cache', function(done) {
|
||||
@@ -791,9 +769,10 @@ describe('Transaction', function() {
|
||||
|
||||
it('Set DestinationTag', function() {
|
||||
var transaction = new Transaction();
|
||||
transaction.destinationTag();
|
||||
transaction.destinationTag('tag');
|
||||
assert.strictEqual(transaction.tx_json.DestinationTag, 'tag');
|
||||
assert.strictEqual(transaction.tx_json.DestinationTag, void(0));
|
||||
transaction.destinationTag(1);
|
||||
assert.strictEqual(transaction.tx_json.DestinationTag, 1);
|
||||
});
|
||||
|
||||
it('Set InvoiceID', function() {
|
||||
@@ -872,7 +851,7 @@ describe('Transaction', function() {
|
||||
}
|
||||
];
|
||||
|
||||
assert.deepEqual(Transaction._pathRewrite(path), [
|
||||
assert.deepEqual(Transaction._rewritePath(path), [
|
||||
{
|
||||
account: 'rP51ycDJw5ZhgvdKiRjBYZKYjsyoCcHmnY',
|
||||
issuer: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm',
|
||||
@@ -892,7 +871,9 @@ describe('Transaction', function() {
|
||||
});
|
||||
|
||||
it('Rewrite transaction path - invalid path', function() {
|
||||
assert.strictEqual(Transaction._pathRewrite(1), void(0));
|
||||
assert.throws(function() {
|
||||
assert.strictEqual(Transaction._rewritePath(1), void(0));
|
||||
});
|
||||
});
|
||||
|
||||
it('Add transaction path', function() {
|
||||
@@ -1001,51 +982,52 @@ describe('Transaction', function() {
|
||||
it('Set SourceTag', function() {
|
||||
var transaction = new Transaction();
|
||||
transaction.sourceTag('tag');
|
||||
assert.strictEqual(transaction.tx_json.SourceTag, 'tag');
|
||||
assert.strictEqual(transaction.tx_json.SourceTag, void(0));
|
||||
transaction.sourceTag(1);
|
||||
assert.strictEqual(transaction.tx_json.SourceTag, 1);
|
||||
});
|
||||
|
||||
it('Set TransferRate', function() {
|
||||
var transaction = new Transaction();
|
||||
|
||||
assert.throws(function() {
|
||||
transaction.transferRate(1);
|
||||
});
|
||||
|
||||
assert.throws(function() {
|
||||
transaction.transferRate('1');
|
||||
});
|
||||
|
||||
transaction.transferRate(1);
|
||||
assert.strictEqual(transaction.tx_json.TransferRate, void(0));
|
||||
transaction.transferRate(1.5 * 1e9);
|
||||
|
||||
assert.strictEqual(transaction.tx_json.TransferRate, 1.5 * 1e9);
|
||||
});
|
||||
|
||||
it('Set Flags', function(done) {
|
||||
var transaction = new Transaction();
|
||||
transaction.tx_json.TransactionType = 'Payment';
|
||||
|
||||
transaction.setFlags();
|
||||
|
||||
assert.strictEqual(transaction.tx_json.Flags, 0);
|
||||
|
||||
transaction.setFlags(1);
|
||||
var transaction = new Transaction();
|
||||
transaction.tx_json.TransactionType = 'Payment';
|
||||
transaction.setFlags(Transaction.flags.Payment.PartialPayment);
|
||||
assert.strictEqual(transaction.tx_json.Flags, 131072);
|
||||
|
||||
assert.strictEqual(transaction.tx_json.Flags, 1);
|
||||
var transaction = new Transaction();
|
||||
transaction.tx_json.TransactionType = 'Payment';
|
||||
transaction.setFlags('NoRippleDirect');
|
||||
assert.strictEqual(transaction.tx_json.Flags, 65536);
|
||||
|
||||
transaction.setFlags('PartialPayment');
|
||||
|
||||
assert.strictEqual(transaction.tx_json.Flags, 131073);
|
||||
var transaction = new Transaction();
|
||||
transaction.tx_json.TransactionType = 'Payment';
|
||||
transaction.setFlags('PartialPayment', 'NoRippleDirect');
|
||||
assert.strictEqual(transaction.tx_json.Flags, 196608);
|
||||
|
||||
var transaction = new Transaction();
|
||||
transaction.tx_json.TransactionType = 'Payment';
|
||||
transaction.setFlags([ 'LimitQuality', 'PartialPayment' ]);
|
||||
assert.strictEqual(transaction.tx_json.Flags, 393216);
|
||||
|
||||
assert.strictEqual(transaction.tx_json.Flags, 524289);
|
||||
|
||||
var transaction = new Transaction();
|
||||
transaction.tx_json.TransactionType = 'Payment';
|
||||
transaction.once('error', function(err) {
|
||||
assert.strictEqual(err.result, 'tejInvalidFlag');
|
||||
done();
|
||||
});
|
||||
|
||||
transaction.setFlags('test');
|
||||
transaction.setFlags('asdf');
|
||||
});
|
||||
|
||||
it('Add Memo', function() {
|
||||
@@ -1548,16 +1530,10 @@ describe('Transaction', function() {
|
||||
|
||||
it('Submit transaction - invalid account', function(done) {
|
||||
var remote = new Remote();
|
||||
var transaction = new Transaction(remote).accountSet('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
|
||||
|
||||
transaction.tx_json.Account += 'z';
|
||||
|
||||
transaction.once('error', function(err) {
|
||||
assert.strictEqual(err.result, 'tejInvalidAccount');
|
||||
done();
|
||||
assert.throws(function() {
|
||||
var transaction = new Transaction(remote).accountSet('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWeZ');
|
||||
});
|
||||
|
||||
transaction.submit();
|
||||
done();
|
||||
});
|
||||
|
||||
it('Abort submission on presubmit', function(done) {
|
||||
@@ -1589,6 +1565,39 @@ describe('Transaction', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Get min ledger', function() {
|
||||
var queue = new TransactionQueue();
|
||||
|
||||
// Randomized submit indexes
|
||||
[
|
||||
28093,
|
||||
456944,
|
||||
347213,
|
||||
165662,
|
||||
729760,
|
||||
808990,
|
||||
927393,
|
||||
925550,
|
||||
872298,
|
||||
543305
|
||||
]
|
||||
.forEach(function(index){
|
||||
var tx = new Transaction();
|
||||
tx.initialSubmitIndex = index;
|
||||
queue.push(tx);
|
||||
});
|
||||
|
||||
// Pending queue sorted by submit index
|
||||
var sorted = queue._queue.slice().sort(function(a, b) {
|
||||
return a.initialSubmitIndex - b.initialSubmitIndex;
|
||||
});
|
||||
|
||||
sorted.forEach(function(tx){
|
||||
assert.strictEqual(queue.getMinLedger(), tx.initialSubmitIndex);
|
||||
queue.remove(tx);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
//vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
Reference in New Issue
Block a user