diff --git a/src/autobridgecalculator.js b/src/autobridgecalculator.js index 9448e925..7037430f 100644 --- a/src/autobridgecalculator.js +++ b/src/autobridgecalculator.js @@ -2,7 +2,6 @@ const _ = require('lodash'); const assert = require('assert'); -const UInt160 = require('./uint160').UInt160; const Amount = require('./amount').Amount; const Utils = require('./orderbookutils'); @@ -38,15 +37,39 @@ AutobridgeCalculator.NULL_AMOUNT = Utils.normalizeAmount('0'); * @return {Array} */ -AutobridgeCalculator.prototype.calculate = function() { - let legOnePointer = 0; - let legTwoPointer = 0; +AutobridgeCalculator.prototype.calculate = function(callback) { + const legOnePointer = 0; + const legTwoPointer = 0; const offersAutobridged = []; this.clearOwnerFundsLeftover(); + this._calculateInternal(legOnePointer, legTwoPointer, offersAutobridged, + callback); +}; + +AutobridgeCalculator.prototype._calculateInternal = function( + legOnePointer_, legTwoPointer_, offersAutobridged, callback +) { + + let legOnePointer = legOnePointer_; + let legTwoPointer = legTwoPointer_; + + const startTime = Date.now(); + while (this.legOneOffers[legOnePointer] && this.legTwoOffers[legTwoPointer]) { + // manually implement cooperative multitasking that yields after 30ms + // of execution so user's browser stays responsive + const lasted = (Date.now() - startTime); + if (lasted > 30) { + setTimeout(() => { + this._calculateInternal(legOnePointer, legTwoPointer, offersAutobridged, + callback); + }, 0); + return; + } + const legOneOffer = this.legOneOffers[legOnePointer]; const legTwoOffer = this.legTwoOffers[legTwoPointer]; const leftoverFunds = this.getLeftoverOwnerFunds(legOneOffer.Account); @@ -103,7 +126,7 @@ AutobridgeCalculator.prototype.calculate = function() { offersAutobridged.push(autobridgedOffer); } - return offersAutobridged; + callback(offersAutobridged); }; /** @@ -308,7 +331,8 @@ function(takerGets, takerPays) { autobridgedOffer.autobridged = true; - autobridgedOffer.BookDirectory = Utils.convertOfferQualityToHexFromText(autobridgedOffer.quality); + autobridgedOffer.BookDirectory = + Utils.convertOfferQualityToHexFromText(autobridgedOffer.quality); autobridgedOffer.qualityHex = autobridgedOffer.BookDirectory; return autobridgedOffer; @@ -432,7 +456,7 @@ function(legOneOffer, takerGets) { const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets); legOneOffer.TakerGets = takerGets.to_text(); - legOneOffer.TakerPays = takerGets.multiply(legOneQuality); + legOneOffer.TakerPays = takerGets.multiply(legOneQuality).to_json(); }; module.exports = AutobridgeCalculator; diff --git a/src/orderbook.js b/src/orderbook.js index 5fde78c5..cfa966ee 100644 --- a/src/orderbook.js +++ b/src/orderbook.js @@ -74,29 +74,30 @@ function OrderBook(remote, this._gotOffersFromLegOne = false; this._gotOffersFromLegTwo = false; + this._waitingForOffers = false; + this._offersModifiedAt = 0; + this._transactionsLeft = 0; + this._calculatorRunning = false; + + this.sortOffers = this._currencyGets.has_interest() ? _sortOffers.bind(this) : _sortOffersQuick; - this.notifyDirectOffersChanged = - _.debounce( - this.notifyDirectOffersChangedInternal, - OrderBook.NOTIFY_TIMEOUT, - {maxWait: OrderBook.NOTIFY_MAXWAIT}); - this._isAutobridgeable = !this._currencyGets.is_native() && !this._currencyPays.is_native(); - this._autobridgeThrottleTimeMultiplier = 1; - this.createDebouncedOffersWrapper(); - function computeAutobridgedOffersWrapperOne() { - self._gotOffersFromLegOne = true; - self.computeAutobridgedOffersThrottled(); + if (!self._gotOffersFromLegOne) { + self._gotOffersFromLegOne = true; + self.computeAutobridgedOffersWrapper(); + } } function computeAutobridgedOffersWrapperTwo() { - self._gotOffersFromLegTwo = true; - self.computeAutobridgedOffersThrottled(); + if (!self._gotOffersFromLegTwo) { + self._gotOffersFromLegTwo = true; + self.computeAutobridgedOffersWrapper(); + } } function onDisconnect() { @@ -125,8 +126,12 @@ function OrderBook(remote, }); } - function updateFundedAmountsWrapper(transaction) { - self.updateFundedAmounts(transaction); + function onTransactionWrapper(transaction) { + self.onTransaction(transaction); + } + + function onLedgerClosedWrapper(message) { + self.onLedgerClosed(message); } function listenersModified(action, event) { @@ -139,7 +144,8 @@ function OrderBook(remote, self._shouldSubscribe = true; self.subscribe(); - self._remote.on('transaction', updateFundedAmountsWrapper); + self._remote.on('transaction', onTransactionWrapper); + self._remote.on('ledger_closed', onLedgerClosedWrapper); self._remote.once('disconnect', onDisconnect); if (self._isAutobridgeable) { @@ -168,7 +174,8 @@ function OrderBook(remote, this.on('unsubscribe', function() { self.resetCache(); - self._remote.removeListener('transaction', updateFundedAmountsWrapper); + self._remote.removeListener('transaction', onTransactionWrapper); + self._remote.removeListener('ledger_closed', onLedgerClosedWrapper); self._remote.removeListener('disconnect', onDisconnect); self._gotOffersFromLegOne = false; @@ -199,16 +206,6 @@ OrderBook.EVENTS = [ OrderBook.DEFAULT_TRANSFER_RATE = Amount.from_json(1000000000); -OrderBook.NOTIFY_TIMEOUT = 100; - -OrderBook.NOTIFY_MAXWAIT = 250; - -OrderBook.AUTOBRIDGE_CALCULATE_THROTTLE_TIME = 1000; - -OrderBook.AUTOBRIDGE_CALCULATE_DEBOUNCE_TIME = 250; - -OrderBook.AUTOBRIDGE_CALCULATE_DEBOUNCE_MAXWAIT = 500; - OrderBook.ZERO_NATIVE_AMOUNT = Amount.from_json('0'); OrderBook.ZERO_NORMALIZED_AMOUNT = OrderBookUtils.normalizeAmount('0'); @@ -345,6 +342,8 @@ OrderBook.prototype.requestOffers = function(callback = function() {}, log.info('requesting offers', this._key); } + this._synchronized = false; + if (this._isAutobridgeable && !internal) { this._gotOffersFromLegOne = false; this._gotOffersFromLegTwo = false; @@ -359,9 +358,12 @@ OrderBook.prototype.requestOffers = function(callback = function() {}, return; } + self._waitingForOffers = false; + if (!Array.isArray(res.offers)) { // XXX What now? callback(new Error('Invalid response')); + self.emit('model', []); return; } @@ -370,7 +372,12 @@ OrderBook.prototype.requestOffers = function(callback = function() {}, } self.setOffers(res.offers); self._synchronized = true; - self.notifyDirectOffersChanged(); + + if (self._isAutobridgeable) { + self.computeAutobridgedOffersWrapper(); + } else { + self.emit('model', self._offers); + } callback(null, self._offers); } @@ -381,9 +388,12 @@ OrderBook.prototype.requestOffers = function(callback = function() {}, log.info('failed to request offers', self._key, err); } + self._waitingForOffers = false; callback(err); } + this._waitingForOffers = true; + const request = this._remote.requestBookOffers(this.toJSON()); request.once('success', handleOffers); request.once('error', handleError); @@ -479,18 +489,6 @@ OrderBook.prototype.subscribeTransactions = function(callback) { return request; }; -/** - * Handles notifying listeners that direct offers have changed. For autobridged - * books, an additional merge step is also performed - */ - -OrderBook.prototype.notifyDirectOffersChangedInternal = function() { - if (this._isAutobridgeable) { - this.mergeDirectAndAutobridgedBooks(); - } else { - this.emit('model', this._offers); - } -}; /** * Reset cached owner's funds, offer counts, and offer sums @@ -828,6 +826,32 @@ OrderBook.prototype.isBalanceChangeNode = function(node) { return true; }; +OrderBook.prototype._canRunAutobridgeCalc = function(): boolean { + return !this._calculatorRunning; +} + +OrderBook.prototype.onTransaction = function(transaction) { + this.updateFundedAmounts(transaction); + + + if (--this._transactionsLeft === 0 && !this._waitingForOffers) { + const lastClosedLedger = this._remote.getLedgerSequence() - 1; + if (this._isAutobridgeable) { + if (this._canRunAutobridgeCalc()) { + if (this._legOneBook._offersModifiedAt === lastClosedLedger || + this._legTwoBook._offersModifiedAt === lastClosedLedger + ) { + this.computeAutobridgedOffersWrapper(); + } else if (this._offersModifiedAt === lastClosedLedger) { + this.mergeDirectAndAutobridgedBooks(); + } + } + } else if (this._offersModifiedAt === lastClosedLedger) { + this.emit('model', this._offers); + } + } +} + /** * Updates funded amounts/balances using modified balance nodes * @@ -929,6 +953,16 @@ OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) { }); }; + +OrderBook.prototype.onLedgerClosed = function(message) { + if (!message || (message && !_.isNumber(message.txn_count)) || + !this._subscribed || this._destroyed || this._waitingForOffers + ) { + return; + } + this._transactionsLeft = message.txn_count; +} + /** * Notify orderbook of a relevant transaction * @@ -1029,7 +1063,7 @@ OrderBook.prototype.notify = function(transaction) { this.emit('transaction', transaction); - this.notifyDirectOffersChanged(); + this._offersModifiedAt = this._remote.getLedgerSequence() - 1; if (!takerGetsTotal.is_zero()) { this.emit('trade', takerPaysTotal, takerGetsTotal); @@ -1312,18 +1346,16 @@ OrderBook.prototype.is_valid = function() { * IOU:XRP and XRP:IOU books */ -OrderBook.prototype.computeAutobridgedOffers = function() { +OrderBook.prototype.computeAutobridgedOffers = function(callback = function() {} +) { assert(!this._currencyGets.is_native() && !this._currencyPays.is_native(), 'Autobridging is only for IOU:IOU orderbooks'); + if (this._destroyed) { return; } - if (!this._gotOffersFromLegOne || !this._gotOffersFromLegTwo) { - return; - } - const autobridgeCalculator = new AutobridgeCalculator( this._currencyGets, this._currencyPays, @@ -1333,35 +1365,28 @@ OrderBook.prototype.computeAutobridgedOffers = function() { this._issuerPays ); - this._offersAutobridged = autobridgeCalculator.calculate(); + const lastClosedLedger = this._remote.getLedgerSequence() - 1; + + autobridgeCalculator.calculate((autobridgedOffers) => { + this._offersAutobridged = autobridgedOffers; + callback(); + }); }; OrderBook.prototype.computeAutobridgedOffersWrapper = function() { - var startTime = Date.now(); - this.computeAutobridgedOffers(); - this.mergeDirectAndAutobridgedBooks(); - var lasted = (Date.now() - startTime); - - const newMult = - ((lasted * 2 / OrderBook.AUTOBRIDGE_CALCULATE_THROTTLE_TIME) << 0) + 1; - if (newMult !== this._autobridgeThrottleTimeMultiplier) { - this._autobridgeThrottleTimeMultiplier = newMult; - this.createDebouncedOffersWrapper(); + if (!this._gotOffersFromLegOne || !this._gotOffersFromLegTwo || + !this._synchronized || this._destroyed || this._calculatorRunning + ) { + return; } -} - -OrderBook.prototype.createDebouncedOffersWrapper = function() { - const m = this._autobridgeThrottleTimeMultiplier; - this.computeAutobridgedOffersThrottled = - _.debounce( - _.throttle( - this.computeAutobridgedOffersWrapper, - OrderBook.AUTOBRIDGE_CALCULATE_THROTTLE_TIME * m, - {leading: true, trailing: true}), - OrderBook.AUTOBRIDGE_CALCULATE_DEBOUNCE_TIME, - {maxWait: OrderBook.AUTOBRIDGE_CALCULATE_DEBOUNCE_MAXWAIT}); -} + this._calculatorRunning = true; + const startTime = Date.now(); + this.computeAutobridgedOffers(() => { + this.mergeDirectAndAutobridgedBooks(); + this._calculatorRunning = false; + }); +}; function _sortOffers(a, b) { const aQuality = OrderBookUtils.getOfferQuality(a, this._currencyGets); diff --git a/test/orderbook-autobridge-test.js b/test/orderbook-autobridge-test.js index c30ea7e3..9e3f12ef 100644 --- a/test/orderbook-autobridge-test.js +++ b/test/orderbook-autobridge-test.js @@ -16,6 +16,7 @@ describe('OrderBook Autobridging', function() { function createRemote() { const remote = new Remote(); + remote._ledger_current_index = 32570; remote.isConnected = function() { return true; }; @@ -37,7 +38,7 @@ describe('OrderBook Autobridging', function() { assert.deepEqual(book._legTwoBook._currencyPays.to_hex(), Currency.from_json('XRP').to_hex()); }); - it('Compute autobridged offers', function() { + it('Compute autobridged offers', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -56,20 +57,23 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 1); - assert.strictEqual(book._offersAutobridged.length, 1); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); + assert.strictEqual(book._offersAutobridged[0].taker_gets_funded, '17.07639524223001'); + assert.strictEqual(book._offersAutobridged[0].taker_pays_funded, '58.61727326122974'); - assert.strictEqual(book._offersAutobridged[0].taker_gets_funded, '17.07639524223001'); - assert.strictEqual(book._offersAutobridged[0].taker_pays_funded, '58.61727326122974'); + assert(book._offersAutobridged[0].autobridged); + + done(); + }); - assert(book._offersAutobridged[0].autobridged); }); - it('Compute autobridged offers - leg one partially funded', function() { + it('Compute autobridged offers - leg one partially funded', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -90,17 +94,20 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 1); - assert.strictEqual(book._offersAutobridged.length, 1); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '7.273651248813431'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '24.96789265329184'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '7.273651248813431'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '24.96789265329184'); + assert(book._offersAutobridged[0].autobridged); + + done(); + }); - assert(book._offersAutobridged[0].autobridged); }); - it('Compute autobridged offers - leg two partially funded', function() { + it('Compute autobridged offers - leg two partially funded', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -121,17 +128,20 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 1); - assert.strictEqual(book._offersAutobridged.length, 1); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '10'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '34.32649132449533'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '10'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '34.32649132449533'); + assert(book._offersAutobridged[0].autobridged); + + done(); + }); - assert(book._offersAutobridged[0].autobridged); }); - it('Compute autobridged offers - leg two transfer rate', function() { + it('Compute autobridged offers - leg two transfer rate', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -152,15 +162,18 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '9.980039920159681'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '34.25797537722665'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '9.980039920159681'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '34.25797537722665'); + assert(book._offersAutobridged[0].autobridged); + + done(); + }); - assert(book._offersAutobridged[0].autobridged); }); - it('Compute autobridged offers - taker funds < leg two in', function() { + it('Compute autobridged offers - taker funds < leg two in', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -185,17 +198,20 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 1); - assert.strictEqual(book._offersAutobridged.length, 1); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '108.6682345172846'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '373.019921005'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '108.6682345172846'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '373.019921005'); + assert(book._offersAutobridged[0].autobridged); + + done(); + }); - assert(book._offersAutobridged[0].autobridged); }); - it('Compute autobridged offers - leg one partially funded - owners equal', function() { + it('Compute autobridged offers - leg one partially funded - owners equal', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -218,17 +234,20 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 1); - assert.strictEqual(book._offersAutobridged.length, 1); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); + assert(book._offersAutobridged[0].autobridged); + + done(); + }); - assert(book._offersAutobridged[0].autobridged); }); - it('Compute autobridged offers - leg one partially funded - owners equal - leg two in > leg one out', function() { + it('Compute autobridged offers - leg one partially funded - owners equal - leg two in > leg one out', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -254,17 +273,20 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 1); - assert.strictEqual(book._offersAutobridged.length, 1); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '108.6682345172846'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '373.0199210049999'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '108.6682345172846'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '373.0199210049999'); + assert(book._offersAutobridged[0].autobridged); + + done(); + }); - assert(book._offersAutobridged[0].autobridged); }); - it('Compute autobridged offers - leg one consumes leg two fully', function() { + it('Compute autobridged offers - leg one consumes leg two fully', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -283,22 +305,25 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 2); - assert.strictEqual(book._offersAutobridged.length, 2); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); + assert(book._offersAutobridged[0].autobridged); - assert(book._offersAutobridged[0].autobridged); + assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5.038346688725268'); + assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '314.4026477437702'); - assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5.038346688725268'); - assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '314.4026477437702'); + assert(book._offersAutobridged[1].autobridged); + + done(); + }); - assert(book._offersAutobridged[1].autobridged); }); - it('Compute autobridged offers - leg two consumes first leg one offer fully', function() { + it('Compute autobridged offers - leg two consumes first leg one offer fully', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -321,22 +346,25 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 2); - assert.strictEqual(book._offersAutobridged.length, 2); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '108.6682345172846'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '373.019921005'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '108.6682345172846'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '373.019921005'); + assert(book._offersAutobridged[0].autobridged); - assert(book._offersAutobridged[0].autobridged); + assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '62.0957179050155'); + assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '213.1791399943838'); - assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '62.0957179050155'); - assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '213.1791399943838'); + assert(book._offersAutobridged[1].autobridged); + + done(); + }); - assert(book._offersAutobridged[1].autobridged); }); - it('Compute autobridged offers - owners equal', function() { + it('Compute autobridged offers - owners equal', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -360,22 +388,25 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 2); - assert.strictEqual(book._offersAutobridged.length, 2); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); + assert(book._offersAutobridged[0].autobridged); - assert(book._offersAutobridged[0].autobridged); + assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '0.4001139945128008'); + assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '24.96789265329184'); - assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '0.4001139945128008'); - assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '24.96789265329184'); + assert(book._offersAutobridged[1].autobridged); + + done(); + }); - assert(book._offersAutobridged[1].autobridged); }); - it('Compute autobridged offers - owners equal - leg one overfunded', function() { + it('Compute autobridged offers - owners equal - leg one overfunded', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -400,22 +431,25 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers(legTwoOffers); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 2); - assert.strictEqual(book._offersAutobridged.length, 2); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974'); + assert(book._offersAutobridged[0].autobridged); - assert(book._offersAutobridged[0].autobridged); + assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5.038346688725268'); + assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '314.4026477437702'); - assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5.038346688725268'); - assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '314.4026477437702'); + assert(book._offersAutobridged[1].autobridged); + + done(); + }); - assert(book._offersAutobridged[1].autobridged); }); - it('Compute autobridged offers - TakerPays < Quality * TakerGets', function() { + it('Compute autobridged offers - TakerPays < Quality * TakerGets', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -458,17 +492,20 @@ describe('OrderBook Autobridging', function() { ]); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 1); - assert.strictEqual(book._offersAutobridged.length, 1); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '75'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '75'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '75'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '75'); + assert(book._offersAutobridged[0].autobridged); + + done(); + }); - assert(book._offersAutobridged[0].autobridged); }); - it('Compute autobridged offers - update funded amount', function() { + it('Compute autobridged offers - update funded amount', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -534,27 +571,30 @@ describe('OrderBook Autobridging', function() { ]); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 3); - assert.strictEqual(book._offersAutobridged.length, 3); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '90'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '90'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '90'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '90'); + assert(book._offersAutobridged[0].autobridged); - assert(book._offersAutobridged[0].autobridged); + assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5'); + assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '10'); - assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5'); - assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '10'); + assert(book._offersAutobridged[1].autobridged); - assert(book._offersAutobridged[1].autobridged); + assert.strictEqual(book._offersAutobridged[2].TakerGets.value, '20'); + assert.strictEqual(book._offersAutobridged[2].TakerPays.value, '80'); - assert.strictEqual(book._offersAutobridged[2].TakerGets.value, '20'); - assert.strictEqual(book._offersAutobridged[2].TakerPays.value, '80'); + assert(book._offersAutobridged[2].autobridged); + + done(); + }); - assert(book._offersAutobridged[2].autobridged); }); - it('Compute autobridged offers - update funded amount - owners equal', function() { + it('Compute autobridged offers - update funded amount - owners equal', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -620,27 +660,30 @@ describe('OrderBook Autobridging', function() { ]); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 3); - assert.strictEqual(book._offersAutobridged.length, 3); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '90'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '90'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '90'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '90'); + assert(book._offersAutobridged[0].autobridged); - assert(book._offersAutobridged[0].autobridged); + assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5'); + assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '10'); - assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5'); - assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '10'); + assert(book._offersAutobridged[1].autobridged); - assert(book._offersAutobridged[1].autobridged); + assert.strictEqual(book._offersAutobridged[2].TakerGets.value, '10'); + assert.strictEqual(book._offersAutobridged[2].TakerPays.value, '100'); - assert.strictEqual(book._offersAutobridged[2].TakerGets.value, '10'); - assert.strictEqual(book._offersAutobridged[2].TakerPays.value, '100'); + assert(book._offersAutobridged[2].autobridged); + + done(); + }); - assert(book._offersAutobridged[2].autobridged); }); - it('Compute autobridged offers - update funded amount - first two owners equal', function() { + it('Compute autobridged offers - update funded amount - first two owners equal', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -717,32 +760,35 @@ describe('OrderBook Autobridging', function() { ]); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 4); - assert.strictEqual(book._offersAutobridged.length, 4); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '90'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '90'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '90'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '90'); + assert(book._offersAutobridged[0].autobridged); - assert(book._offersAutobridged[0].autobridged); + assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5'); + assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '10'); - assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5'); - assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '10'); + assert(book._offersAutobridged[1].autobridged); - assert(book._offersAutobridged[1].autobridged); + assert.strictEqual(book._offersAutobridged[2].TakerGets.value, '25'); + assert.strictEqual(book._offersAutobridged[2].TakerPays.value, '100'); - assert.strictEqual(book._offersAutobridged[2].TakerGets.value, '25'); - assert.strictEqual(book._offersAutobridged[2].TakerPays.value, '100'); + assert(book._offersAutobridged[2].autobridged); - assert(book._offersAutobridged[2].autobridged); + assert.strictEqual(book._offersAutobridged[3].TakerGets.value, '20'); + assert.strictEqual(book._offersAutobridged[3].TakerPays.value, '80'); - assert.strictEqual(book._offersAutobridged[3].TakerGets.value, '20'); - assert.strictEqual(book._offersAutobridged[3].TakerPays.value, '80'); + assert(book._offersAutobridged[3].autobridged); + + done(); + }); - assert(book._offersAutobridged[3].autobridged); }); - it('Compute autobridged offers - unfunded offer - owners equal', function() { + it('Compute autobridged offers - unfunded offer - owners equal', function(done) { const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, @@ -785,13 +831,16 @@ describe('OrderBook Autobridging', function() { ]); book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; - book.computeAutobridgedOffers(); + book.computeAutobridgedOffers(() => { + assert.strictEqual(book._offersAutobridged.length, 1); - assert.strictEqual(book._offersAutobridged.length, 1); + assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '75'); + assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '75'); - assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '75'); - assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '75'); + assert(book._offersAutobridged[0].autobridged); + + done(); + }); - assert(book._offersAutobridged[0].autobridged); }); }); diff --git a/test/orderbook-test.js b/test/orderbook-test.js index 14fc50fb..5a375fa8 100644 --- a/test/orderbook-test.js +++ b/test/orderbook-test.js @@ -15,7 +15,7 @@ describe('OrderBook', function() { function createRemote() { const remote = new Remote(); - + remote._ledger_current_index = 32570; remote.isConnected = function() { return true; }; @@ -1613,9 +1613,15 @@ describe('OrderBook', function() { const offer2 = fixtures.transactionWithCreatedOffer(); const offer3 = fixtures.transactionWithCreatedOffer(); + remote.emit('ledger_closed', {txn_count: 3}); + book.notify(offer); + remote.emit('transaction', offer); book.notify(offer2); + remote.emit('transaction', offer2); book.notify(offer3); + remote.emit('transaction', offer3); + assert.strictEqual(numTransactionEvents, 3); assert.strictEqual(numOfferAddedEvents, 3); @@ -1706,7 +1712,10 @@ describe('OrderBook', function() { const message = fixtures.transactionWithDeletedOffer(); + remote.emit('ledger_closed', {txn_count: 1}); + book.notify(message); + remote.emit('transaction', message); assert.strictEqual(numTransactionEvents, 1); assert.strictEqual(numTradeEvents, 1); @@ -1865,7 +1874,10 @@ describe('OrderBook', function() { const message = fixtures.transactionWithModifiedOffer(); + remote.emit('ledger_closed', {txn_count: 1}); + book.notify(message); + remote.emit('transaction', message); assert.strictEqual(numTransactionEvents, 1); assert.strictEqual(numTradeEvents, 1); diff --git a/test/remote-test.js b/test/remote-test.js index 6fdcb9bb..327d64f8 100644 --- a/test/remote-test.js +++ b/test/remote-test.js @@ -671,6 +671,7 @@ describe('Remote', function() { function() { const message = require('./fixtures/transaction-offercreate'); let i = 0; + remote._ledger_current_index = 32570; const orderbook = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: 'rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR',