mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-22 13:15:49 +00:00
JS: Add BigInteger support to Amount.
This commit is contained in:
committed by
Stefan Thomas
parent
49382cf15f
commit
5425ac4bfb
173
js/amount.js
173
js/amount.js
@@ -1,7 +1,10 @@
|
|||||||
// Represent Newcoin amounts and currencies.
|
// Represent Newcoin amounts and currencies.
|
||||||
|
// - Numbers in hex are big-endian.
|
||||||
|
|
||||||
|
var utils = require('./utils.js');
|
||||||
|
var jsbn = require('./jsbn.js');
|
||||||
|
|
||||||
var utils = require("./utils.js");
|
var BigInteger = jsbn.BigInteger;
|
||||||
|
|
||||||
var UInt160 = function () {
|
var UInt160 = function () {
|
||||||
// Internal form:
|
// Internal form:
|
||||||
@@ -9,7 +12,13 @@ var UInt160 = function () {
|
|||||||
// XXX Should standardize on 'i' format or 20 format.
|
// XXX Should standardize on 'i' format or 20 format.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns NaN on error.
|
UInt160.prototype.from_json = function (j) {
|
||||||
|
var u = new UInt160();
|
||||||
|
|
||||||
|
return u.parse_json(j);
|
||||||
|
};
|
||||||
|
|
||||||
|
// value === NaN on error.
|
||||||
UInt160.prototype.parse_json = function (j) {
|
UInt160.prototype.parse_json = function (j) {
|
||||||
// Canonicalize and validate
|
// Canonicalize and validate
|
||||||
|
|
||||||
@@ -49,7 +58,7 @@ UInt160.prototype.parse_json = function (j) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.value;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert from internal form.
|
// Convert from internal form.
|
||||||
@@ -109,19 +118,84 @@ var Amount = function () {
|
|||||||
// integer : XNS
|
// integer : XNS
|
||||||
// { 'value' : ..., 'currency' : ..., 'issuer' : ...}
|
// { 'value' : ..., 'currency' : ..., 'issuer' : ...}
|
||||||
|
|
||||||
this.value = 0;
|
this.value = new BigInteger(); // NaN for bad value. Always positive for non-XNS.
|
||||||
this.offset = 0;
|
this.offset = undefined; // For non-XNS.
|
||||||
this.is_native = false;
|
this.is_native = true; // Default to XNS. Only valid if value is not NaN.
|
||||||
this.is_negative = false;
|
this.is_negative = undefined; // Undefined for XNS.
|
||||||
|
|
||||||
this.currency = new Currency();
|
this.currency = new Currency();
|
||||||
this.issuer = new UInt160();
|
this.issuer = new UInt160();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert only value to JSON text.
|
// YYY Might also check range.
|
||||||
Amount.prototype.to_text = function() {
|
Amount.prototype.is_valid = function() {
|
||||||
// XXX Needs to work for native and non-native.
|
return NaN !== this.value;
|
||||||
return this.is_negative ? -this.value : this.value; // XXX Use biginteger.
|
}
|
||||||
|
|
||||||
|
// Convert only value to JSON wire format.
|
||||||
|
Amount.prototype.to_text = function(allow_nan) {
|
||||||
|
if (NaN === this.value) {
|
||||||
|
// Never should happen.
|
||||||
|
return allow_nan ? NaN : "0";
|
||||||
|
}
|
||||||
|
else if (this.is_native) {
|
||||||
|
if (this.value.compareTo(exports.consts.xns_max) > 0 || this.value.compareTo(exports.consts.xns_min) < 0)
|
||||||
|
{
|
||||||
|
// Never should happen.
|
||||||
|
return allow_nan ? NaN : "0";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.value.equals(BigInteger.ZERO))
|
||||||
|
{
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
else if (this.offset < -25 || mOffset > -5)
|
||||||
|
{
|
||||||
|
// Use e notation.
|
||||||
|
// XXX Clamp output.
|
||||||
|
|
||||||
|
return (this.is_negative ? "-" : "") + this.value.toString() + "e" + this.offset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var val = "000000000000000000000000000" + this.value.toString() + "00000000000000000000000";
|
||||||
|
var pre = val.substring(0, this.offset + 43);
|
||||||
|
var post = val.substring(this.offset + 43);
|
||||||
|
var s_pre = val.match(/[1-9].*$/); // Everything but leading zeros.
|
||||||
|
var s_post = val.match(/0+$/); // Trailing zeros.
|
||||||
|
|
||||||
|
|
||||||
|
return (this.is_negative ? "-" : "")
|
||||||
|
+ (null == s_pre ? "0" : s_pre[0])
|
||||||
|
+ "."
|
||||||
|
+ post.substring(post.length - s_post.length);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Amount.prototype.canonicalize = function() {
|
||||||
|
if (NaN === this.value || !this.currency) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
else if (this.value.equals(BigInteger.ZERO)) {
|
||||||
|
this.offset = -100;
|
||||||
|
this.is_negative = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (this.value.compareTo(exports.consts.bi_man_min_value)) {
|
||||||
|
this.value.multiply(exports.consts.bi_10);
|
||||||
|
this.offset -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (this.value.compareTo(exports.consts.bi_man_max_value)) {
|
||||||
|
this.value.divide(exports.consts.bi_10);
|
||||||
|
this.offset += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.to_json = function() {
|
Amount.prototype.to_json = function() {
|
||||||
@@ -138,20 +212,34 @@ Amount.prototype.to_json = function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse a native value.
|
// Parse a XNS value from untrusted input.
|
||||||
|
// XXX Improvements: disallow leading zeros.
|
||||||
Amount.prototype.parse_native = function(j) {
|
Amount.prototype.parse_native = function(j) {
|
||||||
if ('integer' === typeof j) {
|
var m;
|
||||||
// XNS
|
|
||||||
this.value = j >= 0 ? j : -j; // XXX Use biginteger.
|
if ('string' === typeof j)
|
||||||
this.offset = 0;
|
m = j.match(/^(\d+)(\.\d{1,6})?$/);
|
||||||
this.is_native = true;
|
|
||||||
this.is_negative = j < 0;
|
if ('integer' === typeof j || null !== m) {
|
||||||
|
if ('integer' === typeof j || ("" === e[2])) {
|
||||||
|
this.value = new BigInteger(j);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Decimal notation
|
||||||
|
var int_part = (new BigInteger(e[1])).multiply(exports.consts.xns_unit);
|
||||||
|
var fraction_part = (new BigInteger(e[2])).multiply(new BigInteger(Math.pow(10, exports.consts.xns_unit-e[2].length)));
|
||||||
|
|
||||||
|
this.value = int_part.add(fraction_part);
|
||||||
}
|
}
|
||||||
else if ('string' === typeof j) {
|
|
||||||
this.value = j >= 0 ? j : -j; // XXX Use biginteger.
|
|
||||||
this.offset = 0;
|
|
||||||
this.is_native = true;
|
this.is_native = true;
|
||||||
this.is_negative = j < 0;
|
this.offset = undefined;
|
||||||
|
this.is_negative = undefined;
|
||||||
|
|
||||||
|
if (this.value.compareTo(exports.consts.xns_max) > 0 || this.value.compareTo(exports.consts.xns_min) < 0)
|
||||||
|
{
|
||||||
|
this.value = NaN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.value = NaN;
|
this.value = NaN;
|
||||||
@@ -161,16 +249,41 @@ Amount.prototype.parse_native = function(j) {
|
|||||||
// Parse a non-native value.
|
// Parse a non-native value.
|
||||||
Amount.prototype.parse_value = function(j) {
|
Amount.prototype.parse_value = function(j) {
|
||||||
if ('integer' === typeof j) {
|
if ('integer' === typeof j) {
|
||||||
this.value = j >= 0 ? j : -j; // XXX Use biginteger.
|
this.value = new BigInteger(j);
|
||||||
this.offset = 0;
|
this.offset = 0;
|
||||||
this.is_native = false;
|
this.is_native = false;
|
||||||
this.is_negative = j < 0;
|
this.is_negative = j < 0;
|
||||||
|
|
||||||
|
this.canonicalize();
|
||||||
}
|
}
|
||||||
else if ('string' === typeof j) {
|
else if ('string' === typeof j) {
|
||||||
this.value = j >= 0 ? j : -j; // XXX Use biginteger.
|
var e = j.match(/^(-?\d+)e(\d+)/);
|
||||||
|
var d = j.match(/^(-?\d+)\.(\d+)/);
|
||||||
|
|
||||||
|
if (null !== e) {
|
||||||
|
// e notation
|
||||||
|
|
||||||
|
this.value = new BigInteger(e[1]);
|
||||||
|
this.offset = parseInt(e[2]);
|
||||||
|
}
|
||||||
|
else if (null !== d) {
|
||||||
|
// float notation
|
||||||
|
|
||||||
|
this.value = (new BigInteger(e[1])).multiply((new BigInteger(exports.consts.bi_10)).pow(e[2].length)).add(new BigInteger(e[2]));
|
||||||
|
this.offset = -e[2].length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// integer notation
|
||||||
|
|
||||||
|
this.value = new BigInteger(j);
|
||||||
this.offset = 0;
|
this.offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
this.is_native = false;
|
this.is_native = false;
|
||||||
this.is_negative = j < 0;
|
this.is_negative = undefined;
|
||||||
|
|
||||||
|
this.canonicalize();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.value = NaN;
|
this.value = NaN;
|
||||||
@@ -201,10 +314,16 @@ exports.consts = {
|
|||||||
'address_one' : "iiiiiiiiiiiiiiiiiiiiBZbvjr",
|
'address_one' : "iiiiiiiiiiiiiiiiiiiiBZbvjr",
|
||||||
'currency_xns' : 0,
|
'currency_xns' : 0,
|
||||||
'currency_one' : 1,
|
'currency_one' : 1,
|
||||||
'uint160_xns' : hexToString("0000000000000000000000000000000000000000"),
|
'uint160_xns' : utils.hexToString("0000000000000000000000000000000000000000"),
|
||||||
'uint160_one' : hexToString("0000000000000000000000000000000000000001"),
|
'uint160_one' : utils.hexToString("0000000000000000000000000000000000000001"),
|
||||||
'hex_xns' : "0000000000000000000000000000000000000000",
|
'hex_xns' : "0000000000000000000000000000000000000000",
|
||||||
'hex_one' : "0000000000000000000000000000000000000001",
|
'hex_one' : "0000000000000000000000000000000000000001",
|
||||||
|
'xns_max' : new BigInteger("9000000000000000000"), // Json wire limit.
|
||||||
|
'xns_min' : new BigInteger("-9000000000000000000"), // Json wire limit.
|
||||||
|
'xns_unit' : new BigInteger('1000000'),
|
||||||
|
'bi_man_min_value' : new BigInteger('1000000000000000'),
|
||||||
|
'bi_man_max_value' : new BigInteger('9999999999999999'),
|
||||||
|
'bi_10' : new BigInteger('10'),
|
||||||
};
|
};
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8
|
// vim:sw=2:sts=2:ts=8
|
||||||
|
|||||||
Reference in New Issue
Block a user