[TASK] Refactor to use bignumber.js

This commit is contained in:
Chris Clark
2015-01-08 17:33:37 -08:00
parent 2cab50f920
commit d025b4a0c3
20 changed files with 571 additions and 1989 deletions

5
npm-shrinkwrap.json generated
View File

@@ -7,6 +7,11 @@
"from": "async@>=0.8.0 <0.9.0",
"resolved": "https://registry.npmjs.org/async/-/async-0.8.0.tgz"
},
"bignumber.js": {
"version": "2.0.0",
"from": "bignumber.js@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.0.0.tgz"
},
"extend": {
"version": "1.2.1",
"from": "extend@>=1.2.1 <1.3.0",

View File

@@ -16,6 +16,7 @@
},
"dependencies": {
"async": "~0.8.0",
"bignumber.js": "^2.0.0",
"extend": "~1.2.1",
"lodash": "^2.4.1",
"lru-cache": "~2.5.0",

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +1,45 @@
// Represent Ripple amounts and currencies.
// - Numbers in hex are big-endian.
var assert = require('assert');
var extend = require('extend');
var utils = require('./utils');
var sjcl = utils.sjcl;
var bn = sjcl.bn;
var BigInteger = utils.jsbn.BigInteger;
var UInt160 = require('./uint160').UInt160;
var Seed = require('./seed').Seed;
var Currency = require('./currency').Currency;
//
// Amount class in the style of Java's BigInteger class
// http://docs.oracle.com/javase/1.3/docs/api/java/math/BigInteger.html
//
var BigNumber = require('./bignumber');
function Amount() {
// Json format:
// integer : XRP
// { 'value' : ..., 'currency' : ..., 'issuer' : ...}
this._value = new BigInteger(); // NaN for bad value. Always positive.
this._offset = 0; // Always 0 for XRP.
this._value = new BigNumber(NaN);
this._is_native = true; // Default to XRP. Only valid if value is not NaN.
this._is_negative = false;
this._currency = new Currency();
this._issuer = new UInt160();
};
}
var consts = {
currency_xns: 0,
currency_one: 1,
xns_precision: 6,
// BigInteger values prefixed with bi_.
bi_5: new BigInteger('5'),
bi_7: new BigInteger('7'),
bi_10: new BigInteger('10'),
bi_1e14: new BigInteger(String(1e14)),
bi_1e16: new BigInteger(String(1e16)),
bi_1e17: new BigInteger(String(1e17)),
bi_1e32: new BigInteger('100000000000000000000000000000000'),
bi_man_max_value: new BigInteger('9999999999999999'),
bi_man_min_value: new BigInteger('1000000000000000'),
bi_xns_max: new BigInteger('9000000000000000000'), // Json wire limit.
bi_xns_min: new BigInteger('-9000000000000000000'),// Json wire limit.
bi_xns_unit: new BigInteger('1000000'),
// bi_ prefix refers to "big integer"
bi_5: new BigNumber('5'),
bi_7: new BigNumber('7'),
bi_10: new BigNumber('10'),
bi_1e14: new BigNumber(String(1e14)),
bi_1e16: new BigNumber(String(1e16)),
bi_1e17: new BigNumber(String(1e17)),
bi_1e32: new BigNumber('100000000000000000000000000000000'),
bi_man_max_value: new BigNumber('9999999999999999'),
bi_man_min_value: new BigNumber('1000000000000000'),
bi_xns_max: new BigNumber('9000000000000000000'), // Json wire limit.
bi_xns_min: new BigNumber('-9000000000000000000'),// Json wire limit.
bi_xrp_max: new BigNumber('9000000000000'),
bi_xrp_min: new BigNumber('-9000000000000'),
bi_xns_unit: new BigNumber('1000000'),
cMinOffset: -96,
cMaxOffset: 80,
@@ -101,8 +93,16 @@ Amount.is_valid_full = function(j) {
Amount.NaN = function() {
var result = new Amount();
result._value = NaN;
return result;
result._value = new BigNumber(NaN); // should have no effect
return result; // but let's be careful
};
// be sure that _is_native is set properly BEFORE calling _set_value
Amount.prototype._set_value = function(value, roundingMode) {
assert(value instanceof BigNumber);
this._value = value.isZero() && value.isNegative() ? value.negated() : value;
this.canonicalize(roundingMode);
this._check_limits();
};
// Returns a new value which is the absolute value of this.
@@ -110,170 +110,47 @@ Amount.prototype.abs = function() {
return this.clone(this.is_negative());
};
// Result in terms of this' currency and issuer.
Amount.prototype.add = function(v) {
var result;
Amount.prototype.add = function(addend) {
var addendAmount = Amount.from_json(addend);
v = Amount.from_json(v);
if (!this.is_comparable(v)) {
result = Amount.NaN();
} else if (v.is_zero()) {
result = this;
} else if (this.is_zero()) {
result = v.clone();
result._is_native = this._is_native;
result._currency = this._currency;
result._issuer = this._issuer;
} else if (this._is_native) {
result = new Amount();
var v1 = this._is_negative ? this._value.negate() : this._value;
var v2 = v._is_negative ? v._value.negate() : v._value;
var s = v1.add(v2);
result._is_negative = s.compareTo(BigInteger.ZERO) < 0;
result._value = result._is_negative ? s.negate() : s;
result._currency = this._currency;
result._issuer = this._issuer;
} else {
var v1 = this._is_negative ? this._value.negate() : this._value;
var o1 = this._offset;
var v2 = v._is_negative ? v._value.negate() : v._value;
var o2 = v._offset;
while (o1 < o2) {
v1 = v1.divide(Amount.bi_10);
o1 += 1;
if (!this.is_comparable(addendAmount)) {
return Amount.NaN();
}
while (o2 < o1) {
v2 = v2.divide(Amount.bi_10);
o2 += 1;
}
result = new Amount();
result._is_native = false;
result._offset = o1;
result._value = v1.add(v2);
result._is_negative = result._value.compareTo(BigInteger.ZERO) < 0;
if (result._is_negative) {
result._value = result._value.negate();
}
result._currency = this._currency;
result._issuer = this._issuer;
result.canonicalize();
}
return result;
return this._copy(this._value.plus(addendAmount._value));
};
// Result in terms of this currency and issuer.
Amount.prototype.subtract = function(v) {
Amount.prototype.subtract = function(subtrahend) {
// Correctness over speed, less code has less bugs, reuse add code.
return this.add(Amount.from_json(v).negate());
return this.add(Amount.from_json(subtrahend).negate());
};
// Result in terms of this' currency and issuer.
// XXX Diverges from cpp.
Amount.prototype.multiply = function(v) {
var result;
v = Amount.from_json(v);
if (this.is_zero()) {
result = this;
} else if (v.is_zero()) {
result = this.clone();
result._value = BigInteger.ZERO;
} else {
var v1 = this._value;
var o1 = this._offset;
var v2 = v._value;
var o2 = v._offset;
if (this.is_native()) {
while (v1.compareTo(Amount.bi_man_min_value) < 0) {
v1 = v1.multiply(Amount.bi_10);
o1 -= 1;
}
}
if (v.is_native()) {
while (v2.compareTo(Amount.bi_man_min_value) < 0) {
v2 = v2.multiply(Amount.bi_10);
o2 -= 1;
}
}
result = new Amount();
result._offset = o1 + o2 + 14;
result._value = v1.multiply(v2).divide(Amount.bi_1e14).add(Amount.bi_7);
result._is_native = this._is_native;
result._is_negative = this._is_negative !== v._is_negative;
result._currency = this._currency;
result._issuer = this._issuer;
result.canonicalize();
}
return result;
Amount.prototype.multiply = function(multiplicand) {
var multiplicandAmount = Amount.from_json(multiplicand);
// TODO: probably should just multiply by multiplicandAmount._value
var multiplyBy = multiplicandAmount.is_native() ?
multiplicandAmount._value.times(Amount.bi_xns_unit)
: multiplicandAmount._value;
return this._copy(this._value.times(multiplyBy));
};
// Result in terms of this' currency and issuer.
Amount.prototype.divide = function(d) {
var result;
d = Amount.from_json(d);
if (d.is_zero()) {
Amount.prototype.divide = function(divisor) {
var divisorAmount = Amount.from_json(divisor);
if (!this.is_valid()) {
throw new Error('Invalid dividend');
}
if (!divisorAmount.is_valid()) {
throw new Error('Invalid divisor');
}
if (divisorAmount.is_zero()) {
throw new Error('divide by zero');
}
if (this.is_zero()) {
result = this;
} else if (!this.is_valid()) {
throw new Error('Invalid dividend');
} else if (!d.is_valid()) {
throw new Error('Invalid divisor');
} else {
var _n = this;
if (_n.is_native()) {
_n = _n.clone();
while (_n._value.compareTo(Amount.bi_man_min_value) < 0) {
_n._value = _n._value.multiply(Amount.bi_10);
_n._offset -= 1;
}
}
var _d = d;
if (_d.is_native()) {
_d = _d.clone();
while (_d._value.compareTo(Amount.bi_man_min_value) < 0) {
_d._value = _d._value.multiply(Amount.bi_10);
_d._offset -= 1;
}
}
result = new Amount();
result._offset = _n._offset - _d._offset - 17;
result._value = _n._value.multiply(Amount.bi_1e17).divide(_d._value).add(Amount.bi_5);
result._is_native = _n._is_native;
result._is_negative = _n._is_negative !== _d._is_negative;
result._currency = _n._currency;
result._issuer = _n._issuer;
result.canonicalize();
}
return result;
// TODO: probably should just divide by divisorAmount._value
var divideBy = divisorAmount.is_native() ?
divisorAmount._value.times(Amount.bi_xns_unit)
: divisorAmount._value;
return this._copy(this._value.dividedBy(divideBy));
};
/**
@@ -307,8 +184,6 @@ Amount.prototype.ratio_human = function(denominator, opts) {
denominator = Amount.from_json(denominator);
}
denominator = Amount.from_json(denominator);
// If either operand is NaN, the result is NaN.
if (!numerator.is_valid() || !denominator.is_valid()) {
return Amount.NaN();
@@ -337,9 +212,7 @@ Amount.prototype.ratio_human = function(denominator, opts) {
//
// To compensate, we multiply the numerator by 10^xns_precision.
if (denominator._is_native) {
numerator = numerator.clone();
numerator._value = numerator._value.multiply(Amount.bi_xns_unit);
numerator.canonicalize();
numerator._set_value(numerator._value.times(Amount.bi_xns_unit));
}
return numerator.divide(denominator);
@@ -396,8 +269,7 @@ Amount.prototype.product_human = function(factor, opts) {
//
// See also Amount#ratio_human.
if (factor._is_native) {
product._value = product._value.divide(Amount.bi_xns_unit);
product.canonicalize();
product._set_value(product._value.dividedBy(Amount.bi_xns_unit));
}
return product;
@@ -409,10 +281,7 @@ Amount.prototype.product_human = function(factor, opts) {
* @private
*/
Amount.prototype._invert = function() {
this._value = Amount.bi_1e32.divide(this._value);
this._offset = -32 - this._offset;
this.canonicalize();
this._set_value((new BigNumber(1)).dividedBy(this._value));
return this;
};
@@ -423,7 +292,7 @@ Amount.prototype._invert = function() {
* inverse of the value.
*/
Amount.prototype.invert = function() {
return this.copy()._invert();
return this.clone()._invert();
};
/**
@@ -453,56 +322,35 @@ Amount.prototype.invert = function() {
* @returns {Amount}
* @throws {Error} if offset exceeds legal ranges, meaning the amount value is bigger than supported
*/
Amount.prototype.canonicalize = function() {
if (!(this._value instanceof BigInteger)) {
// NaN.
// nothing
} else if (this._is_native) {
// Native.
if (this._value.equals(BigInteger.ZERO)) {
this._offset = 0;
this._is_negative = false;
Amount.prototype.canonicalize = function(roundingMode) {
if (this._is_native) {
this._value = this._value.round(6, BigNumber.ROUND_DOWN);
} else {
// Normalize _offset to 0.
while (this._offset < 0) {
this._value = this._value.divide(Amount.bi_10);
this._offset += 1;
}
while (this._offset > 0) {
this._value = this._value.multiply(Amount.bi_10);
this._offset -= 1;
}
}
} else if (this.is_zero()) {
this._offset = Amount.cMinOffset;
this._is_negative = false;
if (roundingMode) {
var value = this._value;
this._value = BigNumber.withRoundingMode(roundingMode, function() {
return new BigNumber(value.toPrecision(16));
});
} else {
// Normalize mantissa to valid range.
while (this._value.compareTo(Amount.bi_man_min_value) < 0) {
this._value = this._value.multiply(Amount.bi_10);
this._offset -= 1;
}
while (this._value.compareTo(Amount.bi_man_max_value) > 0) {
this._value = this._value.divide(Amount.bi_10);
this._offset += 1;
this._value = new BigNumber(this._value.toPrecision(16));
}
}
};
// Make sure not bigger than supported. Throw if so.
if (this.is_negative() && this._offset < Amount.cMinOffset) {
Amount.prototype._check_limits = function() {
if (this._value.isNaN() || this._value.isZero()) {
return this;
}
if (!this._is_native) {
var absval = this._value.absoluteValue();
if (absval.lessThan((new BigNumber(Amount.min_value)).absoluteValue())) {
throw new Error('Exceeding min value of ' + Amount.min_value);
}
// Make sure not smaller than supported. Throw if so.
if (!this.is_negative() && this._offset > Amount.cMaxOffset) {
if (absval.greaterThan(new BigNumber(Amount.max_value))) {
throw new Error('Exceeding max value of ' + Amount.max_value);
}
}
return this;
};
@@ -510,61 +358,27 @@ Amount.prototype.clone = function(negate) {
return this.copyTo(new Amount(), negate);
};
Amount.prototype.compareTo = function(v) {
var result;
Amount.prototype._copy = function(value) {
var copy = this.clone();
copy._set_value(value);
return copy;
};
v = Amount.from_json(v);
if (!this.is_comparable(v)) {
result = Amount.NaN();
} else if (this._is_negative !== v._is_negative) {
// Different sign.
result = this._is_negative ? -1 : 1;
} else if (this._value.equals(BigInteger.ZERO)) {
// Same sign: positive.
result = v._value.equals(BigInteger.ZERO) ? 0 : -1;
} else if (v._value.equals(BigInteger.ZERO)) {
// Same sign: positive.
result = 1;
} else if (!this._is_native && this._offset > v._offset) {
result = this._is_negative ? -1 : 1;
} else if (!this._is_native && this._offset < v._offset) {
result = this._is_negative ? 1 : -1;
} else {
result = this._value.compareTo(v._value);
if (result > 0) {
result = this._is_negative ? -1 : 1;
} else if (result < 0) {
result = this._is_negative ? 1 : -1;
Amount.prototype.compareTo = function(to) {
var toAmount = Amount.from_json(to);
if (!this.is_comparable(toAmount)) {
return Amount.NaN();
}
}
return result;
return this._value.comparedTo(toAmount._value);
};
// Make d a copy of this. Returns d.
// Modification of objects internally refered to is not allowed.
Amount.prototype.copyTo = function(d, negate) {
if (typeof this._value === 'object') {
this._value.copyTo(d._value);
} else {
d._value = this._value;
}
d._offset = this._offset;
d._value = negate ? this._value.negated() : this._value;
d._is_native = this._is_native;
d._is_negative = negate
? !this._is_negative // Negating.
: this._is_negative; // Just copying.
d._currency = this._currency;
d._issuer = this._issuer;
// Prevent negative zero
if (d.is_zero()) {
d._is_negative = false;
}
return d;
};
@@ -577,20 +391,16 @@ Amount.prototype.equals = function(d, ignore_issuer) {
return this.equals(Amount.from_json(d));
}
var result = !((!this.is_valid() || !d.is_valid())
|| (this._is_native !== d._is_native)
|| (!this._value.equals(d._value) || this._offset !== d._offset)
|| (this._is_negative !== d._is_negative)
|| (!this._is_native && (!this._currency.equals(d._currency) || !ignore_issuer && !this._issuer.equals(d._issuer))));
return result;
return this.is_valid() && d.is_valid()
&& this._is_native === d._is_native
&& this._value.equals(d._value)
&& (this._is_native || (this._currency.equals(d._currency)
&& (ignore_issuer || this._issuer.equals(d._issuer))));
};
// True if Amounts are valid and both native or non-native.
Amount.prototype.is_comparable = function(v) {
return this._value instanceof BigInteger
&& v._value instanceof BigInteger
&& this._is_native === v._is_native;
return this.is_valid() && v.is_valid() && this._is_native === v._is_native;
};
Amount.prototype.is_native = function() {
@@ -598,9 +408,7 @@ Amount.prototype.is_native = function() {
};
Amount.prototype.is_negative = function() {
return this._value instanceof BigInteger
? this._is_negative
: false; // NaN is not negative
return this._value.isNegative();
};
Amount.prototype.is_positive = function() {
@@ -609,7 +417,7 @@ Amount.prototype.is_positive = function() {
// Only checks the value. Not the currency and issuer.
Amount.prototype.is_valid = function() {
return this._value instanceof BigInteger;
return !this._value.isNaN();
};
Amount.prototype.is_valid_full = function() {
@@ -617,7 +425,7 @@ Amount.prototype.is_valid_full = function() {
};
Amount.prototype.is_zero = function() {
return this._value instanceof BigInteger ? this._value.equals(BigInteger.ZERO) : false;
return this._value.isZero();
};
Amount.prototype.issuer = function() {
@@ -629,23 +437,6 @@ Amount.prototype.negate = function() {
return this.clone('NEGATE');
};
/**
* Invert this amount and return the new value.
*
* Creates a new Amount object as a copy of the current one (including the same
* unit (currency & issuer), inverts it (1/x) and returns the result.
*/
Amount.prototype.invert = function() {
var one = this.clone();
one._value = BigInteger.ONE;
one._offset = 0;
one._is_negative = false;
one.canonicalize();
return one.ratio_human(this);
};
/**
* Tries to correctly interpret an amount as entered by a user.
*
@@ -659,74 +450,54 @@ Amount.prototype.invert = function() {
*
* The regular expression below matches above cases, broken down for better understanding:
*
* ^\s* // start with any amount of whitespace
* ([A-z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217
* \s* // any amount of whitespace
* (-)? // optional dash
* (\d+) // 1 or more digits
* (?:\.(\d*))? // optional . character with any amount of digits
* \s* // any amount of whitespace
* ([A-z]{3}|[0-9]{3})? // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217
* \s* // any amount of whitespace
* $ // end of string
*
*/
Amount.human_RE_hex = /^\s*(-)?(\d+)(?:\.(\d*))?\s*([a-fA-F0-9]{40})\s*$/;
Amount.human_RE = /^\s*([A-z]{3}|[0-9]{3})?\s*(-)?(\d+)(?:\.(\d*))?\s*([A-z]{3}|[0-9]{3})?\s*$/;
Amount.prototype.parse_human = function(j, opts) {
opts = opts || {};
var integer;
var fraction;
var hex_RE = /^[a-fA-F0-9]{40}$/;
var currency_RE = /^([a-zA-Z]{3}|[0-9]{3})$/;
var value;
var currency;
var precision = null;
// first check if it's a hex formatted currency
var matches = String(j).match(Amount.human_RE_hex);
if (matches && matches.length === 5 && matches[4]) {
integer = matches[2];
fraction = matches[3] || '';
currency = matches[4];
this._is_negative = Boolean(matches[1]);
}
var words = j.split(' ').filter(function(word) { return word !== ''; });
if (integer === void(0) && currency === void(0)) {
var m = String(j).match(Amount.human_RE);
if (m) {
currency = m[5] || m[1] || 'XRP';
integer = m[5] && m[1] ? m[1] + '' + m[3] : (m[3] || '0');
fraction = m[4] || '';
this._is_negative = Boolean(m[2]);
}
}
if (integer) {
currency = currency.toUpperCase();
this._value = new BigInteger(integer);
this.set_currency(currency);
// XRP have exactly six digits of precision
if (currency === 'XRP') {
fraction = fraction.slice(0, 6);
while (fraction.length < 6) {
fraction += '0';
}
this._is_native = true;
this._value = this._value.multiply(Amount.bi_xns_unit).add(new BigInteger(fraction));
if (words.length === 1) {
if (isFinite(words[0])) {
value = words[0];
currency = 'XRP';
} else {
// Other currencies have arbitrary precision
fraction = fraction.replace(/0+$/, '');
precision = fraction.length;
this._is_native = false;
var multiplier = Amount.bi_10.clone().pow(precision);
this._value = this._value.multiply(multiplier).add(new BigInteger(fraction));
this._offset = -precision;
this.canonicalize();
value = words[0].slice(0, -3);
currency = words[0].slice(-3);
if (!(isFinite(value) && currency.match(currency_RE))) {
return Amount.NaN();
}
}
} else if (words.length === 2) {
if (isFinite(words[0]) && words[1].match(hex_RE)) {
value = words[0];
currency = words[1];
} else if (words[0].match(currency_RE) && isFinite(words[1])) {
value = words[1];
currency = words[0];
} else if (isFinite(words[0]) && words[1].match(currency_RE)) {
value = words[0];
currency = words[1];
} else {
return Amount.NaN();
}
} else {
return Amount.NaN();
}
currency = currency.toUpperCase();
this.set_currency(currency);
this._is_native = (currency === 'XRP');
this._set_value(new BigNumber(value));
// Apply interest/demurrage
if (opts.reference_date && this._currency.has_interest()) {
@@ -742,21 +513,15 @@ Amount.prototype.parse_human = function(j, opts) {
var interestTempAmount = Amount.from_json(''+interest+'/1/1');
if (interestTempAmount.is_valid()) {
var ref = this.divide(interestTempAmount);
this._value = ref._value;
this._offset = ref._offset;
this._set_value(this.divide(interestTempAmount)._value);
}
}
} else {
this._value = NaN;
}
return this;
};
Amount.prototype.parse_issuer = function(issuer) {
this._issuer = UInt160.from_json(issuer);
return this;
};
@@ -798,29 +563,41 @@ Amount.prototype.parse_quality = function(quality, counterCurrency, counterIssue
var baseCurrency = Currency.from_json(opts.base_currency);
this._is_negative = false;
this._value = new BigInteger(quality.substring(quality.length-14), 16);
this._offset = parseInt(quality.substring(quality.length-16, quality.length-14), 16)-100;
var mantissa_hex = quality.substring(quality.length-14);
var offset_hex = quality.substring(quality.length-16, quality.length-14);
var mantissa = new BigNumber(mantissa_hex, 16);
var offset = parseInt(offset_hex, 16) - 100;
var value = new BigNumber(mantissa.toString() + 'e' + offset.toString());
this._currency = Currency.from_json(counterCurrency);
this._issuer = UInt160.from_json(counterIssuer);
this._is_native = this._currency.is_native();
var power = 0;
if (this._is_native) {
if (opts.inverse) {
power += 1;
} else {
power -= 1;
}
}
// Correct offset if xrp_as_drops option is not set and base currency is XRP
if (!opts.xrp_as_drops &&
baseCurrency.is_valid() &&
baseCurrency.is_native()) {
if (opts.inverse) {
this._offset -= 6;
power -= 1;
} else {
this._offset += 6;
power += 1;
}
}
if (opts.inverse) {
this._invert();
}
this.canonicalize();
var one = new BigNumber(1);
var adjusted = value.times(Amount.bi_xns_unit.toPower(power));
var newValue = opts.inverse ? one.dividedBy(adjusted) : adjusted;
this._set_value(newValue);
if (opts.reference_date && baseCurrency.is_valid() && baseCurrency.has_interest()) {
var interest = baseCurrency.get_interest_at(opts.reference_date);
@@ -829,9 +606,7 @@ Amount.prototype.parse_quality = function(quality, counterCurrency, counterIssue
var interestTempAmount = Amount.from_json(''+interest+'/1/1');
if (interestTempAmount.is_valid()) {
var v = this.divide(interestTempAmount);
this._value = v._value;
this._offset = v._offset;
this._set_value(this.divide(interestTempAmount)._value);
}
}
@@ -842,12 +617,7 @@ Amount.prototype.parse_number = function(n) {
this._is_native = false;
this._currency = Currency.from_json(1);
this._issuer = UInt160.from_json(1);
this._is_negative = n < 0 ? true : false;
this._value = new BigInteger(String(this._is_negative ? -n : n));
this._offset = 0;
this.canonicalize();
this._set_value(new BigNumber(n));
return this;
};
@@ -897,7 +667,7 @@ Amount.prototype.parse_json = function(j) {
break;
default:
this._value = NaN;
this._set_value(new BigNumber(NaN));
}
return this;
@@ -908,33 +678,20 @@ Amount.prototype.parse_json = function(j) {
// - float = with precision 6
// XXX Improvements: disallow leading zeros.
Amount.prototype.parse_native = function(j) {
var m;
if (typeof j === 'string') {
m = j.match(/^(-?)(\d*)(\.\d{0,6})?$/);
}
if (m) {
if (m[3] === void(0)) {
// Integer notation
this._value = new BigInteger(m[2]);
} else {
// Float notation : values multiplied by 1,000,000.
var int_part = (new BigInteger(m[2])).multiply(Amount.bi_xns_unit);
var fraction_part = (new BigInteger(m[3])).multiply(new BigInteger(String(Math.pow(10, 1+Amount.xns_precision-m[3].length))));
this._value = int_part.add(fraction_part);
}
if (typeof j === 'string' && j.match(/^-?\d*(\.\d{0,6})?$/)) {
var value = new BigNumber(j);
this._is_native = true;
this._offset = 0;
this._is_negative = !!m[1] && this._value.compareTo(BigInteger.ZERO) !== 0;
if (this._value.compareTo(Amount.bi_xns_max) > 0) {
this._value = NaN;
if (j.indexOf('.') >= 0) {
this._set_value(value);
} else {
this._set_value(value.dividedBy(Amount.bi_xns_unit));
}
// TODO: move this overflow check to canonicalize
if (this._value.abs().greaterThan(Amount.bi_xrp_max)) {
this._set_value(new BigNumber(NaN));
}
} else {
this._value = NaN;
this._set_value(new BigNumber(NaN));
}
return this;
@@ -944,62 +701,13 @@ Amount.prototype.parse_native = function(j) {
// Requires _currency to be set!
Amount.prototype.parse_value = function(j) {
this._is_native = false;
switch (typeof j) {
case 'number':
this._is_negative = j < 0;
this._value = new BigInteger(Math.abs(j));
this._offset = 0;
this.canonicalize();
break;
case 'string':
var i = j.match(/^(-?)(\d+)$/);
var d = !i && j.match(/^(-?)(\d*)\.(\d*)$/);
var e = !e && j.match(/^(-?)(\d*)e(-?\d+)$/);
if (e) {
// e notation
this._value = new BigInteger(e[2]);
this._offset = parseInt(e[3]);
this._is_negative = !!e[1];
this.canonicalize();
} else if (d) {
// float notation
var integer = new BigInteger(d[2]);
var fraction = new BigInteger(d[3]);
var precision = d[3].length;
this._value = integer.multiply(Amount.bi_10.clone().pow(precision)).add(fraction);
this._offset = -precision;
this._is_negative = !!d[1];
this.canonicalize();
} else if (i) {
// integer notation
this._value = new BigInteger(i[2]);
this._offset = 0;
this._is_negative = !!i[1];
this.canonicalize();
} else {
this._value = NaN;
}
break;
default:
this._value = j instanceof BigInteger ? j : NaN;
}
this._set_value(new BigNumber(j), BigNumber.ROUND_DOWN);
return this;
};
Amount.prototype.set_currency = function(c) {
this._currency = Currency.from_json(c);
this._is_native = this._currency.is_native();
return this;
};
@@ -1020,37 +728,43 @@ Amount.prototype.to_number = function(allow_nan) {
// Convert only value to JSON wire format.
Amount.prototype.to_text = function(allow_nan) {
var result = NaN;
if (this._is_native && this._value.abs().greaterThan(Amount.bi_xrp_max)) {
return '0';
}
if (this._value.isNaN() && !allow_nan) {
return '0';
} else if (this._value.isNaN()) {
return NaN; // TODO: why does to_text return NaN? return 'NaN'?
}
if (this._is_native) {
if (this.is_valid() && this._value.compareTo(Amount.bi_xns_max) <= 0){
result = this._value.toString();
if (this.is_valid() && this._value.lessThanOrEqualTo(Amount.bi_xns_max)){
return this._value.times(Amount.bi_xns_unit).toString();
} else {
return NaN; // TODO: why does to_text return NaN? return 'NaN'?
}
} else if (this.is_zero()) {
result = '0';
} else if (this._offset && (this._offset < -25 || this._offset > -4)) {
}
// not native
var offset = this._value.e - 15;
var sign = this._value.isNegative() ? '-' : '';
var mantissa = utils.getMantissaDecimalString(this._value.absoluteValue());
if (offset !== 0 && (offset < -25 || offset > -4)) {
// Use e notation.
// XXX Clamp output.
result = this._value.toString() + 'e' + this._offset;
return sign + mantissa.toString() + 'e' + offset.toString();
} else {
var val = '000000000000000000000000000' + this._value.toString() + '00000000000000000000000';
var pre = val.substring(0, this._offset + 43);
var post = val.substring(this._offset + 43);
var val = '000000000000000000000000000' + mantissa.toString()
+ '00000000000000000000000';
var pre = val.substring(0, offset + 43);
var post = val.substring(offset + 43);
var s_pre = pre.match(/[1-9].*$/); // Everything but leading zeros.
var s_post = post.match(/[1-9]0*$/); // Last non-zero plus trailing zeros.
result = ''
+ (s_pre ? s_pre[0] : '0')
return sign + (s_pre ? s_pre[0] : '0')
+ (s_post ? '.' + post.substring(0, 1 + post.length - s_post[0].length) : '');
}
if (!allow_nan && typeof result === 'number' && isNaN(result)) {
result = '0';
} else if (this._is_negative) {
result = '-' + result;
}
return result;
};
/**
@@ -1131,15 +845,11 @@ Amount.prototype.to_human = function(opts) {
ref = this.applyInterest(opts.reference_date);
}
var order = ref._is_native ? Amount.xns_precision : -ref._offset;
var denominator = Amount.bi_10.clone().pow(order);
var int_part = ref._value.divide(denominator).toString();
var fraction_part = ref._value.mod(denominator).toString();
// Add leading zeros to fraction
while (fraction_part.length < order) {
fraction_part = '0' + fraction_part;
}
var isNegative = ref._value.isNegative();
var valueString = ref._value.abs().toString();
var parts = valueString.split('.');
var int_part = parts[0];
var fraction_part = parts.length === 2 ? parts[1] : '';
int_part = int_part.replace(/^0*/, '');
fraction_part = fraction_part.replace(/0*$/, '');
@@ -1208,7 +918,7 @@ Amount.prototype.to_human = function(opts) {
}
var formatted = '';
if (opts.signed && this._is_negative) {
if (opts.signed && isNegative) {
if (typeof opts.signed !== 'string') {
opts.signed = '-';
}
@@ -1250,11 +960,9 @@ Amount.prototype.to_json = function() {
};
Amount.prototype.to_text_full = function(opts) {
return this._value instanceof BigInteger
? this._is_native
return this._is_native
? this.to_human() + '/XRP'
: this.to_text() + '/' + this._currency.to_json() + '/' + this._issuer.to_json(opts)
: NaN;
: this.to_text() + '/' + this._currency.to_json() + '/' + this._issuer.to_json(opts);
};
// For debugging.
@@ -1276,10 +984,10 @@ Amount.prototype.not_equals_why = function(d, ignore_issuer) {
} else {
var type = this._is_native ? 'XRP' : 'Non-XRP';
if (!this._value.equals(d._value) || this._offset !== d._offset) {
result = type + ' value differs.';
} else if (this._is_negative !== d._is_negative) {
if (!this._value.isZero() && this._value.negated().equals(d._value)) {
result = type + ' sign differs.';
} else if (!this._value.equals(d._value)) {
result = type + ' value differs.';
} else if (!this._is_native) {
if (!this._currency.equals(d._currency)) {
result = 'Non-XRP currency differs.';

View File

@@ -2,8 +2,6 @@ var sjcl = require('./utils').sjcl;
var utils = require('./utils');
var extend = require('extend');
var BigInteger = utils.jsbn.BigInteger;
var Base = {};
var alphabets = Base.alphabets = {
@@ -25,33 +23,142 @@ extend(Base, {
function sha256(bytes) {
return sjcl.codec.bytes.fromBits(sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
};
}
function sha256hash(bytes) {
return sha256(sha256(bytes));
};
}
function divmod58(number, startAt) {
var remainder = 0;
for (var i = startAt; i < number.length; i++) {
var digit256 = number[i] & 0xFF;
var temp = remainder * 256 + digit256;
number[i] = (temp / 58);
remainder = temp % 58;
}
return remainder;
}
function divmod256(number58, startAt) {
var remainder = 0;
for (var i = startAt; i < number58.length; i++) {
var digit58 = number58[i] & 0xFF;
var temp = remainder * 58 + digit58;
number58[i] = (temp / 256);
remainder = temp % 256;
}
return remainder;
}
function encodeString (alphabet, input) {
if (input.length == 0) {
return [];
}
// we need to copy the buffer for calc
scratch = input.slice();
// Count leading zeroes.
var zeroCount = 0;
while (zeroCount < scratch.length &&
scratch[zeroCount] == 0)
++zeroCount;
// The actual encoding.
var out = new Array(scratch.length * 2);
var j = out.length;
var startAt = zeroCount;
while (startAt < scratch.length) {
var mod = divmod58(scratch, startAt);
if (scratch[startAt] == 0) {
++startAt;
}
out[--j] = alphabet[mod];
}
// Strip extra 'r' if there are some after decoding.
while (j < out.length && out[j] == alphabet[0]) ++j;
// Add as many leading 'r' as there were leading zeros.
while (--zeroCount >= 0) out[--j] = alphabet[0];
while(j--) out.shift();
return out.join('');
}
function decodeString(indexes, input) {
var isString = typeof input === 'string';
if (input.length == 0) {
return [];
}
input58 = new Array(input.length);
// Transform the String to a base58 byte sequence
for (var i = 0; i < input.length; ++i) {
if (isString) {
var c = input.charCodeAt(i);
}
var digit58 = -1;
if (c >= 0 && c < 128) {
digit58 = indexes[c];
}
if (digit58 < 0) {
throw new Error("Illegal character " + c + " at " + i);
}
input58[i] = digit58;
}
// Count leading zeroes
var zeroCount = 0;
while (zeroCount < input58.length && input58[zeroCount] == 0) {
++zeroCount;
}
// The encoding
out = utils.arraySet(input.length, 0);
var j = out.length;
var startAt = zeroCount;
while (startAt < input58.length) {
var mod = divmod256(input58, startAt);
if (input58[startAt] == 0) {
++startAt;
}
out[--j] = mod;
}
// Do no add extra leading zeroes, move j to first non null byte.
while (j < out.length && (out[j] == 0)) ++j;
j -= zeroCount;
while(j--) out.shift();
return out;
}
function Base58(alphabet) {
var indexes = utils.arraySet(128, -1);
for (var i = 0; i < alphabet.length; i++) {
indexes[alphabet.charCodeAt(i)] = i;
}
return {
decode: decodeString.bind(null, indexes),
encode: encodeString.bind(null, alphabet)
};
}
Base.encoders = {};
Object.keys(alphabets).forEach(function(alphabet){
Base.encoders[alphabet] = Base58(alphabets[alphabet]);
});
// --> input: big-endian array of bytes.
// <-- string at least as long as input.
Base.encode = function(input, alpha) {
var alphabet = alphabets[alpha || 'ripple'];
var bi_base = new BigInteger(String(alphabet.length));
var bi_q = new BigInteger();
var bi_r = new BigInteger();
var bi_value = new BigInteger(input);
var buffer = [];
while (bi_value.compareTo(BigInteger.ZERO) > 0) {
bi_value.divRemTo(bi_base, bi_q, bi_r);
bi_q.copyTo(bi_value);
buffer.push(alphabet[bi_r.intValue()]);
}
for (var i=0; i !== input.length && !input[i]; i += 1) {
buffer.push(alphabet[0]);
}
return buffer.reverse().join('');
return this.encoders[alpha || 'ripple'].encode(input);
};
// --> input: String
@@ -60,48 +167,12 @@ Base.decode = function(input, alpha) {
if (typeof input !== 'string') {
return void(0);
}
var alphabet = alphabets[alpha || 'ripple'];
var bi_base = new BigInteger(String(alphabet.length));
var bi_value = new BigInteger();
var i;
for (i = 0; i !== input.length && input[i] === alphabet[0]; i += 1) {
try {
return this.encoders[alpha || 'ripple'].decode(input);
}
for (; i !== input.length; i += 1) {
var v = alphabet.indexOf(input[i]);
if (v < 0) {
return void(0);
catch(e) {
return (void 0);
}
var r = new BigInteger();
r.fromInt(v);
bi_value = bi_value.multiply(bi_base).add(r);
}
// toByteArray:
// - Returns leading zeros!
// - Returns signed bytes!
var bytes = bi_value.toByteArray().map(function(b) { return b ? b < 0 ? 256+b : b : 0; });
var extra = 0;
while (extra !== bytes.length && !bytes[extra]) {
extra += 1;
}
if (extra) {
bytes = bytes.slice(extra);
}
var zeros = 0;
while (zeros !== input.length && input[zeros] === alphabet[0]) {
zeros += 1;
}
return [].concat(utils.arraySet(zeros, 0), bytes);
};
Base.verify_checksum = function(bytes) {
@@ -129,7 +200,7 @@ Base.encode_check = function(version, input, alphabet) {
};
// --> input : String
// <-- NaN || BigInteger
// <-- NaN || sjcl.bn
Base.decode_check = function(version, input, alphabet) {
var buffer = Base.decode(input, alphabet);
@@ -163,7 +234,8 @@ Base.decode_check = function(version, input, alphabet) {
// intrepret the value as a negative number
buffer[0] = 0;
return new BigInteger(buffer.slice(0, -4), 256);
return sjcl.bn.fromBits (
sjcl.codec.bytes.toBits(buffer.slice(0, -4)));
};
exports.Base = Base;

View File

@@ -0,0 +1,33 @@
var BigNumber = require('bignumber.js');
var extend = require('extend');
function BigNumberWrapper(value, base) {
// reset config every time a BigNumber is instantiated so that
// these global settings won't be overridden if another file tries
// to set them at require-time.
BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_HALF_UP,
DECIMAL_PLACES: 40 });
BigNumber.call(this, value, base);
}
extend(BigNumberWrapper, BigNumber); // copy class static properties
BigNumberWrapper.prototype = BigNumber.prototype;
BigNumberWrapper.config = function() {
throw new Error('BigNumber.config may only be called from bignumber.js');
};
BigNumberWrapper.withRoundingMode = function(roundingMode, func) {
var config = BigNumber.config();
var oldRoundingMode = config.ROUNDING_MODE;
config.ROUNDING_MODE = roundingMode;
BigNumber.config(config);
try {
return func();
} finally {
config.ROUNDING_MODE = oldRoundingMode;
BigNumber.config(config);
}
};
module.exports = BigNumberWrapper;

View File

@@ -308,7 +308,7 @@ Currency.prototype.get_interest_percentage_at = function(referenceDate, decimals
// currency data, since there are some values that are invalid.
//
//Currency.prototype.is_valid = function() {
// return this._value instanceof BigInteger && ...;
// return UInt.prototype.is_valid() && ...;
//};
Currency.prototype.to_json = function(opts) {

View File

@@ -29,7 +29,6 @@ exports.RangeSet = require('./rangeset').RangeSet;
// the official client, it makes sense to expose the SJCL instance so we don't
// have to include it twice.
exports.sjcl = require('./utils').sjcl;
exports.jsbn = require('./utils').jsbn;
exports.types = require('./serializedtypes');
exports.config = require('./config');

View File

@@ -6,8 +6,6 @@ var extend = require('extend');
var utils = require('./utils');
var sjcl = utils.sjcl;
var BigInteger = utils.jsbn.BigInteger;
var Base = require('./base').Base;
var UInt = require('./uint').UInt;
var UInt256 = require('./uint256').UInt256;
@@ -15,7 +13,6 @@ var UInt160 = require('./uint160').UInt160;
var KeyPair = require('./keypair').KeyPair;
var Seed = extend(function () {
// Internal form: NaN or BigInteger
this._curve = sjcl.ecc.curves.k256;
this._value = NaN;
}, UInt);
@@ -60,7 +57,7 @@ Seed.prototype.parse_passphrase = function (j) {
};
Seed.prototype.to_json = function () {
if (!(this._value instanceof BigInteger)) {
if (!(this.is_valid())) {
return NaN;
}

View File

@@ -1,13 +1,12 @@
var _ = require('lodash');
var assert = require('assert');
var extend = require('extend');
var binformat = require('./binformat');
var stypes = require('./serializedtypes');
var UInt256 = require('./uint256').UInt256;
var Crypt = require('./crypt').Crypt;
var utils = require('./utils');
var sjcl = utils.sjcl;
var BigInteger = utils.jsbn.BigInteger;
var TRANSACTION_TYPES = { };
@@ -27,6 +26,13 @@ Object.keys(binformat.ter).forEach(function(key) {
TRANSACTION_RESULTS[binformat.ter[key]] = key;
});
function normalize_sjcl_bn_hex(string) {
var hex = string.slice(2); // remove '0x' prefix
// now strip leading zeros
var i = _.findIndex(hex, function(c) { return c !== '0'; });
return i >= 0 ? hex.slice(i) : '0';
}
function SerializedObject(buf) {
if (Array.isArray(buf) || (Buffer && Buffer.isBuffer(buf)) ) {
this.buffer = buf;
@@ -38,11 +44,11 @@ function SerializedObject(buf) {
throw new Error('Invalid buffer passed.');
}
this.pointer = 0;
};
}
SerializedObject.from_json = function(obj) {
// Create a copy of the object so we don't modify it
var obj = extend(true, {}, obj);
obj = extend(true, {}, obj);
var so = new SerializedObject();
var typedef;
@@ -103,8 +109,8 @@ SerializedObject.check_no_missing_fields = function(typedef, obj) {
if (binformat.REQUIRED === requirement && obj[field] === void(0)) {
missing_fields.push(field);
};
};
}
}
if (missing_fields.length > 0) {
var object_name;
@@ -114,12 +120,12 @@ SerializedObject.check_no_missing_fields = function(typedef, obj) {
} else if (obj.LedgerEntryType != null){
object_name = SerializedObject.lookup_type_le(obj.LedgerEntryType);
} else {
object_name = "TransactionMetaData";
object_name = 'TransactionMetaData';
}
throw new Error(object_name + " is missing fields: " +
throw new Error(object_name + ' is missing fields: ' +
JSON.stringify(missing_fields));
};
}
};
SerializedObject.prototype.append = function(bytes) {
@@ -152,7 +158,7 @@ function readOrPeek(advance) {
return result;
};
};
}
SerializedObject.prototype.read = readOrPeek(true);
@@ -209,8 +215,8 @@ SerializedObject.jsonify_structure = function(structure, field_name) {
if (typeof structure.to_json === 'function') {
output = structure.to_json();
} else if (structure instanceof BigInteger) {
output = ('0000000000000000' + structure.toString(16).toUpperCase()).slice(-16);
} else if (structure instanceof sjcl.bn) {
output = ('0000000000000000' + normalize_sjcl_bn_hex(structure.toString()).toUpperCase()).slice(-16);
} else {
//new Array or Object
output = new structure.constructor();
@@ -250,7 +256,7 @@ SerializedObject.prototype.hash = function(prefix) {
var sign_buffer = new SerializedObject();
// Add hashing prefix
if ("undefined" !== typeof prefix) {
if ('undefined' !== typeof prefix) {
stypes.Int32.serialize(sign_buffer, prefix);
}
@@ -312,7 +318,7 @@ SerializedObject.sort_typedef = function(typedef) {
function sort_field_compare(a, b) {
// Sort by type id first, then by field id
return a[3] !== b[3] ? stypes[a[3]].id - stypes[b[3]].id : a[2] - b[2];
};
}
return typedef.sort(sort_field_compare);
};

View File

@@ -11,6 +11,7 @@ var extend = require('extend');
var binformat = require('./binformat');
var utils = require('./utils');
var sjcl = utils.sjcl;
var BigNumber = require('./bignumber');
var UInt128 = require('./uint128').UInt128;
var UInt160 = require('./uint160').UInt160;
@@ -21,59 +22,48 @@ var amount = require('./amount');
var Amount = amount.Amount;
var Currency = amount.Currency;
// Shortcuts
var hex = sjcl.codec.hex;
var bytes = sjcl.codec.bytes;
var utf8 = sjcl.codec.utf8String;
var BigInteger = utils.jsbn.BigInteger;
var SerializedType = function (methods) {
extend(this, methods);
};
function isNumber(val) {
return typeof val === 'number' && isFinite(val);
};
}
function isString(val) {
return typeof val === 'string';
};
}
function isHexInt64String(val) {
return isString(val) && /^[0-9A-F]{0,16}$/i.test(val);
};
}
function isCurrencyString(val) {
return isString(val) && /^[A-Z0-9]{3}$/.test(val);
};
function isBigInteger(val) {
return val instanceof BigInteger;
};
function serializeHex(so, hexData, noLength) {
var byteData = bytes.fromBits(hex.toBits(hexData));
function serializeBits(so, bits, noLength) {
var byteData = sjcl.codec.bytes.fromBits(bits);
if (!noLength) {
SerializedType.serialize_varint(so, byteData.length);
}
so.append(byteData);
};
}
function serializeHex(so, hexData, noLength) {
serializeBits(so, sjcl.codec.hex.toBits(hexData), noLength);
}
/**
* parses bytes as hex
*/
function convertByteArrayToHex (byte_array) {
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array)).toUpperCase();
};
}
function convertStringToHex(string) {
return hex.fromBits(utf8.toBits(string)).toUpperCase();
var utf8String = sjcl.codec.utf8String.toBits(string);
return sjcl.codec.hex.fromBits(utf8String).toUpperCase();
}
function convertHexToString(hexString) {
return utf8.fromBits(hex.toBits(hexString));
return sjcl.codec.utf8String.fromBits(sjcl.codec.hex.toBits(hexString));
}
SerializedType.serialize_varint = function (so, val) {
@@ -130,7 +120,7 @@ function convertIntegerToByteArray(val, bytes) {
}
if (val < 0 || val >= Math.pow(256, bytes)) {
throw new Error('Value out of bounds');
throw new Error('Value out of bounds ');
}
var newBytes = [ ];
@@ -140,7 +130,7 @@ function convertIntegerToByteArray(val, bytes) {
}
return newBytes;
};
}
// Convert a certain number of bytes from the serialized object ('so') into an integer.
function readAndSum(so, bytes) {
@@ -157,7 +147,7 @@ function readAndSum(so, bytes) {
// Convert to unsigned integer
return sum >>> 0;
};
}
var STInt8 = exports.Int8 = new SerializedType({
serialize: function (so, val) {
@@ -201,41 +191,25 @@ var STInt64 = exports.Int64 = new SerializedType({
if (val < 0) {
throw new Error('Negative value for unsigned Int64 is invalid.');
}
bigNumObject = new BigInteger(String(val), 10);
bigNumObject = new sjcl.bn(val, 10);
} else if (isString(val)) {
if (!isHexInt64String(val)) {
throw new Error('Not a valid hex Int64.');
}
bigNumObject = new BigInteger(val, 16);
} else if (isBigInteger(val)) {
if (val.compareTo(BigInteger.ZERO) < 0) {
bigNumObject = new sjcl.bn(val, 16);
} else if (val instanceof sjcl.bn) {
if (!val.greaterEquals(0)) {
throw new Error('Negative value for unsigned Int64 is invalid.');
}
bigNumObject = val;
} else {
throw new Error('Invalid type for Int64');
}
var hex = bigNumObject.toString(16);
if (hex.length > 16) {
throw new Error('Int64 is too large');
}
while (hex.length < 16) {
hex = '0' + hex;
}
serializeHex(so, hex, true); //noLength = true
serializeBits(so, bigNumObject.toBits(64), true); //noLength = true
},
parse: function (so) {
var bytes = so.read(8);
// We need to add a 0, so if the high bit is set it won't think it's a
// pessimistic numeric fraek. What doth lief?
var result = new BigInteger([0].concat(bytes), 256);
assert(result instanceof BigInteger);
return result;
return sjcl.bn.fromBits(sjcl.codec.bytes.toBits(bytes));
}
});
@@ -247,7 +221,7 @@ var STHash128 = exports.Hash128 = new SerializedType({
if (!hash.is_valid()) {
throw new Error('Invalid Hash128');
}
serializeHex(so, hash.to_hex(), true); //noLength = true
serializeBits(so, hash.to_bits(), true); //noLength = true
},
parse: function (so) {
return UInt128.from_bytes(so.read(16));
@@ -262,7 +236,7 @@ var STHash256 = exports.Hash256 = new SerializedType({
if (!hash.is_valid()) {
throw new Error('Invalid Hash256');
}
serializeHex(so, hash.to_hex(), true); //noLength = true
serializeBits(so, hash.to_bits(), true); //noLength = true
},
parse: function (so) {
return UInt256.from_bytes(so.read(32));
@@ -277,7 +251,7 @@ var STHash160 = exports.Hash160 = new SerializedType({
if (!hash.is_valid()) {
throw new Error('Invalid Hash160');
}
serializeHex(so, hash.to_hex(), true); //noLength = true
serializeBits(so, hash.to_bits(), true); //noLength = true
},
parse: function (so) {
return UInt160.from_bytes(so.read(20));
@@ -288,7 +262,7 @@ STHash160.id = 17;
// Internal
var STCurrency = new SerializedType({
serialize: function (so, val, xrp_as_ascii) {
serialize: function (so, val) {
var currencyData = val.to_bytes();
if (!currencyData) {
@@ -317,11 +291,14 @@ var STAmount = exports.Amount = new SerializedType({
throw new Error('Not a valid Amount object.');
}
var value = new BigNumber(amount.to_text());
var offset = value.e - 15;
// Amount (64-bit integer)
var valueBytes = utils.arraySet(8, 0);
if (amount.is_native()) {
var valueHex = amount._value.toString(16);
var valueHex = value.absoluteValue().toString(16);
// Enforce correct length (64 bits)
if (valueHex.length > 16) {
@@ -332,7 +309,7 @@ var STAmount = exports.Amount = new SerializedType({
valueHex = '0' + valueHex;
}
valueBytes = bytes.fromBits(hex.toBits(valueHex));
valueBytes = sjcl.codec.bytes.fromBits(sjcl.codec.hex.toBits(valueHex));
// Clear most significant two bits - these bits should already be 0 if
// Amount enforces the range correctly, but we'll clear them anyway just
// so this code can make certain guarantees about the encoded value.
@@ -354,10 +331,16 @@ var STAmount = exports.Amount = new SerializedType({
}
// Next eight bits: offset/exponent
hi |= ((97 + amount._offset) & 0xff) << 22;
hi |= ((97 + offset) & 0xff) << 22;
// Remaining 54 bits: mantissa
hi |= amount._value.shiftRight(32).intValue() & 0x3fffff;
lo = amount._value.intValue() & 0xffffffff;
var mantissaDecimal = utils.getMantissaDecimalString(value.abs());
var mantissaHex = (new BigNumber(mantissaDecimal)).toString(16);
assert(mantissaHex.length <= 16,
'Mantissa hex representation ' + mantissaHex +
' exceeds the maximum length of 16');
hi |= parseInt(mantissaHex.slice(0, -8), 16) & 0x3fffff;
lo = parseInt(mantissaHex.slice(-8), 16);
}
valueBytes = sjcl.codec.bytes.fromBits([hi, lo]);
@@ -375,7 +358,6 @@ var STAmount = exports.Amount = new SerializedType({
}
},
parse: function (so) {
var amount = new Amount();
var value_bytes = so.read(8);
var is_zero = !(value_bytes[0] & 0x7f);
@@ -383,6 +365,8 @@ var STAmount = exports.Amount = new SerializedType({
is_zero = is_zero && !value_bytes[i];
}
var is_negative = !is_zero && !(value_bytes[0] & 0x40);
if (value_bytes[0] & 0x80) {
//non-native
var currency = STCurrency.parse(so);
@@ -392,26 +376,23 @@ var STAmount = exports.Amount = new SerializedType({
var offset = ((value_bytes[0] & 0x3f) << 2) + (value_bytes[1] >>> 6) - 97;
var mantissa_bytes = value_bytes.slice(1);
mantissa_bytes[0] &= 0x3f;
var value = new BigInteger(mantissa_bytes, 256);
var mantissa = new BigNumber(utils.arrayToHex(mantissa_bytes), 16);
var sign = is_negative ? '-' : '';
var valueString = sign + mantissa.toString() + 'e' + offset.toString();
if (value.equals(BigInteger.ZERO) && !is_zero ) {
throw new Error('Invalid zero representation');
}
amount._value = value;
amount._offset = offset;
amount._currency = currency;
amount._issuer = issuer;
amount._is_native = false;
return Amount.from_json({
currency: currency,
issuer: issuer.to_json(),
value: valueString
});
} else {
//native
var integer_bytes = value_bytes.slice();
integer_bytes[0] &= 0x3f;
amount._value = new BigInteger(integer_bytes, 256);
amount._is_native = true;
var integer_hex = utils.arrayToHex(integer_bytes);
var value = new BigNumber(integer_hex, 16);
return Amount.from_json((is_negative ? '-' : '') + value.toString());
}
amount._is_negative = !is_zero && !(value_bytes[0] & 0x40);
return amount;
}
});
@@ -440,7 +421,7 @@ var STAccount = exports.Account = new SerializedType({
if (!account.is_valid()) {
throw new Error('Invalid account!');
}
serializeHex(so, account.to_hex());
serializeBits(so, account.to_bits());
},
parse: function (so) {
var len = this.parse_varint(so);
@@ -493,7 +474,7 @@ var STPathSet = exports.PathSet = new SerializedType({
STInt8.serialize(so, type);
if (entry.account) {
so.append(UInt160.from_json(entry.account).to_bytes());
STHash160.serialize(so, entry.account);
}
if (entry.currency) {
@@ -502,7 +483,7 @@ var STPathSet = exports.PathSet = new SerializedType({
}
if (entry.issuer) {
so.append(UInt160.from_json(entry.issuer).to_bytes());
STHash160.serialize(so, entry.issuer);
}
}
}
@@ -572,7 +553,7 @@ var STPathSet = exports.PathSet = new SerializedType({
if (entry.account || entry.currency || entry.issuer) {
entry.type = type;
entry.type_hex = ("000000000000000" + type.toString(16)).slice(-16);
entry.type_hex = ('000000000000000' + type.toString(16)).slice(-16);
current_path.push(entry);
} else {
@@ -593,7 +574,7 @@ STPathSet.id = 18;
var STVector256 = exports.Vector256 = new SerializedType({
serialize: function (so, val) { //Assume val is an array of STHash256 objects.
var length_as_varint = SerializedType.serialize_varint(so, val.length * 32);
SerializedType.serialize_varint(so, val.length * 32);
for (var i=0, l=val.length; i<l; i++) {
STHash256.serialize(so, val[i]);
}
@@ -612,7 +593,7 @@ var STVector256 = exports.Vector256 = new SerializedType({
STVector256.id = 19;
// Internal
var STMemo = exports.STMemo = new SerializedType({
exports.STMemo = new SerializedType({
serialize: function(so, val, no_marker) {
var keys = [];
@@ -682,29 +663,29 @@ var STMemo = exports.STMemo = new SerializedType({
output[keyval[0]] = keyval[1];
}
if (output['MemoType'] !== void(0)) {
var parsedType = convertHexToString(output['MemoType']);
if (output.MemoType !== void(0)) {
var parsedType = convertHexToString(output.MemoType);
if (parsedType !== 'unformatted_memo') {
output['parsed_memo_type'] = convertHexToString(output['MemoType']);
output.parsed_memo_type = convertHexToString(output.MemoType);
}
}
if (output['MemoFormat'] !== void(0)) {
output['parsed_memo_format'] = convertHexToString(output['MemoFormat']);
if (output.MemoFormat !== void(0)) {
output.parsed_memo_format = convertHexToString(output.MemoFormat);
}
if (output['MemoData'] !== void(0)) {
if (output.MemoData !== void(0)) {
// see if we can parse JSON
if (output['parsed_memo_format'] === 'json') {
if (output.parsed_memo_format === 'json') {
try {
output['parsed_memo_data'] = JSON.parse(convertHexToString(output['MemoData']));
output.parsed_memo_data = JSON.parse(convertHexToString(output.MemoData));
} catch(e) {
// fail, which is fine, we just won't add the memo_data field
}
} else if(output['parsed_memo_format'] === 'text') {
output['parsed_memo_data'] = convertHexToString(output['MemoData']);
} else if(output.parsed_memo_format === 'text') {
output.parsed_memo_data = convertHexToString(output.MemoData);
}
}
@@ -788,7 +769,7 @@ function parse(so) {
assert(type, 'Unknown type - header byte is 0x' + tag_byte.toString(16));
return [ field_name, type.parse(so) ]; //key, value
};
}
function sort_fields(keys) {
function sort_field_compare(a, b) {
@@ -801,7 +782,7 @@ function sort_fields(keys) {
// Sort by type id first, then by field id
return a_type_bits !== b_type_bits ? a_type_bits - b_type_bits : a_field_bits - b_field_bits;
};
}
return keys.sort(sort_field_compare);
}

View File

@@ -2,8 +2,6 @@ var utils = require('./utils');
var sjcl = utils.sjcl;
var config = require('./config');
var BigInteger = utils.jsbn.BigInteger;
//
// Abstract UInt class
//
@@ -11,7 +9,7 @@ var BigInteger = utils.jsbn.BigInteger;
//
var UInt = function() {
// Internal form: NaN or BigInteger
// Internal form: NaN or sjcl.bn
this._value = NaN;
this._update();
};
@@ -107,17 +105,15 @@ UInt.prototype.copyTo = function(d) {
};
UInt.prototype.equals = function(d) {
return this._value instanceof BigInteger
&& d._value instanceof BigInteger
&& this._value.equals(d._value);
return this.is_valid() && d.is_valid() && this._value.equals(d._value);
};
UInt.prototype.is_valid = function() {
return this._value instanceof BigInteger;
return this._value instanceof sjcl.bn;
};
UInt.prototype.is_zero = function() {
return this._value.equals(BigInteger.ZERO);
return this.is_valid() && this._value.equals(new sjcl.bn(0));
};
/**
@@ -147,24 +143,25 @@ UInt.prototype.parse_generic = function(j) {
case this.constructor.STR_ZERO:
case this.constructor.ACCOUNT_ZERO:
case this.constructor.HEX_ZERO:
this._value = BigInteger.valueOf();
this._value = new sjcl.bn(0);
break;
case '1':
case this.constructor.STR_ONE:
case this.constructor.ACCOUNT_ONE:
case this.constructor.HEX_ONE:
this._value = new BigInteger([1]);
this._value = new sjcl.bn(1);
break;
default:
if (typeof j !== 'string') {
this._value = NaN;
} else if (this.constructor.width === j.length) {
this._value = new BigInteger(utils.stringToArray(j), 256);
var hex = utils.arrayToHex(utils.stringToArray(j));
this._value = new sjcl.bn(hex, 16);
} else if ((this.constructor.width * 2) === j.length) {
// XXX Check char set!
this._value = new BigInteger(j, 16);
this._value = new sjcl.bn(j, 16);
} else {
this._value = NaN;
}
@@ -177,7 +174,7 @@ UInt.prototype.parse_generic = function(j) {
UInt.prototype.parse_hex = function(j) {
if (typeof j === 'string' && j.length === (this.constructor.width * 2)) {
this._value = new BigInteger(j, 16);
this._value = new sjcl.bn(j, 16);
} else {
this._value = NaN;
}
@@ -191,8 +188,9 @@ UInt.prototype.parse_bits = function(j) {
if (sjcl.bitArray.bitLength(j) !== this.constructor.width * 8) {
this._value = NaN;
} else {
var bytes = sjcl.codec.bytes.fromBits(j);
this.parse_bytes(bytes);
this._value = sjcl.bn.fromBits(j);
// var bytes = sjcl.codec.bytes.fromBits(j);
// this.parse_bytes(bytes);
}
this._update();
@@ -205,7 +203,8 @@ UInt.prototype.parse_bytes = function(j) {
if (!Array.isArray(j) || j.length !== this.constructor.width) {
this._value = NaN;
} else {
this._value = new BigInteger([0].concat(j), 256);
var bits = sjcl.codec.bytes.toBits(j);
this._value = sjcl.bn.fromBits(bits);
}
this._update();
@@ -218,8 +217,9 @@ UInt.prototype.parse_json = UInt.prototype.parse_hex;
UInt.prototype.parse_bn = function(j) {
if ((j instanceof sjcl.bn) && j.bitLength() <= this.constructor.width * 8) {
var bytes = sjcl.codec.bytes.fromBits(j.toBits());
this._value = new BigInteger(bytes, 256);
// var bytes = sjcl.codec.bytes.fromBits(j.toBits());
// this._value = new sjcl.bn(utils.arrayToHex(bytes), 16);
this._value = new sjcl.bn(j);
} else {
this._value = NaN;
}
@@ -233,7 +233,7 @@ UInt.prototype.parse_number = function(j) {
this._value = NaN;
if (typeof j === 'number' && isFinite(j) && j >= 0) {
this._value = new BigInteger(String(j));
this._value = new sjcl.bn(j);
}
this._update();
@@ -243,51 +243,31 @@ UInt.prototype.parse_number = function(j) {
// Convert from internal form.
UInt.prototype.to_bytes = function() {
if (!(this._value instanceof BigInteger)) {
if (!this.is_valid()) {
return null;
}
var bytes = this._value.toByteArray();
bytes = bytes.map(function(b) {
return (b + 256) % 256;
});
var target = this.constructor.width;
// XXX Make sure only trim off leading zeros.
bytes = bytes.slice(-target);
while (bytes.length < target) {
bytes.unshift(0);
}
return bytes;
return sjcl.codec.bytes.fromBits(this.to_bits());
};
UInt.prototype.to_hex = function() {
if (!(this._value instanceof BigInteger)) {
if (!this.is_valid()) {
return null;
}
var bytes = this.to_bytes();
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(bytes)).toUpperCase();
return sjcl.codec.hex.fromBits(this.to_bits()).toUpperCase();
};
UInt.prototype.to_json = UInt.prototype.to_hex;
UInt.prototype.to_bits = function() {
if (!(this._value instanceof BigInteger)) {
if (!this.is_valid()) {
return null;
}
var bytes = this.to_bytes();
return sjcl.codec.bytes.toBits(bytes);
return this._value.toBits(this.constructor.width * 8);
};
UInt.prototype.to_bn = function() {
if (!(this._value instanceof BigInteger)) {
if (!this.is_valid()) {
return null;
}

View File

@@ -7,7 +7,6 @@ var UInt = require('./uint').UInt;
//
var UInt128 = extend(function () {
// Internal form: NaN or BigInteger
this._value = NaN;
}, UInt);

View File

@@ -2,8 +2,6 @@ var utils = require('./utils');
var config = require('./config');
var extend = require('extend');
var BigInteger = utils.jsbn.BigInteger;
var UInt = require('./uint').UInt;
var Base = require('./base').Base;
@@ -12,7 +10,6 @@ var Base = require('./base').Base;
//
var UInt160 = extend(function() {
// Internal form: NaN or BigInteger
this._value = NaN;
this._version_byte = void(0);
this._update();
@@ -49,7 +46,7 @@ UInt160.prototype.parse_json = function(j) {
// Allow raw numbers - DEPRECATED
// This is used mostly by the test suite and is supported
// as a legacy feature only. DO NOT RELY ON THIS BEHAVIOR.
this._value = new BigInteger(String(j));
this.parse_number(j);
this._version_byte = Base.VER_ACCOUNT_ID;
} else if (typeof j !== 'string') {
this._value = NaN;
@@ -83,7 +80,7 @@ UInt160.prototype.parse_generic = function(j) {
UInt160.prototype.to_json = function(opts) {
opts = opts || {};
if (this._value instanceof BigInteger) {
if (this.is_valid()) {
// If this value has a type, return a Base58 encoded string.
if (typeof this._version_byte === 'number') {
var output = Base.encode_check(this._version_byte, this.to_bytes());

View File

@@ -7,7 +7,6 @@ var UInt = require('./uint').UInt;
//
var UInt256 = extend(function() {
// Internal form: NaN or BigInteger
this._value = NaN;
}, UInt);

View File

@@ -1,3 +1,15 @@
function getMantissaDecimalString(bignum) {
var mantissa = bignum.toPrecision(16)
.replace(/\./, '') // remove decimal point
.replace(/e.*/, '') // remove scientific notation
.replace(/^0*/, ''); // remove leading zeroes
while (mantissa.length < 16) {
mantissa += '0'; // add trailing zeroes until length is 16
}
return mantissa;
}
function filterErr(code, done) {
return function(e) {
done(e.code !== code ? e : void(0));
@@ -69,6 +81,13 @@ function hexToArray(h) {
return stringToArray(hexToString(h));
};
function arrayToHex(a) {
return a.map(function(byteValue) {
var hex = byteValue.toString(16);
return hex.length > 1 ? hex : '0' + hex;
}).join('');
}
function chunkString(str, n, leftAlign) {
var ret = [];
var i=0, len=str.length;
@@ -144,15 +163,16 @@ exports.hexToString = hexToString;
exports.hexToArray = hexToArray;
exports.stringToArray = stringToArray;
exports.stringToHex = stringToHex;
exports.arrayToHex = arrayToHex;
exports.chunkString = chunkString;
exports.assert = assert;
exports.arrayUnique = arrayUnique;
exports.toTimestamp = toTimestamp;
exports.fromTimestamp = fromTimestamp;
exports.getMantissaDecimalString = getMantissaDecimalString;
// Going up three levels is needed to escape the src-cov folder used for the
// test coverage stuff.
exports.sjcl = require('../../../build/sjcl');
exports.jsbn = require('../../../src/js/jsbn/jsbn');
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1,5 +1,4 @@
var assert = require('assert');
var BigInteger = require('ripple-lib').jsbn.BigInteger;
var Amount = require('ripple-lib').Amount;
var UInt160 = require('ripple-lib').UInt160;
var load_config = require('ripple-lib').config.load;
@@ -127,6 +126,9 @@ describe('Amount', function() {
it('1 XRP human', function() {
assert.strictEqual(Amount.from_human("1 XRP").to_human_full(), '1/XRP');
});
it('1XRP human', function() {
assert.strictEqual(Amount.from_human('1XRP').to_human_full(), '1/XRP');
});
it('0.1 XRP', function() {
assert.strictEqual(Amount.from_human("0.1 XRP").to_text_full(), '0.1/XRP');
});
@@ -281,14 +283,11 @@ describe('Amount', function() {
});
});
describe('UInt160', function() {
it('Parse 0', function () {
assert.deepEqual(new BigInteger(), UInt160.from_generic('0')._value);
});
it('Parse 0 export', function () {
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_generic('0').set_version(0).to_json());
});
it('Parse 1', function () {
assert.deepEqual(new BigInteger([1]), UInt160.from_generic('1')._value);
assert.deepEqual(UInt160.ACCOUNT_ONE, UInt160.from_generic('1').set_version(0).to_json());
});
it('Parse rrrrrrrrrrrrrrrrrrrrrhoLvTp export', function () {
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrrhoLvTp').to_json());
@@ -973,7 +972,7 @@ describe('Amount', function() {
assert.strictEqual(Amount.from_json('10000000').product_human(Amount.from_json('10')).to_text_full(), '0.0001/XRP');
});
it('Multiply USD with XAU (dem)', function () {
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_text_full(), '19900.00316303882/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_text_full(), '19900.00316303883/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
});
it('Multiply 0 XRP with 0 XRP human', function () {
assert.strictEqual('0/XRP', Amount.from_json('0').product_human(Amount.from_json('0')).to_human_full());
@@ -1045,7 +1044,7 @@ describe('Amount', function() {
assert.strictEqual(Amount.from_json('10000000').product_human(Amount.from_json('10')).to_human_full(), '0.0001/XRP');
});
it('Multiply USD with XAU (dem) human', function () {
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_human_full(), '19,900.00316303882/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_human_full(), '19,900.00316303883/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
});
});
@@ -1220,7 +1219,6 @@ describe('Amount', function() {
it ('from_json minimum IOU', function() {
var amt = Amount.from_json('-1e-81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
assert.strictEqual(amt._value.toString(), Amount.bi_man_min_value.toString());
assert.strictEqual(amt.to_text(), '-1000000000000000e-96');
assert.strictEqual(amt.to_text(), Amount.min_value);
});
@@ -1233,7 +1231,6 @@ describe('Amount', function() {
it ('from_json maximum IOU', function() {
var amt = Amount.from_json('9999999999999999e80/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
assert.strictEqual(amt._value.toString(), Amount.bi_man_max_value.toString());
assert.strictEqual(amt.to_text(), '9999999999999999e80');
});
@@ -1245,13 +1242,11 @@ describe('Amount', function() {
it ('from_json normalize mantissa to valid max range, lost significant digits', function() {
var amt = Amount.from_json('99999999999999999999999999999999/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
assert.strictEqual(amt._value.toString(), Amount.bi_man_max_value.toString());
assert.strictEqual(amt.to_text(), '9999999999999999e16');
});
it ('from_json normalize mantissa to min valid range, lost significant digits', function() {
var amt = Amount.from_json('-0.0000000000000000000000001/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
assert.strictEqual(amt._value.toString(), Amount.bi_man_min_value.toString());
assert.strictEqual(amt.to_text(), '-1000000000000000e-40');
});
});

View File

@@ -1566,8 +1566,8 @@ describe('OrderBook', function() {
},
index: 'B6BC3B0F87976370EE11F5575593FE63AA5DC1D602830DC96F04B2D597F044BF',
owner_funds: '0.1129267125000245',
taker_gets_funded: '0.1127013098802639',
taker_pays_funded: '55.95620035555102',
taker_gets_funded: '0.112701309880264',
taker_pays_funded: '55.95620035555106',
is_fully_funded: false },
{ Account: 'raudnGKfTK23YKfnS7ixejHrqGERTYNFXk',

View File

@@ -2,7 +2,7 @@ var assert = require('assert');
var SerializedObject = require('ripple-lib').SerializedObject;
var types = require('ripple-lib').types;
var Amount = require('ripple-lib').Amount;
var BigInteger = require('ripple-lib').jsbn.BigInteger;
var sjcl = require('ripple-lib').sjcl;
describe('Serialized types', function() {
describe('Int8', function() {
@@ -287,7 +287,7 @@ describe('Serialized types', function() {
var so = new SerializedObject("8B2386F26F8E232B");
var num = types.Int64.parse(so);
// We get a positive number
assert.strictEqual(num.toString(16), '8b2386f26f8e232b');
assert.strictEqual(num.toString(), '0x8b2386f26f8e232b');
});
it('Serialize "0123456789ABCDEF"', function () {
var so = new SerializedObject();
@@ -299,15 +299,15 @@ describe('Serialized types', function() {
types.Int64.serialize(so, 'F0E1D2C3B4A59687');
assert.strictEqual(so.to_hex(), 'F0E1D2C3B4A59687');
});
it('Serialize BigInteger("FFEEDDCCBBAA9988")', function () {
it('Serialize bn("FFEEDDCCBBAA9988")', function () {
var so = new SerializedObject();
types.Int64.serialize(so, new BigInteger('FFEEDDCCBBAA9988', 16));
types.Int64.serialize(so, new sjcl.bn('FFEEDDCCBBAA9988', 16));
assert.strictEqual(so.to_hex(), 'FFEEDDCCBBAA9988');
});
it('Fail to serialize BigInteger("-1")', function () {
it('Fail to serialize BigNumber("-1")', function () {
var so = new SerializedObject();
assert.throws(function () {
types.Int64.serialize(so, new BigInteger('-1', 10));
types.Int64.serialize(so, new BigNumber('-1', 10));
});
});
it('Fail to serialize "10000000000000000"', function () {
@@ -343,7 +343,7 @@ describe('Serialized types', function() {
it('Parse "0123456789ABCDEF"', function () {
var so = new SerializedObject("0123456789ABCDEF");
var num = types.Int64.parse(so);
assert.strictEqual(num.toString(10), '81985529216486895');
assert.strictEqual(num.toString(), '0x123456789abcdef');
});
});

View File

@@ -9,8 +9,8 @@ describe('UInt', function() {
assert.strictEqual(val.to_hex(), '00000000000000000000000000000000');
});
it('should create 00000000000000000000000000000001 when called with 1', function () {
var val = UInt128.from_number(0);
assert.strictEqual(val.to_hex(), '00000000000000000000000000000000');
var val = UInt128.from_number(1);
assert.strictEqual(val.to_hex(), '00000000000000000000000000000001');
});
it('should create 000000000000000000000000FFFFFFFF when called with 0xFFFFFFFF', function () {
var val = UInt128.from_number(0xFFFFFFFF);