utils and tests.
This commit is contained in:
parent
6776c701e3
commit
535b6a823e
@ -648,69 +648,80 @@ utils.assert.fatal = function fatal(value, message) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert satoshis to a BTC string.
|
||||
* This function explicitly avoids
|
||||
* any floating point arithmetic.
|
||||
* @param {Number} satoshi
|
||||
* Safely convert satoshis to a BTC string.
|
||||
* This function explicitly avoids any
|
||||
* floating point arithmetic.
|
||||
* @param {Number} value - Satoshis.
|
||||
* @returns {String} BTC string.
|
||||
*/
|
||||
|
||||
utils.btc = function btc(satoshi) {
|
||||
utils.btc = function btc(value) {
|
||||
var negative = false;
|
||||
var btc;
|
||||
var hi, lo, result;
|
||||
|
||||
if (utils.isBTC(satoshi))
|
||||
return satoshi;
|
||||
if (utils.isFloat(value))
|
||||
return value;
|
||||
|
||||
assert(utils.isSatoshi(satoshi), 'Non-satoshi value for conversion.');
|
||||
assert(utils.isInt(value), 'Non-satoshi value for conversion.');
|
||||
|
||||
if (satoshi < 0) {
|
||||
satoshi = -satoshi;
|
||||
if (value < 0) {
|
||||
value = -value;
|
||||
negative = true;
|
||||
}
|
||||
|
||||
btc = satoshi.toString(10);
|
||||
assert(value <= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1.');
|
||||
|
||||
while (btc.length < 9)
|
||||
btc = '0' + btc;
|
||||
// assert(value <= 21000000 * 100000000, 'Number exceeds MAX_MONEY.');
|
||||
|
||||
btc = btc.slice(0, -8) + '.' + btc.slice(-8);
|
||||
value = value.toString(10);
|
||||
|
||||
btc = btc.replace(/0+$/, '');
|
||||
assert(value.length <= 16, 'Number exceeds 2^53-1.');
|
||||
|
||||
if (btc[btc.length - 1] === '.')
|
||||
btc = btc.slice(0, -1);
|
||||
while (value.length < 9)
|
||||
value = '0' + value;
|
||||
|
||||
hi = value.slice(0, -8);
|
||||
lo = value.slice(-8);
|
||||
|
||||
lo = lo.replace(/0+$/, '');
|
||||
|
||||
if (lo.length === 0)
|
||||
lo += '0';
|
||||
|
||||
result = hi + '.' + lo;
|
||||
|
||||
if (negative)
|
||||
btc = '-' + btc;
|
||||
result = '-' + result;
|
||||
|
||||
return btc;
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert BTC string to satoshis.
|
||||
* This function explicitly avoids
|
||||
* any floating point arithmetic.
|
||||
* @param {String} btc
|
||||
* Safely convert a BTC string to satoshis.
|
||||
* This function explicitly avoids any
|
||||
* floating point arithmetic. It also does
|
||||
* extra validation to ensure the resulting
|
||||
* Number will be 53 bits or less.
|
||||
* @param {String} value - BTC
|
||||
* @returns {Number} Satoshis.
|
||||
* @throws on parse error
|
||||
*/
|
||||
|
||||
utils.satoshi = function satoshi(btc) {
|
||||
utils.satoshi = function satoshi(value) {
|
||||
var negative = false;
|
||||
var satoshi, parts, hi, lo;
|
||||
var parts, hi, lo, result;
|
||||
|
||||
if (utils.isSatoshi(btc))
|
||||
return btc;
|
||||
if (utils.isInt(value))
|
||||
return value;
|
||||
|
||||
assert(utils.isBTC(btc), 'Non-BTC value for conversion.');
|
||||
assert(utils.isFloat(value), 'Non-BTC value for conversion.');
|
||||
|
||||
if (btc[0] === '-') {
|
||||
if (value[0] === '-') {
|
||||
negative = true;
|
||||
btc = btc.substring(1);
|
||||
value = value.substring(1);
|
||||
}
|
||||
|
||||
parts = btc.split('.');
|
||||
parts = value.split('.');
|
||||
|
||||
assert(parts.length <= 2, 'Bad decimal point.');
|
||||
|
||||
@ -720,53 +731,93 @@ utils.satoshi = function satoshi(btc) {
|
||||
hi = hi.replace(/^0+/, '');
|
||||
lo = lo.replace(/0+$/, '');
|
||||
|
||||
assert(hi.length <= 8, 'Number exceeds MAX_MONEY.');
|
||||
assert(+hi < 21000000, 'Number exceeds MAX_MONEY.');
|
||||
|
||||
assert(hi.length <= 8, 'Number exceeds 2^53-1.');
|
||||
assert(lo.length <= 8, 'Too many decimal places.');
|
||||
|
||||
if (hi.length === 0)
|
||||
hi = '0';
|
||||
|
||||
while (lo.length < 8)
|
||||
lo += '0';
|
||||
|
||||
satoshi = parseInt(hi + lo, 10);
|
||||
hi = parseInt(hi, 10);
|
||||
lo = parseInt(lo, 10);
|
||||
|
||||
assert(hi < 90071992 || (hi === 90071992 && lo <= 54740991),
|
||||
'Number exceeds 2^53-1.');
|
||||
|
||||
// assert(hi < 21000000 || (hi === 21000000 && lo === 0),
|
||||
// 'Number exceeds MAX_MONEY.');
|
||||
|
||||
result = hi * 100000000 + lo;
|
||||
|
||||
if (negative)
|
||||
satoshi = -satoshi;
|
||||
result = -result;
|
||||
|
||||
return satoshi;
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether a number is both a Number and finite.
|
||||
* @param {Number?} val
|
||||
* @param {Number?} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isNumber = function isNumber(val) {
|
||||
return typeof val === 'number' && isFinite(val);
|
||||
utils.isNumber = function isNumber(value) {
|
||||
return typeof value === 'number' && isFinite(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether an object qualifies as satoshis.
|
||||
* @param {BN?} val
|
||||
* Test whether a string qualifies as a float.
|
||||
* @param {String?} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isSatoshi = function isSatoshi(val) {
|
||||
return utils.isNumber(val) && val % 1 === 0;
|
||||
utils.isFloat = function isFloat(value) {
|
||||
return typeof value === 'string'
|
||||
&& /^-?(\d+)?(?:\.\d*)?$/.test(value)
|
||||
&& value.length !== 0
|
||||
&& value !== '-';
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether an object qualifies as a BTC string.
|
||||
* @param {String?} val
|
||||
* Test whether an object is a finite number and int.
|
||||
* @param {BN?} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isBTC = function isBTC(val) {
|
||||
return typeof val === 'string'
|
||||
&& /^-?(\d+)?(?:\.\d*)?$/.test(val)
|
||||
&& val.length !== 0
|
||||
&& val !== '-';
|
||||
utils.isInt = function isInt(value) {
|
||||
return utils.isNumber(value) && value % 1 === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test and validate a satoshi value (Number).
|
||||
* @param {Number?} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isSatoshi = function isSatoshi(value) {
|
||||
try {
|
||||
utils.satoshi(value);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test and validate a BTC string.
|
||||
* @param {String?} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isBTC = function isBTC(value) {
|
||||
try {
|
||||
utils.btc(value);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1600,6 +1651,15 @@ utils.writeU64NBE = function writeU64NBE(dst, num, off) {
|
||||
|
||||
utils.MAX_SAFE_INTEGER = 0x1fffffffffffff;
|
||||
|
||||
/**
|
||||
* Max 52 bit integer (safe for additions).
|
||||
* (MAX_SAFE_INTEGER - 1) / 2
|
||||
* @type Number
|
||||
* @const
|
||||
*/
|
||||
|
||||
utils.MAX_SAFE_ADDITION = 0xfffffffffffff;
|
||||
|
||||
/**
|
||||
* Write a javascript number as an int64le (faster than big numbers).
|
||||
* @param {Number} value
|
||||
@ -1613,8 +1673,6 @@ utils.write64N = function write64N(dst, num, off, be) {
|
||||
|
||||
off = off >>> 0;
|
||||
|
||||
assert(num <= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1');
|
||||
|
||||
negative = num < 0;
|
||||
|
||||
if (negative) {
|
||||
@ -1622,6 +1680,8 @@ utils.write64N = function write64N(dst, num, off, be) {
|
||||
num -= 1;
|
||||
}
|
||||
|
||||
assert(num <= utils.MAX_SAFE_INTEGER, 'Number exceeds 2^53-1');
|
||||
|
||||
hi = num / 0x100000000 | 0;
|
||||
lo = num % 0x100000000;
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ describe('Utils', function() {
|
||||
btc = utils.btc(54678 * 1000000);
|
||||
assert.equal(btc, '546.78');
|
||||
btc = utils.btc(5460 * 10000000);
|
||||
assert.equal(btc, '546');
|
||||
assert.equal(btc, '546.0');
|
||||
});
|
||||
|
||||
it('should convert btc to satoshi', function() {
|
||||
@ -37,6 +37,42 @@ describe('Utils', function() {
|
||||
assert(btc === 54678 * 1000000);
|
||||
btc = utils.satoshi('546');
|
||||
assert(btc === 5460 * 10000000);
|
||||
btc = utils.satoshi('546.0');
|
||||
assert(btc === 5460 * 10000000);
|
||||
btc = utils.satoshi('546.0000');
|
||||
assert(btc === 5460 * 10000000);
|
||||
assert.doesNotThrow(function() {
|
||||
utils.satoshi('546.00000000000000000');
|
||||
});
|
||||
assert.throws(function() {
|
||||
utils.satoshi('546.00000000000000001');
|
||||
});
|
||||
/*
|
||||
assert.doesNotThrow(function() {
|
||||
utils.satoshi('21000000');
|
||||
});
|
||||
assert.doesNotThrow(function() {
|
||||
utils.satoshi('021000000');
|
||||
});
|
||||
assert.throws(function() {
|
||||
utils.satoshi('21000001');
|
||||
});
|
||||
assert.throws(function() {
|
||||
utils.satoshi('121000000');
|
||||
});
|
||||
*/
|
||||
assert.doesNotThrow(function() {
|
||||
utils.satoshi('90071992.54740991');
|
||||
});
|
||||
assert.doesNotThrow(function() {
|
||||
utils.satoshi('090071992.547409910');
|
||||
});
|
||||
assert.throws(function() {
|
||||
utils.satoshi('90071992.54740992');
|
||||
});
|
||||
assert.throws(function() {
|
||||
utils.satoshi('190071992.54740991');
|
||||
});
|
||||
});
|
||||
|
||||
var unsigned = [
|
||||
|
||||
Loading…
Reference in New Issue
Block a user