Compare commits

...

25 Commits

Author SHA1 Message Date
Alan Cohen
a11abcc016 Bump version to 0.13.0-rc11.1 2015-10-15 18:22:20 -07:00
Alan Cohen
dd693fdc5f Add proxy support to schema 2015-10-15 18:14:22 -07:00
Geert Weening
e2c853e40d Bump version to 0.13.0-rc11 2015-09-25 17:05:22 -07:00
Geert Weening
b9b5a71869 Update release notes 2015-09-25 17:01:58 -07:00
Geert Weening
87fdbc932f Merge pull request #567 from clark800/fix-crash
Fix crash due to rippled slowDown error
2015-09-25 16:59:42 -07:00
Chris Clark
84838b2e9f Fix crash due to rippled slowDown error 2015-09-25 16:41:37 -07:00
Chris Clark
88a3f3d43b Merge pull request #565 from clark800/value
Use ripple-lib-value package and update ripple-lib-transactionparser dependency
2015-09-25 12:39:03 -07:00
Chris Clark
5f8dcd71a5 Merge pull request #564 from darkdarkdragon/develop-master-merge-2
Merge branch 'master' into develop
2015-09-24 13:58:11 -07:00
Ivan Tivonenko
45db95da79 put back UInt160 in AutobridgeCalculator
fix lint issues
2015-09-24 23:49:32 +03:00
Chris Clark
c79b12b27f Use ripple-lib-value package and update ripple-lib-transactionparser dependency 2015-09-24 12:32:15 -07:00
Chris Clark
135da6108d Merge pull request #563 from clark800/keypairs
Move to new ripple-keypairs API
2015-09-24 11:53:20 -07:00
Ivan Tivonenko
0d6dda579f Merge branch 'master' into develop 2015-09-24 20:04:18 +03:00
Chris Clark
e641a347db Merge pull request #561 from darkdarkdragon/master-performance-2
more OrderBook performance optimizations
2015-09-23 17:14:44 -07:00
Ivan Tivonenko
3e17d91edf more OrderBook performance optimizations
OrderBook: emit 'model' event only after last transaction in closed ledger
run AutobridgeCalculator only once in a ledger
2015-09-24 02:50:48 +03:00
Chris Clark
715c648d52 Move to new ripple-keypairs API 2015-09-23 14:30:56 -07:00
Geert Weening
d0ebed9822 bump version to 0.12.8 2015-09-23 11:51:42 -07:00
Geert Weening
a3775f18ba update release notes 2015-09-23 11:51:29 -07:00
wltsmrz
7b5d6e9fc5 Merge pull request #562 from wltsmrz/add-reconnect-test
Add test for Server automatic reconnection
2015-09-22 21:52:11 -07:00
wltsmrz
368ac0b9e0 Merge pull request #560 from wltsmrz/fix-connect-when-already-connected
Always call Remote.connect() callback
2015-09-22 21:51:30 -07:00
wltsmrz
0448696bd8 Merge pull request #552 from wltsmrz/update-multisigning
Autofill LastLedgerSequence for multisigned transactions
2015-09-22 21:50:53 -07:00
wltsmrz
deb75ed0d7 Add test for Server automatic reconnection 2015-09-22 19:48:25 -07:00
wltsmrz
1c023c4377 Always call Remote.connect() callback
Fixes non-resolving Promise in RippleAPI.connect()
2015-09-22 18:22:28 -07:00
wltsmrz
de67570230 Autofill LastLedgerSequence for multisigned transactions 2015-09-21 10:26:00 -07:00
Geert Weening
f282585c3f Bump version to 0.12.7
bump dependencies and regenerate shrinkwrap
2015-09-17 10:30:23 -07:00
Geert Weening
ae5ff31c96 Update release notes 2015-09-17 10:20:52 -07:00
37 changed files with 671 additions and 887 deletions

View File

@@ -1,5 +1,6 @@
##0.13.0 (release candidate)
+ [Fix crash due to rippled slowDown error](https://github.com/ripple/ripple-lib/commit/84838b2e9f6969b593b8462a62a6b8f516ada937)
+ [Fix: Emit error events and return error on pathfind](https://github.com/ripple/ripple-lib/commit/1ccbaf677631a1944eb05d90f7afc5f3690a03dd)
+ [Deprecate core and remove snake case method copying](https://github.com/ripple/ripple-lib/commit/fb8dc44ec1d49bb05cd0cdbe6dd4ab211195868a)
+ Add new RippleAPI interface
@@ -9,6 +10,14 @@
+ [Fix bug where the paths would be set with an empty array](https://github.com/ripple/ripple-lib/commit/83874ec0962da311b76f2385623e51c68bc39035)
+ [Fix reserve calculation](https://github.com/ripple/ripple-lib/commit/52879febb92d876f01f2e4d70871baa07af631fb)
##0.12.7 and 0.12.8
+ [Improve performance of orderbook](https://github.com/ripple/ripple-lib/commit/c745faaaf0956ca98448a754b4fe97fb50574fc7)
+ [Remove Firefox warning about prototype overwrite](https://github.com/ripple/ripple-lib/commit/0c62fa21123b220b066871e1c41a3b4fe6f51885)
+ [Fix compare bug in Amount class](https://github.com/ripple/ripple-lib/commit/806547dd154e1b0bf252e8a74ad3ac6aa8a97660)
##0.12.6
+ [Fix webpack require failure due to "./" notation](https://github.com/ripple/ripple-lib/commit/8d9746d7b10be203ee613df523c2522012ff1baf)

24
npm-shrinkwrap.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "ripple-lib",
"version": "0.13.0-rc10",
"version": "0.13.0-rc11.1",
"npm-shrinkwrap-version": "5.4.0",
"node-version": "v0.12.7",
"dependencies": {
@@ -9,8 +9,8 @@
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
},
"babel-runtime": {
"version": "5.8.24",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.24.tgz",
"version": "5.8.25",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.25.tgz",
"dependencies": {
"core-js": {
"version": "1.1.4",
@@ -133,8 +133,8 @@
}
},
"ripple-keypairs": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-0.8.0.tgz",
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-0.9.0.tgz",
"dependencies": {
"brorand": {
"version": "1.0.5",
@@ -153,14 +153,12 @@
}
},
"ripple-lib-transactionparser": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.5.0.tgz",
"dependencies": {
"bignumber.js": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-1.4.1.tgz"
}
}
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.5.1.tgz"
},
"ripple-lib-value": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/ripple-lib-value/-/ripple-lib-value-0.1.0.tgz"
},
"sjcl-codec": {
"version": "0.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "ripple-lib",
"version": "0.13.0-rc10",
"version": "0.13.0-rc11.1",
"license": "ISC",
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
"files": [
@@ -27,8 +27,9 @@
"lodash": "^3.1.0",
"lru-cache": "~2.5.0",
"ripple-address-codec": "^1.6.0",
"ripple-keypairs": "^0.8.0",
"ripple-lib-transactionparser": "^0.5.0",
"ripple-keypairs": "^0.9.0",
"ripple-lib-transactionparser": "^0.5.1",
"ripple-lib-value": "0.1.0",
"sjcl-codec": "0.1.0",
"ws": "~0.7.1"
},

View File

@@ -9,6 +9,7 @@
},
"quantity": {"$ref": "balance"},
"totalPrice": {"$ref": "balance"},
"makerExchangeRate": {"$ref": "value"},
"sequence": {"$ref": "sequence"},
"status": {"enum": ["created", "open", "closed", "canceled"]}
},

View File

@@ -11,6 +11,9 @@
"format": "uri",
"pattern": "^wss?://"
}
},
"proxy": {
"format": "uri"
}
},
"additionalProperties": false

View File

@@ -29,8 +29,10 @@ function toRippledAmount(amount: Amount): string|Amount {
}
function generateAddress(options?: Object): Object {
const {accountID, seed} = keypairs.generateWallet(options);
return {secret: seed, address: accountID};
const secret = keypairs.generateSeed(options);
const keypair = keypairs.deriveKeypair(secret);
const address = keypairs.deriveAddress(keypair.publicKey);
return {secret, address};
}
type AsyncFunction = (...x: any) => void

View File

@@ -1,7 +1,7 @@
/* @flow */
'use strict';
const _ = require('lodash');
const core = require('./utils').core;
const deriveKeypair = require('ripple-keypairs').deriveKeypair;
const ValidationError = require('./errors').ValidationError;
const schemaValidate = require('./schema-validator').schemaValidate;
@@ -9,6 +9,15 @@ function error(text) {
return new ValidationError(text);
}
function isValidSecret(secret) {
try {
deriveKeypair(secret);
return true;
} catch (err) {
return false;
}
}
function validateAddressAndSecret(obj: {address: string, secret: string}
): void {
const address = obj.address;
@@ -17,8 +26,8 @@ function validateAddressAndSecret(obj: {address: string, secret: string}
if (!secret) {
throw error('Parameter missing: secret');
}
if (!core.Seed.from_json(secret).is_valid()) {
throw error('secret is invalid');
if (!isValidSecret(secret)) {
throw error('Invalid parameter: secret');
}
}
@@ -26,13 +35,9 @@ function validateSecret(secret: string): void {
if (!secret) {
throw error('Parameter missing: secret');
}
if (typeof secret !== 'string' || secret[0] !== 's') {
throw error('Invalid parameter');
}
const seed = new core.Seed().parse_base58(secret);
if (!seed.is_valid()) {
throw error('invalid seed');
if (typeof secret !== 'string' || secret[0] !== 's'
|| !isValidSecret(secret)) {
throw error('Invalid parameter: secret');
}
}

View File

@@ -1,6 +1,7 @@
/* @flow */
'use strict';
const utils = require('./utils');
const keypairs = require('ripple-keypairs');
const core = utils.common.core;
const validate = utils.common.validate;
@@ -16,14 +17,6 @@ const validate = utils.common.validate;
*/
const HASH_TX_ID = 0x54584E00; // 'TXN'
function getKeyPair(secret) {
return core.Seed.from_json(secret).get_key();
}
function getPublicKeyHex(keypair) {
return keypair.pubKeyHex();
}
function serialize(txJSON) {
return core.SerializedObject.from_json(txJSON);
}
@@ -36,8 +29,8 @@ function signingData(txJSON) {
return core.Transaction.from_json(txJSON).signingData().buffer;
}
function computeSignature(txJSON, keypair) {
return keypair.signHex(signingData(txJSON));
function computeSignature(txJSON, privateKey) {
return keypairs.sign(signingData(txJSON), privateKey);
}
function sign(txJSON: string, secret: string
@@ -46,11 +39,11 @@ function sign(txJSON: string, secret: string
validate.txJSON(tx);
validate.secret(secret);
const keypair = getKeyPair(secret);
const keypair = keypairs.deriveKeypair(secret);
if (tx.SigningPubKey === undefined) {
tx.SigningPubKey = getPublicKeyHex(keypair);
tx.SigningPubKey = keypair.publicKey;
}
tx.TxnSignature = computeSignature(tx, keypair);
tx.TxnSignature = computeSignature(tx, keypair.privateKey);
const serialized = serialize(tx);
return {
signedTransaction: serialized.to_hex(),

View File

@@ -18,7 +18,7 @@ function isImmediateRejection(engineResult) {
function convertSubmitErrors(callback) {
return function(error, data) {
if (isImmediateRejection(data.engineResult)) {
if (!error && isImmediateRejection(data.engineResult)) {
callback(new utils.common.errors.RippleError('Submit failed'), data);
} else {
callback(error, data);

View File

@@ -14,10 +14,8 @@ const _ = require('lodash');
const async = require('async');
const extend = require('extend');
const util = require('util');
const {createAccountID} = require('ripple-keypairs');
const {encodeAccountID} = require('ripple-address-codec');
const {deriveAddress} = require('ripple-keypairs');
const {EventEmitter} = require('events');
const {hexToArray} = require('./utils');
const {TransactionManager} = require('./transactionmanager');
const {UInt160} = require('./uint160');
@@ -377,7 +375,7 @@ Account.prototype.publicKeyIsActive = function(public_key, callback) {
Account._publicKeyToAddress = function(public_key) {
// Based on functions in /src/js/ripple/keypair.js
function hexToUInt160(publicKey) {
return encodeAccountID(createAccountID(hexToArray(publicKey)));
return deriveAddress(publicKey);
}
if (UInt160.is_valid(public_key)) {

View File

@@ -7,17 +7,16 @@ const assert = require('assert');
const extend = require('extend');
const utils = require('./utils');
const UInt160 = require('./uint160').UInt160;
const Seed = require('./seed').Seed;
const Currency = require('./currency').Currency;
const Value = require('./value').Value;
const IOUValue = require('./iouvalue').IOUValue;
const XRPValue = require('./xrpvalue').XRPValue;
const {XRPValue, IOUValue} = require('ripple-lib-value');
type Value = XRPValue | IOUValue;
function Amount(value = new XRPValue(NaN)) {
// Json format:
// integer : XRP
// { 'value' : ..., 'currency' : ..., 'issuer' : ...}
assert(value instanceof Value);
assert(value instanceof XRPValue || value instanceof IOUValue);
this._value = value;
this._is_native = true; // Default to XRP. Only valid if value is not NaN.
@@ -626,7 +625,8 @@ function(quality, counterCurrency, counterIssuer, opts) {
}
if (this._is_native) {
this._set_value(
new XRPValue(nativeAdjusted.round(6, Value.getBNRoundDown()).toString()));
new XRPValue(nativeAdjusted.round(6, XRPValue.getBNRoundDown())
.toString()));
} else {
this._set_value(nativeAdjusted);
}
@@ -724,7 +724,7 @@ Amount.prototype.parse_native = function(j) {
// Requires _currency to be set!
Amount.prototype.parse_value = function(j) {
this._is_native = false;
const newValue = new IOUValue(j, Value.getBNRoundDown());
const newValue = new IOUValue(j, IOUValue.getBNRoundDown());
this._set_value(newValue);
return this;
};
@@ -1008,10 +1008,4 @@ Amount.prototype.not_equals_why = function(d, ignore_issuer) {
};
exports.Amount = Amount;
// DEPRECATED: Include the corresponding files instead.
exports.Currency = Currency;
exports.Seed = Seed;
exports.UInt160 = UInt160;
// vim:sw=2:sts=2:ts=8:et

View File

@@ -2,8 +2,8 @@
const _ = require('lodash');
const assert = require('assert');
const UInt160 = require('./uint160').UInt160;
const Amount = require('./amount').Amount;
const UInt160 = require('./uint160').UInt160;
const Utils = require('./orderbookutils');
function assertValidNumber(number, message) {
@@ -42,18 +42,46 @@ const NULL_AMOUNT = Utils.normalizeAmount('0');
* @return {Array}
*/
AutobridgeCalculator.prototype.calculate = function() {
const oldMode = Amount.strict_mode;
Amount.strict_mode = false;
AutobridgeCalculator.prototype.calculate = function(callback) {
let legOnePointer = 0;
let legTwoPointer = 0;
const legOnePointer = 0;
const legTwoPointer = 0;
const offersAutobridged = [];
this.clearOwnerFundsLeftover();
this._calculateInternal(legOnePointer, legTwoPointer, offersAutobridged,
callback);
};
AutobridgeCalculator.prototype._calculateInternal = function(
legOnePointer_, legTwoPointer_, offersAutobridged, callback
) {
// Amount class is calling _check_limits after each operation in strict mode,
// and _check_limits is very computationally expensive, so we turning it off
// whle doing calculations
this._oldMode = Amount.strict_mode;
Amount.strict_mode = false;
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.bind(this, legOnePointer,
legTwoPointer, offersAutobridged, callback), 0);
Amount.strict_mode = this._oldMode;
return;
}
const legOneOffer = this.legOneOffers[legOnePointer];
const legTwoOffer = this.legTwoOffers[legTwoPointer];
const leftoverFunds = this.getLeftoverOwnerFunds(legOneOffer.Account);
@@ -112,8 +140,8 @@ AutobridgeCalculator.prototype.calculate = function() {
offersAutobridged.push(autobridgedOffer);
}
Amount.strict_mode = oldMode;
return offersAutobridged;
Amount.strict_mode = this._oldMode;
callback(offersAutobridged);
};
/**

View File

@@ -9,7 +9,6 @@ exports.Base = require('./base').Base;
exports.UInt128 = require('./uint128').UInt128;
exports.UInt160 = require('./uint160').UInt160;
exports.UInt256 = require('./uint256').UInt256;
exports.Seed = require('./seed').Seed;
exports.Meta = require('./meta').Meta;
exports.SerializedObject = require('./serializedobject').SerializedObject;
exports.RippleError = require('./rippleerror').RippleError;
@@ -21,7 +20,6 @@ exports.TransactionQueue = require('./transactionqueue').TransactionQueue;
exports.convertBase = require('./baseconverter');
exports._test = {
IOUValue: require('./iouvalue').IOUValue,
Log: require('./log'),
PathFind: require('./pathfind').PathFind,
TransactionManager: require('./transactionmanager').TransactionManager,

View File

@@ -1,56 +0,0 @@
/* @flow */
'use strict';
const Value = require('./value').Value;
const XRPValue = require('./xrpvalue').XRPValue;
const GlobalBigNumber = require('bignumber.js');
const BigNumber = GlobalBigNumber.another({
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
DECIMAL_PLACES: 40
});
const rippleUnits = new BigNumber(1e6);
class IOUValue extends Value {
constructor(value: string | BigNumber, roundingMode: ?number = null,
base: ?number = null) {
super(new BigNumber(value, base).toDigits(16, roundingMode));
}
multiply(multiplicand: Value) {
if (multiplicand instanceof XRPValue) {
return super.multiply(
new IOUValue(
multiplicand._value.times(rippleUnits)));
}
return super.multiply(multiplicand);
}
divide(divisor: Value) {
if (divisor instanceof XRPValue) {
return super.divide(
new IOUValue(divisor._value.times(rippleUnits)));
}
return super.divide(divisor);
}
negate() {
return new IOUValue(this._value.neg());
}
_canonicalize(value) {
if (value.isNaN()) {
throw new Error('Invalid result');
}
return new IOUValue(value.toPrecision(16));
}
equals(comparator) {
return (comparator instanceof IOUValue)
&& this._value.equals(comparator._value);
}
}
exports.IOUValue = IOUValue;

View File

@@ -22,7 +22,7 @@ const Currency = require('./currency').Currency;
const AutobridgeCalculator = require('./autobridgecalculator');
const OrderBookUtils = require('./orderbookutils');
const log = require('./log').internal.sub('orderbook');
const IOUValue = require('./iouvalue').IOUValue;
const {IOUValue} = require('ripple-lib-value');
function _sortOffers(a, b) {
const aQuality = OrderBookUtils.getOfferQuality(a, this._currencyGets);
@@ -87,29 +87,30 @@ function OrderBook(remote,
this._gotOffersFromLegOne = false;
this._gotOffersFromLegTwo = false;
this._waitingForOffers = false;
this._lastUpdateLedgerSequence = 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() {
@@ -138,8 +139,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) {
@@ -152,7 +157,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) {
@@ -181,7 +187,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;
@@ -212,16 +219,6 @@ OrderBook.EVENTS = [
OrderBook.DEFAULT_TRANSFER_RATE = new IOUValue(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');
@@ -358,6 +355,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;
@@ -372,9 +371,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;
}
@@ -382,7 +384,12 @@ OrderBook.prototype.requestOffers = function(callback = function() {},
log.info('requested offers', self._key, 'offers: ' + res.offers.length);
}
self.setOffers(res.offers);
self.notifyDirectOffersChanged();
if (self._isAutobridgeable) {
self.computeAutobridgedOffersWrapper();
} else {
self.emit('model', self._offers);
}
callback(null, self._offers);
}
@@ -393,9 +400,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 requestOptions = _.merge({}, this.toJSON(), {ledger: 'validated'});
const request = this._remote.requestBookOffers(requestOptions);
request.once('success', handleOffers);
@@ -493,18 +503,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
@@ -839,6 +837,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();
if (this._isAutobridgeable) {
if (this._canRunAutobridgeCalc()) {
if (this._legOneBook._lastUpdateLedgerSequence === lastClosedLedger ||
this._legTwoBook._lastUpdateLedgerSequence === lastClosedLedger
) {
this.computeAutobridgedOffersWrapper();
} else if (this._lastUpdateLedgerSequence === lastClosedLedger) {
this.mergeDirectAndAutobridgedBooks();
}
}
} else if (this._lastUpdateLedgerSequence === lastClosedLedger) {
this.emit('model', this._offers);
}
}
};
/**
* Updates funded amounts/balances using modified balance nodes
*
@@ -946,6 +970,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
*
@@ -1046,7 +1080,7 @@ OrderBook.prototype.notify = function(transaction) {
this.emit('transaction', transaction);
this.notifyDirectOffersChanged();
this._lastUpdateLedgerSequence = this._remote.getLedgerSequence();
if (!takerGetsTotal.is_zero()) {
this.emit('trade', takerPaysTotal, takerGetsTotal);
@@ -1331,15 +1365,13 @@ 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) {
if (this._destroyed) {
return;
}
@@ -1352,36 +1384,26 @@ OrderBook.prototype.computeAutobridgedOffers = function() {
this._issuerPays
);
this._offersAutobridged = autobridgeCalculator.calculate();
autobridgeCalculator.calculate((autobridgedOffers) => {
this._offersAutobridged = autobridgedOffers;
callback();
});
};
OrderBook.prototype.computeAutobridgedOffersWrapper = function() {
const startTime = Date.now();
this.computeAutobridgedOffers();
this.mergeDirectAndAutobridgedBooks();
const lasted = (Date.now() - startTime);
const newMult =
Math.floor(lasted * 2 / OrderBook.AUTOBRIDGE_CALCULATE_THROTTLE_TIME) + 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;
this.computeAutobridgedOffers(() => {
this.mergeDirectAndAutobridgedBooks();
this._calculatorRunning = false;
});
};
/**
* Merge direct and autobridged offers into a combined orderbook
*

View File

@@ -7,7 +7,7 @@ const Types = require('./serializedtypes');
const Amount = require('./amount').Amount;
const Currency = require('./currency').Currency;
const UInt160 = require('./uint160').UInt160;
const IOUValue = require('./iouvalue').IOUValue;
const {IOUValue} = require('ripple-lib-value');
const OrderBookUtils = {};
function assertValidNumber(number, message) {

View File

@@ -421,22 +421,23 @@ Remote.prototype.reconnect = function() {
/**
* Connect to the Ripple network
*
* @param {Function} [callback]
* @param [Function] [callback]
* @api public
*/
Remote.prototype.connect = function(callback) {
if (!this._servers.length) {
Remote.prototype.connect = function(callback = function() {}) {
if (_.isEmpty(this._servers)) {
throw new Error('No servers available.');
}
if (typeof callback === 'function') {
this.once('connect', callback);
if (this.isConnected()) {
callback();
return this;
}
this.once('connect', callback);
this._should_connect = true;
this._servers.forEach(function(server) {
this._servers.forEach(server => {
server.connect();
});
@@ -450,25 +451,19 @@ Remote.prototype.connect = function(callback) {
* @api public
*/
Remote.prototype.disconnect = function(callback_) {
if (!this._servers.length) {
Remote.prototype.disconnect = function(callback = function() {}) {
if (_.isEmpty(this._servers)) {
throw new Error('No servers available, not disconnecting');
}
const callback = _.isFunction(callback_)
? callback_
: function() {};
this._should_connect = false;
if (!this.isConnected()) {
callback();
return this;
}
this._should_connect = false;
this.once('disconnect', callback);
this._servers.forEach(function(server) {
this._servers.forEach(server => {
server.disconnect();
});

View File

@@ -227,14 +227,8 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
let called = false;
function requestSuccess(message) {
if (!called) {
called = true;
callback.call(self, null, message);
}
}
function requestError(error) {
self.remote.removeListener('error', requestError);
if (!called) {
called = true;
@@ -246,8 +240,18 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
}
}
function requestSuccess(message) {
self.remote.removeListener('error', requestError);
if (!called) {
called = true;
callback.call(self, null, message);
}
}
this.remote.once('error', requestError); // e.g. rate-limiting slowDown error
this.once(this.successEvent, requestSuccess);
this.once(this.errorEvent, requestError);
if (!this.requested) {
this.request();
}

View File

@@ -1,97 +0,0 @@
'use strict';
//
// Seed support
//
const {KeyPair, KeyType} = require('ripple-keypairs');
const {decodeSeed, encodeSeed} = require('ripple-address-codec');
const extend = require('extend');
const sjclcodec = require('sjcl-codec');
const BN = require('bn.js');
const hashjs = require('hash.js');
const UInt = require('./uint').UInt;
const Seed = extend(function() {
this._value = NaN;
this._type = KeyType.secp256k1;
}, UInt);
Seed.width = 16;
Seed.prototype = Object.create(extend({}, UInt.prototype));
Seed.prototype.constructor = Seed;
// value = NaN on error.
// One day this will support rfc1751 too.
Seed.prototype.parse_json = function(j) {
if (typeof j === 'string') {
if (!j.length) {
this._value = NaN;
} else {
this.parse_base58(j);
if (!this.is_valid()) {
this.parse_hex(j);
// XXX Should also try 1751
}
if (!this.is_valid() && j[0] !== 's') {
this.parse_passphrase(j);
}
}
} else {
this._value = NaN;
}
return this;
};
Seed.prototype.parse_base58 = function(j) {
if (typeof j !== 'string') {
throw new Error('Value must be a string');
}
if (!j.length || j[0] !== 's') {
this._value = NaN;
} else {
try {
const {bytes, type} = decodeSeed(j);
this._value = new BN(bytes);
this._type = type;
} catch (e) {
this._value = NaN;
}
}
return this;
};
Seed.prototype.set_ed25519 = function() {
this._type = KeyType.ed25519;
return this;
};
Seed.prototype.parse_passphrase = function(j) {
if (typeof j !== 'string') {
throw new Error('Passphrase must be a string');
}
const phraseBytes = sjclcodec.bytes.fromBits(sjclcodec.utf8String.toBits(j));
const hash = hashjs.sha512().update(phraseBytes).digest();
this.parse_bytes(hash.slice(0, 16));
return this;
};
Seed.prototype.to_json = function() {
if (!(this.is_valid())) {
return NaN;
}
return encodeSeed(this.to_bytes(), this._type);
};
Seed.prototype.get_key = function() {
if (!this.is_valid()) {
throw new Error('Cannot generate keys from invalid seed!');
}
return KeyPair.fromSeed(this.to_bytes(), this._type);
};
exports.Seed = Seed;

View File

@@ -3,14 +3,13 @@
const assert = require('assert');
const util = require('util');
const _ = require('lodash');
const {deriveKeypair, sign} = require('ripple-keypairs');
const EventEmitter = require('events').EventEmitter;
const utils = require('./utils');
const sjclcodec = require('sjcl-codec');
const Amount = require('./amount').Amount;
const Currency = require('./amount').Currency;
const UInt160 = require('./amount').UInt160;
const Seed = require('./seed').Seed;
const KeyPair = require('ripple-keypairs').KeyPair;
const Currency = require('./currency').Currency;
const UInt160 = require('./uint160').UInt160;
const SerializedObject = require('./serializedobject').SerializedObject;
const RippleError = require('./rippleerror').RippleError;
const hashprefixes = require('./hashprefixes');
@@ -45,6 +44,7 @@ function Transaction(remote) {
? this.remote.automatic_resubmission
: true;
this._maxFee = remoteExists ? this.remote.max_fee : undefined;
this._lastLedgerOffset = remoteExists ? this.remote.last_ledger_offset : 3;
this.state = 'unsubmitted';
this.finalized = false;
this.previousSigningHash = undefined;
@@ -429,31 +429,12 @@ Transaction.prototype.complete = function() {
return this.tx_json;
};
Transaction.prototype.getKeyPair = function(secret_) {
if (this._keyPair) {
return this._keyPair;
}
const secret = secret_ || this._secret;
assert(secret, 'Secret missing');
const keyPair = Seed.from_json(secret).get_key();
this._keyPair = keyPair;
return keyPair;
};
Transaction.prototype.getSigningPubKey = function(secret) {
return this.getKeyPair(secret).pubKeyHex();
return deriveKeypair(secret || this._secret).publicKey;
};
Transaction.prototype.setSigningPubKey = function(key) {
if (_.isString(key)) {
this.tx_json.SigningPubKey = key;
} else if (key instanceof KeyPair) {
this.tx_json.SigningPubKey = key.pubKeyHex();
}
this.tx_json.SigningPubKey = key;
return this;
};
@@ -508,16 +489,13 @@ Transaction.prototype.hash = function(prefix_, asUINT256, serialized) {
return asUINT256 ? hash : hash.to_hex();
};
Transaction.prototype.sign = function() {
Transaction.prototype.sign = function(secret) {
if (this.hasMultiSigners()) {
return this;
}
const keyPair = this.getKeyPair();
const prev_sig = this.tx_json.TxnSignature;
delete this.tx_json.TxnSignature;
const hash = this.signingHash();
// If the hash is the same, we can re-use the previous signature
@@ -526,7 +504,9 @@ Transaction.prototype.sign = function() {
return this;
}
this.tx_json.TxnSignature = keyPair.signHex(this.signingData().buffer);
const keypair = deriveKeypair(secret || this._secret);
this.tx_json.TxnSignature = sign(this.signingData().buffer,
keypair.privateKey);
this.previousSigningHash = hash;
return this;
@@ -582,19 +562,30 @@ Transaction.prototype.clientID = function(id) {
return this;
};
/**
* Set LastLedgerSequence as the absolute last ledger sequence the transaction
* is valid for. LastLedgerSequence is set automatically if not set using this
* method
*
* @param {Number} ledger index
*/
Transaction.prototype.setLastLedgerSequenceOffset = function(offset) {
this._lastLedgerOffset = offset;
};
Transaction.prototype.setLastLedgerSequence =
Transaction.prototype.getLastLedgerSequenceOffset = function() {
return this._lastLedgerOffset;
};
Transaction.prototype.lastLedger =
Transaction.prototype.setLastLedger =
Transaction.prototype.lastLedger = function(sequence) {
this._setUInt32('LastLedgerSequence', sequence);
Transaction.prototype.setLastLedgerSequence = function(sequence) {
if (!_.isUndefined(sequence)) {
this._setUInt32('LastLedgerSequence', sequence);
} else {
// Autofill LastLedgerSequence
assert(this.remote, 'Unable to set LastLedgerSequence, missing Remote');
this._setUInt32('LastLedgerSequence',
this.remote.getLedgerSequence() + 1
+ this.getLastLedgerSequenceOffset());
}
this._setLastLedger = true;
return this;
};
@@ -1479,7 +1470,7 @@ Transaction.prototype.summary = function() {
submissionAttempts: this.attempts,
submitIndex: this.submitIndex,
initialSubmitIndex: this.initialSubmitIndex,
lastLedgerSequence: this.lastLedgerSequence,
lastLedgerSequence: this.tx_json.LastLedgerSequence,
state: this.state,
finalized: this.finalized
};
@@ -1616,30 +1607,44 @@ Transaction.prototype.setSigners = function(signers) {
Transaction.prototype.addMultiSigner = function(signer) {
assert(UInt160.is_valid(signer.Account), 'Signer must have a valid Account');
if (_.isUndefined(this.multi_signers)) {
this.multi_signers = [];
if (_.isUndefined(this.tx_json.Signers)) {
this.tx_json.Signers = [];
}
this.multi_signers.push({Signer: signer});
this.tx_json.Signers.push({Signer: signer});
this.multi_signers.sort((a, b) => {
this.tx_json.Signers.sort((a, b) => {
return UInt160.from_json(a.Signer.Account)
.cmp(UInt160.from_json(b.Signer.Account));
});
return this;
};
Transaction.prototype.hasMultiSigners = function() {
return !_.isEmpty(this.multi_signers);
return !_.isEmpty(this.tx_json.Signers);
};
Transaction.prototype.getMultiSigners = function() {
return this.multi_signers;
return this.tx_json.Signers;
};
Transaction.prototype.getMultiSigningJson = function() {
assert(this.tx_json.Sequence, 'Sequence must be set before multi-signing');
assert(this.tx_json.Fee, 'Fee must be set before multi-signing');
const signingTx = Transaction.from_json(this.tx_json);
if (_.isUndefined(this.tx_json.LastLedgerSequence)) {
// Auto-fill LastLedgerSequence
this.setLastLedgerSequence();
}
const cleanedJson = _.omit(this.tx_json, [
'SigningPubKey',
'Signers',
'TxnSignature'
]);
const signingTx = Transaction.from_json(cleanedJson);
signingTx.remote = this.remote;
signingTx.setSigningPubKey('');
signingTx.setCanonicalFlag();
@@ -1649,12 +1654,12 @@ Transaction.prototype.getMultiSigningJson = function() {
Transaction.prototype.multiSign = function(account, secret) {
const signingData = this.multiSigningData(account);
const keyPair = Seed.from_json(secret).get_key();
const keypair = deriveKeypair(secret);
const signer = {
Account: account,
TxnSignature: keyPair.signHex(signingData.buffer),
SigningPubKey: keyPair.pubKeyHex()
TxnSignature: sign(signingData.buffer, keypair.privateKey),
SigningPubKey: keypair.publicKey
};
return signer;

View File

@@ -27,7 +27,6 @@ function TransactionManager(account) {
this._maxFee = this._remote.max_fee;
this._maxAttempts = this._remote.max_attempts;
this._submissionTimeout = this._remote.submission_timeout;
this._lastLedgerOffset = this._remote.last_ledger_offset;
this._pending = new PendingQueue();
this._account.on('transaction-outbound', function(res) {
@@ -521,17 +520,6 @@ TransactionManager.prototype._resubmit = function(ledgers_, pending_) {
TransactionManager.prototype._prepareRequest = function(tx) {
const submitRequest = this._remote.requestSubmit();
if (tx.hasMultiSigners()) {
tx.setSigningPubKey('');
if (this._remote.local_signing) {
tx.setSigners(tx.getMultiSigners());
} else {
submitRequest.message.command = 'submit_multisigned';
submitRequest.message.Signers = tx.getMultiSigners();
}
}
if (this._remote.local_signing) {
tx.sign();
@@ -541,6 +529,10 @@ TransactionManager.prototype._prepareRequest = function(tx) {
const hash = tx.hash(null, null, serialized);
tx.addId(hash);
} else {
if (tx.hasMultiSigners()) {
submitRequest.message.command = 'submit_multisigned';
}
// ND: `build_path` is completely ignored when doing local signing as
// `Paths` is a component of the signed blob, the `tx_blob` is signed,
// sealed and delivered, and the txn unmodified.
@@ -580,6 +572,11 @@ TransactionManager.prototype._request = function(tx) {
return;
}
if (Number(tx.tx_json.Fee) > tx._maxFee) {
tx.emit('error', new RippleError('tejMaxFeeExceeded'));
return;
}
if (remote.trace) {
log.info('submit transaction:', tx.tx_json);
}
@@ -684,24 +681,12 @@ TransactionManager.prototype._request = function(tx) {
}
}
tx.submitIndex = this._remote._ledger_current_index;
tx.submitIndex = this._remote.getLedgerSequence() + 1;
if (tx.attempts === 0) {
tx.initialSubmitIndex = tx.submitIndex;
}
if (!tx._setLastLedger && !tx.hasMultiSigners()) {
// Honor LastLedgerSequence set with tx.lastLedger()
tx.tx_json.LastLedgerSequence = tx.initialSubmitIndex
+ this._lastLedgerOffset;
}
tx.lastLedgerSequence = tx.tx_json.LastLedgerSequence;
if (remote.local_signing) {
tx.sign();
}
const submitRequest = this._prepareRequest(tx);
submitRequest.once('error', submitted);
submitRequest.once('success', submitted);
@@ -743,8 +728,13 @@ TransactionManager.prototype.submit = function(tx) {
tx.setSequence(this._nextSequence++);
}
if (_.isUndefined(tx.tx_json.LastLedgerSequence)) {
tx.setLastLedgerSequence();
}
if (tx.hasMultiSigners()) {
tx.setResubmittable(false);
tx.setSigningPubKey('');
}
tx.once('cleanup', function() {

View File

@@ -1,109 +0,0 @@
/* @flow */
'use strict';
const GlobalBigNumber = require('bignumber.js');
const BigNumber = GlobalBigNumber.another({
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
DECIMAL_PLACES: 40
});
const assert = require('assert');
class Value {
constructor(value: string | BigNumber) {
if (this.constructor === 'Value') {
throw new Error(
'Cannot instantiate Value directly, it is an abstract base class');
}
this._value = new BigNumber(value);
}
static getBNRoundDown() {
return BigNumber.ROUND_DOWN;
}
abs() {
const result = this._value.abs();
return this._canonicalize(result);
}
add(addend: Value) {
assert(this.constructor === addend.constructor);
const result = this._value.plus(addend._value);
return this._canonicalize(result);
}
subtract(subtrahend: Value) {
assert(this.constructor === subtrahend.constructor);
const result = this._value.minus(subtrahend._value);
return this._canonicalize(result);
}
multiply(multiplicand: Value) {
const result = this._value.times(multiplicand._value);
return this._canonicalize(result);
}
divide(divisor: Value) {
if (divisor.isZero()) {
throw new Error('divide by zero');
}
const result = this._value.dividedBy(divisor._value);
return this._canonicalize(result);
}
invert() {
const result = (new BigNumber(this._value)).toPower(-1);
return this._canonicalize(result);
}
round(decimalPlaces: number, roundingMode: number) {
const result = this._value.round(decimalPlaces, roundingMode);
return this._canonicalize(result);
}
toFixed(decimalPlaces: number, roundingMode: number) {
return this._value.toFixed(decimalPlaces, roundingMode);
}
getExponent() {
return this._value.e;
}
isNaN() {
return this._value.isNaN();
}
isZero() {
return this._value.isZero();
}
isNegative() {
return this._value.isNegative();
}
toString() {
return this._value.toString();
}
greaterThan(comparator: Value) {
assert(this.constructor === comparator.constructor);
return this._value.greaterThan(comparator._value);
}
lessThan(comparator: Value) {
assert(this.constructor === comparator.constructor);
return this._value.lessThan(comparator._value);
}
comparedTo(comparator: Value) {
assert(this.constructor === comparator.constructor);
return this._value.comparedTo(comparator._value);
}
}
exports.Value = Value;

View File

@@ -1,59 +0,0 @@
/* @flow */
'use strict';
const GlobalBigNumber = require('bignumber.js');
const BigNumber = GlobalBigNumber.another({
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
DECIMAL_PLACES: 40
});
const Value = require('./value').Value;
const rippleUnits = new BigNumber(1e6);
class XRPValue extends Value {
constructor(value: string | BigNumber) {
super(value);
if (this._value.dp() > 6) {
throw new Error(
'Value has more than 6 digits of precision past the decimal point, '
+ 'an IOUValue may be being cast to an XRPValue'
);
}
}
multiply(multiplicand: Value) {
if (multiplicand instanceof XRPValue) {
return super.multiply(
new XRPValue(multiplicand._value.times(rippleUnits)));
}
return super.multiply(multiplicand);
}
divide(divisor: Value) {
if (divisor instanceof XRPValue) {
return super.divide(
new XRPValue(divisor._value.times(rippleUnits)));
}
return super.divide(divisor);
}
negate() {
return new XRPValue(this._value.neg());
}
_canonicalize(value) {
if (value.isNaN()) {
throw new Error('Invalid result');
}
return new XRPValue(value.round(6, BigNumber.ROUND_DOWN));
}
equals(comparator) {
return (comparator instanceof XRPValue)
&& this._value.equals(comparator._value);
}
}
exports.XRPValue = XRPValue;

View File

@@ -481,7 +481,7 @@ describe('RippleAPI', function() {
function random() {
return _.fill(Array(16), 0);
}
assert.deepEqual(this.api.generateAddress({random}),
assert.deepEqual(this.api.generateAddress({entropy: random()}),
responses.generateAddress);
});

View File

@@ -31,6 +31,7 @@
"currency": "XRP",
"value": "0"
},
"makerExchangeRate": "1185000",
"sequence": 465,
"status": "canceled"
}
@@ -39,4 +40,4 @@
"ledgerVersion": 14661789,
"indexInLedger": 4
}
}
}

View File

@@ -40,6 +40,7 @@
"currency": "XRP",
"value": "0.0002"
},
"makerExchangeRate": "1185000",
"sequence": 465,
"status": "created"
}

View File

@@ -75,6 +75,7 @@
"counterparty": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"value": "-0.001002"
},
"makerExchangeRate": "1099",
"sequence": 58,
"status": "open"
}

View File

@@ -81,6 +81,7 @@
"counterparty": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"value": "-0.001002"
},
"makerExchangeRate": "1099",
"sequence": 58,
"status": "open"
}
@@ -172,6 +173,7 @@
"counterparty": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"value": "-0.001002"
},
"makerExchangeRate": "1099",
"sequence": 58,
"status": "open"
}

View File

@@ -7,7 +7,7 @@ const addresses = require('./addresses');
const Meta = require('ripple-lib').Meta;
const SerializedObject = require('ripple-lib').SerializedObject;
const Types = require('ripple-lib').types;
const IOUValue = require('ripple-lib')._test.IOUValue;
const IOUValue = require('ripple-lib-value').IOUValue;
module.exports.FIAT_BALANCE = '10';
module.exports.NATIVE_BALANCE = '55';

View File

@@ -8,7 +8,7 @@ const Remote = require('ripple-lib').Remote;
const Currency = require('ripple-lib').Currency;
const addresses = require('./fixtures/addresses');
const fixtures = require('./fixtures/orderbook');
const IOUValue = require('ripple-lib')._test.IOUValue;
const IOUValue = require('ripple-lib-value').IOUValue;
describe('OrderBook Autobridging', function() {
this.timeout(0);
@@ -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);
});
});

View File

@@ -9,14 +9,14 @@ const Amount = require('ripple-lib').Amount;
const Meta = require('ripple-lib').Meta;
const addresses = require('./fixtures/addresses');
const fixtures = require('./fixtures/orderbook');
const IOUValue = require('ripple-lib')._test.IOUValue;
const IOUValue = require('ripple-lib-value').IOUValue;
describe('OrderBook', function() {
this.timeout(0);
function createRemote() {
const remote = new Remote();
remote._ledger_current_index = 32570;
remote.isConnected = function() {
return true;
};
@@ -1605,9 +1605,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);
@@ -1698,7 +1704,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);
@@ -1857,7 +1866,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);

View File

@@ -716,6 +716,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',

View File

@@ -1,46 +0,0 @@
/* eslint max-len: 0 */
/* eslint-disable max-nested-callbacks */
'use strict';
const assert = require('assert');
const Seed = require('ripple-lib').Seed;
describe('Seed', function() {
it('saESc82Vun7Ta5EJRzGJbrXb5HNYk', function() {
const seed = Seed.from_json('saESc82Vun7Ta5EJRzGJbrXb5HNYk');
assert.strictEqual(seed.to_hex(), 'FF1CF838D02B2CF7B45BAC27F5F24F4F');
});
it('can create ed25519 seeds from a phrase', function() {
const seed = Seed.from_json('phrase').set_ed25519().to_json();
assert.strictEqual(seed, 'sEdT7U4WpkoiH6wBoNeLzDi1eu9N64Y');
});
it('sp6iDHnmiPN7tQFHm5sCW59ax3hfE', function() {
const seed = Seed.from_json('sp6iDHnmiPN7tQFHm5sCW59ax3hfE');
assert.strictEqual(seed.to_hex(), '00AD8DA764C3C8AF5F9B8D51C94B9E49');
});
it('sp6iDHnmiPN7tQFHm5sCW59ax3hfE using parse_base58', function() {
const seed = new Seed().parse_base58('sp6iDHnmiPN7tQFHm5sCW59ax3hfE');
assert.strictEqual(seed.to_hex(), '00AD8DA764C3C8AF5F9B8D51C94B9E49');
});
it('parse_base58 should throw on non-string input', function() {
assert.throws(function() {
new Seed().parse_base58(1);
});
});
it('parse_base58 should make invalid seed from empty string', function() {
const seed = new Seed().parse_base58('');
assert(!seed.is_valid());
});
it('parse_base58 should make invalid seed from invalid input', function() {
const seed = new Seed().parse_base58('Xs');
assert(!seed.is_valid());
});
it('should return the key_pair for a valid account and secret pair', function() {
const address = 'r3GgMwvgvP8h4yVWvjH1dPZNvC37TjzBBE';
const seed = Seed.from_json('shsWGZcmZz6YsWWmcnpfr6fLTdtFV');
const keyPair = seed.get_key();
assert.strictEqual(keyPair.accountID(), address);
assert.strictEqual(keyPair.pubKeyHex(), '02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8');
});
});
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1249,4 +1249,71 @@ describe('Server', function() {
server.connect();
});
it('Automatic reconnect', function(done) {
const port = 5748;
let connections = 0;
function handleWsConnection(_ws) {
++connections;
_ws.on('message', (message) => {
const parsed = JSON.parse(message);
assert.strictEqual(parsed.command, 'subscribe');
_ws.send(JSON.stringify({
id: parsed.id,
status: 'success',
type: 'response',
result: {
fee_base: 10,
fee_ref: 10,
ledger_hash:
'1838539EE12463C36F2C53B079D807C697E3D93A1936B717E565A4A912E11776',
ledger_index: 7053695,
ledger_time: 455414390,
load_base: 256,
load_factor: 256,
random:
'E56C9154D9BE94D49C581179356C2E084E16D18D74E8B09093F2D61207625E6A',
reserve_base: 20000000,
reserve_inc: 5000000,
server_status: 'full',
validated_ledgers: '32570-7053695',
pubkey_node: 'n94pSqypSfddzAVj9qoezHyUoetsrMnwgNuBqRJ3WHvM8aMMf7rW'
}
}));
});
}
let wss = new ws.Server({port});
wss.once('connection', handleWsConnection);
const remote = new Remote();
const server = remote.addServer(`ws://localhost:${port}`);
let receivedReconnectAttempt = false;
server.once('disconnect', () => {
assert.equal(remote.getServer(), null);
server.once('connect', () => {
assert(receivedReconnectAttempt);
assert.equal(connections, 2);
assert(remote.getServer() instanceof Server);
done();
});
server.once('connecting', () => {
receivedReconnectAttempt = true;
wss = new ws.Server({port});
wss.once('connection', handleWsConnection);
});
});
server.once('connect', () => {
assert(remote.getServer() instanceof Server);
// Force server disconnect, ripple-lib should attempt
// to reconnect automatically
wss.close();
});
server.connect();
});
});

View File

@@ -1,62 +0,0 @@
'use strict';
const assert = require('assert');
const Seed = require('ripple-lib').Seed;
function _isNaN(n) {
return typeof n === 'number' && isNaN(n);
}
describe('Signing', function() {
describe('Keys', function() {
it('SigningPubKey 1 (ripple-client issue #245)', function() {
const seed = Seed.from_json('saESc82Vun7Ta5EJRzGJbrXb5HNYk');
const key = seed.get_key('rBZ4j6MsoctipM6GEyHSjQKzXG3yambDnZ');
const pub = key.pubKeyHex();
assert.strictEqual(
pub,
'0396941B22791A448E5877A44CE98434DB217D6FB97D63F0DAD23BE49ED45173C9');
});
it('SigningPubKey 2 (master seed)', function() {
const seed = Seed.from_json('snoPBrXtMeMyMHUVTgbuqAfg1SUTb');
const key = seed.get_key('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
const pub = key.pubKeyHex();
assert.strictEqual(
pub,
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020');
});
});
describe('parse_json', function() {
it('empty string', function() {
assert(_isNaN(new Seed().parse_json('').to_json()));
});
it('hex string', function() {
// 32 0s is a valid hex repr of seed bytes
const str = new Array(33).join('0');
assert.strictEqual((new Seed().parse_json(str).to_json()),
'sp6JS7f14BuwFY8Mw6bTtLKWauoUs');
});
it('passphrase', function() {
const str = new Array(60).join('0');
assert.strictEqual('snFRPnVL3secohdpwSie8ANXdFQvG',
new Seed().parse_json(str).to_json());
});
it('null', function() {
assert(_isNaN(new Seed().parse_json(null).to_json()));
});
});
describe('parse_passphrase', function() {
it('invalid passphrase', function() {
assert.throws(function() {
new Seed().parse_passphrase(null);
});
});
});
describe('get_key', function() {
it('get key from invalid seed', function() {
assert.throws(function() {
new Seed().get_key('rBZ4j6MsoctipM6GEyHSjQKzXG3yambDnZ');
});
});
});
});

View File

@@ -518,7 +518,9 @@ describe('TransactionManager', function() {
break;
}
});
/* eslint-disable no-unused-vars */
rippled.once('request_submit', function(m, req) {
/* eslint-enable no-unused-vars */
req.sendJSON(lodash.extend({}, LEDGER, {
ledger_index: transaction.tx_json.LastLedgerSequence + 1
}));
@@ -574,7 +576,9 @@ describe('TransactionManager', function() {
req.sendResponse(SUBMIT_TEF_RESPONSE, {id: m.id});
});
/* eslint-disable no-unused-vars */
rippled.once('request_submit', function(m, req) {
/* eslint-enable no-unused-vars */
transaction.once('resubmitted', function() {
receivedResubmitted = true;
req.sendJSON(lodash.extend({}, LEDGER, {
@@ -634,7 +638,9 @@ describe('TransactionManager', function() {
req.sendResponse(SUBMIT_TEL_RESPONSE, {id: m.id});
});
/* eslint-disable no-unused-vars */
rippled.once('request_submit', function(m, req) {
/* eslint-enable no-unused-vars */
transaction.once('resubmitted', function() {
receivedResubmitted = true;
req.sendJSON(lodash.extend({}, LEDGER, {
@@ -690,7 +696,7 @@ describe('TransactionManager', function() {
assert.strictEqual(summary.submissionAttempts, 0);
assert.strictEqual(summary.submitIndex, undefined);
assert.strictEqual(summary.initialSubmitIndex, undefined);
assert.strictEqual(summary.lastLedgerSequence, undefined);
assert.strictEqual(summary.lastLedgerSequence, remote.getLedgerSequence() + 1 + Remote.DEFAULTS.last_ledger_offset);
assert.strictEqual(summary.state, 'failed');
assert.strictEqual(summary.finalized, true);
assert.deepEqual(summary.result, {
@@ -799,7 +805,9 @@ describe('TransactionManager', function() {
req.sendResponse(SUBMIT_TEL_RESPONSE, {id: m.id});
});
/* eslint-disable no-unused-vars */
rippled.once('request_submit', function(m, req) {
/* eslint-enable no-unused-vars */
transaction.once('resubmitted', function() {
receivedResubmitted = true;
});
@@ -857,6 +865,7 @@ describe('TransactionManager', function() {
receivedSubmitted = true;
});
/* eslint-disable no-unused-vars */
rippled.on('request_submit', function(m, req) {
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
transaction.tx_json).to_hex());
@@ -867,7 +876,9 @@ describe('TransactionManager', function() {
req.sendResponse(SUBMIT_TOO_BUSY_ERROR, {id: m.id});
});
/* eslint-disable no-unused-vars */
rippled.once('request_submit', function(m, req) {
/* eslint-enable no-unused-vars */
transaction.once('resubmitted', function() {
receivedResubmitted = true;
req.sendJSON(lodash.extend({}, LEDGER, {

View File

@@ -2,8 +2,9 @@
'use strict';
const assert = require('assert');
const assert = require('assert-diff');
const lodash = require('lodash');
const addresses = require('./fixtures/addresses');
const ripple = require('ripple-lib');
const Transaction = require('ripple-lib').Transaction;
const TransactionQueue = require('ripple-lib').TransactionQueue;
@@ -340,7 +341,7 @@ describe('Transaction', function() {
const dst = 'rGihwhaqU8g7ahwAvTq6iX5rvsfcbgZw6v';
transaction.payment(src, dst, '100');
remote.setSecret(src, 'masterpassphrase');
remote.setSecret(src, addresses.SECRET);
assert(transaction.complete());
const json = transaction.serialize().to_json();
@@ -983,9 +984,6 @@ describe('Transaction', function() {
it('Set LastLedgerSequence', function() {
const transaction = new Transaction();
assert.throws(function() {
transaction.lastLedger('a');
}, /Error: LastLedgerSequence must be a valid UInt32/);
assert.throws(function() {
transaction.setLastLedgerSequence('a');
}, /Error: LastLedgerSequence must be a valid UInt32/);
@@ -1945,6 +1943,8 @@ describe('Transaction', function() {
it('Submit transaction', function(done) {
const remote = new Remote();
remote._ledger_current_index = 1;
const transaction = new Transaction(remote).accountSet('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
assert.strictEqual(transaction.callback, undefined);
@@ -1989,6 +1989,8 @@ describe('Transaction', function() {
it('Submit transaction - submission error', function(done) {
const remote = new Remote();
remote._ledger_current_index = 1;
const transaction = new Transaction(remote).accountSet('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
const account = remote.addAccount('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
@@ -2107,82 +2109,6 @@ describe('Transaction', function() {
});
});
it('Add multisigner', function() {
const transaction = new Transaction();
const s1 = {
Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK',
TxnSignature: '304402203020865BDC995431325C371E6A3CE89BFC40597D9CFAF77DBB16E9D159824EA402203645A6462A6DCEC7B5D0811882DC54CEA66258A227A2762BE6EFCD9EB62C27BF',
SigningPubKey: '02691AC5AE1C4C333AE5DF8A93BDC495F0EEBFC6DB0DA7EB6EF808F3AFC006E3FE'
};
const s2 = {
Account: 'rH4KEcG9dEwGwpn6AyoWK9cZPLL4RLSmWW',
TxnSignature: '30450221009C84E455DC199A7DB4B800D68C92269D60972E8850AFC0D50B1AE6B08BBB02EA02206FA93A560BE96844DF7D96D07F6400EF9534A32FBA352DD10E855DA8923A3AF8',
SigningPubKey: '028949021029D5CC87E78BCF053AFEC0CAFD15108EC119EAAFEC466F5C095407BF'
};
transaction.addMultiSigner(s1);
transaction.addMultiSigner(s2);
assert.deepEqual(transaction.getMultiSigners(), [
{Signer: s2}, {Signer: s1}]);
});
it('Get multisign data', function() {
const transaction = Transaction.from_json({
Account: 'rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn',
Sequence: 1,
Fee: '100',
TransactionType: 'AccountSet',
Flags: 0
});
transaction.setSigningPubKey('');
const a1 = 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK';
const d1 = transaction.multiSigningData(a1);
const tbytes = ripple.SerializedObject.from_json(
lodash.merge(transaction.tx_json, {SigningPubKey: ''})).buffer;
const abytes = ripple.UInt160.from_json(a1).to_bytes();
const prefix = require('ripple-lib')._test.HashPrefixes.HASH_TX_MULTISIGN_BYTES;
assert.deepEqual(d1.buffer, prefix.concat(tbytes, abytes));
});
it('Multisign', function() {
const transaction = Transaction.from_json({
Account: 'rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn',
Sequence: 1,
Fee: '100',
TransactionType: 'AccountSet',
Flags: 0
});
const multiSigningJson = transaction.getMultiSigningJson();
const t1 = Transaction.from_json(multiSigningJson);
const a1 = 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK';
const a2 = 'rH4KEcG9dEwGwpn6AyoWK9cZPLL4RLSmWW';
const s1 = t1.multiSign(a1, 'alice');
assert.strictEqual(s1.Account, a1);
assert.strictEqual(s1.SigningPubKey, '0388935426E0D08083314842EDFBB2D517BD47699F9A4527318A8E10468C97C052');
assert.strictEqual(s1.TxnSignature, '30440220611256E46B2946152695FFEF34D5C71BB3AE569C3D919A270BFBCA9ADF260D9202202FAE24FC8A575FE3265A6D7CFA596094A7950E0011706431A11C2A9ABEF60B3B');
const s2 = t1.multiSign(a2, 'bob');
assert.strictEqual(s2.Account, a2);
assert.strictEqual(s2.SigningPubKey, '02691AC5AE1C4C333AE5DF8A93BDC495F0EEBFC6DB0DA7EB6EF808F3AFC006E3FE');
assert.strictEqual(s2.TxnSignature, '3044022067F769BE0A4CC2B4F26E7B52B366F861FED02DA0F564F98B44009C8181A9655702206D882919139DF8E9D7F2FC1DD54D8B4FEAC40203349AE21519FD388925A4DE83');
transaction.addMultiSigner(s1);
transaction.addMultiSigner(s2);
assert.deepEqual(transaction.getMultiSigners(), [
{Signer: s2},
{Signer: s1}
]);
});
it('Construct SuspendedPaymentCreate transaction', function() {
const transaction = new Transaction().suspendedPaymentCreate({
account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm',
@@ -2294,4 +2220,100 @@ describe('Transaction', function() {
OfferSequence: 1234
});
});
it('Add multisigner', function() {
const transaction = new Transaction();
const s1 = {
Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK',
TxnSignature: '304402203020865BDC995431325C371E6A3CE89BFC40597D9CFAF77DBB16E9D159824EA402203645A6462A6DCEC7B5D0811882DC54CEA66258A227A2762BE6EFCD9EB62C27BF',
SigningPubKey: '02691AC5AE1C4C333AE5DF8A93BDC495F0EEBFC6DB0DA7EB6EF808F3AFC006E3FE'
};
const s2 = {
Account: 'rH4KEcG9dEwGwpn6AyoWK9cZPLL4RLSmWW',
TxnSignature: '30450221009C84E455DC199A7DB4B800D68C92269D60972E8850AFC0D50B1AE6B08BBB02EA02206FA93A560BE96844DF7D96D07F6400EF9534A32FBA352DD10E855DA8923A3AF8',
SigningPubKey: '028949021029D5CC87E78BCF053AFEC0CAFD15108EC119EAAFEC466F5C095407BF'
};
transaction.addMultiSigner(s1);
transaction.addMultiSigner(s2);
assert.deepEqual(transaction.getMultiSigners(), [
{Signer: s2}, {Signer: s1}]);
});
it('Get multisign data', function() {
const transaction = Transaction.from_json({
Account: 'rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn',
Sequence: 1,
Fee: '100',
TransactionType: 'AccountSet',
Flags: 0
});
transaction.setSigningPubKey('');
const a1 = 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK';
const d1 = transaction.multiSigningData(a1);
const tbytes = ripple.SerializedObject.from_json(
lodash.merge(transaction.tx_json, {SigningPubKey: ''})).buffer;
const abytes = ripple.UInt160.from_json(a1).to_bytes();
const prefix = require('ripple-lib')._test.HashPrefixes.HASH_TX_MULTISIGN_BYTES;
assert.deepEqual(d1.buffer, prefix.concat(tbytes, abytes));
});
it('Multisign', function() {
const transaction = Transaction.from_json({
Account: 'rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn',
Sequence: 1,
Fee: '100',
TransactionType: 'AccountSet',
Flags: 0,
LastLedgerSequence: 1
});
const multiSigningJson = transaction.getMultiSigningJson();
const t1 = Transaction.from_json(multiSigningJson);
const a1 = 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK';
const a2 = 'rH4KEcG9dEwGwpn6AyoWK9cZPLL4RLSmWW';
const s1 = t1.multiSign(a1, addresses.SECRET);
assert.deepEqual(s1, {
Account: 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK',
TxnSignature: '30440220613DF9410B4844C7FAB637FD707F5185A2107DD10D0C2F59155844CD1910AB99022004A2AE607C15DD0959FDB3AAEE6A0337AA5337515230CE6EC11E32B74EEE896E',
SigningPubKey: '02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8'
});
const s2 = t1.multiSign(a2, addresses.SECRET);
assert.deepEqual(s2, {
Account: 'rH4KEcG9dEwGwpn6AyoWK9cZPLL4RLSmWW',
TxnSignature: '3044022011762BC175E166EF540ABB162F0E8B48250E7C95DE5E8464E3F648EAF9A94A50022022439146DC3C6BB943C719F89696E7EBED14888A653F4618F62F8DA5CE202A45',
SigningPubKey: '02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8'
});
transaction.addMultiSigner(s1);
transaction.addMultiSigner(s2);
assert.deepEqual(transaction.getMultiSigners(), [
{Signer: s2},
{Signer: s1}
]);
});
it('Multisign -- missing LastLedgerSequence', function() {
const transaction = Transaction.from_json({
Account: 'rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn',
Sequence: 1,
Fee: '100',
TransactionType: 'AccountSet',
Flags: 0
});
assert.throws(function() {
transaction.getMultiSigningJson();
});
});
});