Browser Compatibility Updates (#107)

* BigInt -> big-integer to support older browsers
* Buffer read/write BigUInt64 removed for browser compatibility.
This commit is contained in:
Nathan Nichols
2020-10-22 15:36:45 -05:00
parent b197897227
commit b43e79a9af
10 changed files with 1288 additions and 1215 deletions

View File

@@ -12,6 +12,7 @@
"test": "test"
},
"dependencies": {
"big-integer": "^1.6.48",
"create-hash": "^1.2.0",
"decimal.js": "^10.2.0",
"ripple-address-codec": "^4.1.1"

View File

@@ -9,6 +9,7 @@ import { sha512Half, transactionID } from "./hashes";
import { FieldInstance } from "./enums";
import { STObject } from "./types/st-object";
import { JsonObject } from "./types/serialized-type";
import * as bigInt from "big-integer";
/**
* Construct a BinaryParser
@@ -102,9 +103,10 @@ interface ClaimObject extends JsonObject {
* @returns the serialized object with appropriate prefix
*/
function signingClaimData(claim: ClaimObject): Buffer {
const num = bigInt(String(claim.amount));
const prefix = HashPrefix.paymentChannelClaim;
const channel = coreTypes.Hash256.from(claim.channel).toBytes();
const amount = coreTypes.UInt64.from(BigInt(claim.amount)).toBytes();
const amount = coreTypes.UInt64.from(num).toBytes();
const bytesList = new BytesList();

View File

@@ -10,6 +10,7 @@ import { UInt32 } from "./types/uint-32";
import { UInt8 } from "./types/uint-8";
import { BinaryParser } from "./serdes/binary-parser";
import { JsonObject } from "./types/serialized-type";
import * as bigInt from "big-integer";
/**
* Computes the hash of a list of objects
@@ -119,7 +120,7 @@ function accountStateHash(param: Array<JsonObject>): Hash256 {
*/
interface ledgerObject {
ledger_index: number;
total_coins: string | number | bigint;
total_coins: string | number | bigInt.BigInteger;
parent_hash: string;
transaction_hash: string;
account_hash: string;
@@ -142,7 +143,9 @@ function ledgerHash(header: ledgerObject): Hash256 {
assert(header.close_flags !== undefined);
UInt32.from<number>(header.ledger_index).toBytesSink(hash);
UInt64.from<bigint>(BigInt(header.total_coins)).toBytesSink(hash);
UInt64.from<bigInt.BigInteger>(
bigInt(String(header.total_coins))
).toBytesSink(hash);
Hash256.from<string>(header.parent_hash).toBytesSink(hash);
Hash256.from<string>(header.transaction_hash).toBytesSink(hash);
Hash256.from<string>(header.account_hash).toBytesSink(hash);

View File

@@ -1,5 +1,6 @@
import { coreTypes } from "./types";
import { Decimal } from "decimal.js";
import * as bigInt from "big-integer";
/**
* class for encoding and decoding quality
@@ -15,7 +16,7 @@ class quality {
const decimal = new Decimal(quality);
const exponent = decimal.e - 15;
const qualityString = decimal.times(`1e${-exponent}`).abs().toString();
const bytes = coreTypes.UInt64.from(BigInt(qualityString)).toBytes();
const bytes = coreTypes.UInt64.from(bigInt(qualityString)).toBytes();
bytes[0] = exponent + 100;
return bytes;
}

View File

@@ -5,6 +5,7 @@ import { BinaryParser } from "../serdes/binary-parser";
import { AccountID } from "./account-id";
import { Currency } from "./currency";
import { JsonObject, SerializedType } from "./serialized-type";
import * as bigInt from "big-integer";
/**
* Constants for validating amounts
@@ -14,6 +15,7 @@ const MAX_IOU_EXPONENT = 80;
const MAX_IOU_PRECISION = 16;
const MAX_DROPS = new Decimal("1e17");
const MIN_XRP = new Decimal("1e-6");
const mask = bigInt(0x00000000ffffffff);
/**
* decimal.js configuration for Amount IOUs
@@ -69,12 +71,17 @@ class Amount extends SerializedType {
return value;
}
const amount = Buffer.alloc(8);
let amount = Buffer.alloc(8);
if (typeof value === "string") {
Amount.assertXrpIsValid(value);
const number = BigInt(value);
amount.writeBigUInt64BE(number);
const number = bigInt(value);
const intBuf = [Buffer.alloc(4), Buffer.alloc(4)];
intBuf[0].writeUInt32BE(Number(number.shiftRight(32)));
intBuf[1].writeUInt32BE(Number(number.and(mask)));
amount = Buffer.concat(intBuf);
amount[0] |= 0x40;
@@ -92,7 +99,13 @@ class Amount extends SerializedType {
.times(`1e${-(number.e - 15)}`)
.abs()
.toString();
amount.writeBigUInt64BE(BigInt(integerNumberString));
const num = bigInt(integerNumberString);
const intBuf = [Buffer.alloc(4), Buffer.alloc(4)];
intBuf[0].writeUInt32BE(Number(num.shiftRight(32)));
intBuf[1].writeUInt32BE(Number(num.and(mask)));
amount = Buffer.concat(intBuf);
amount[0] |= 0x80;
@@ -136,9 +149,13 @@ class Amount extends SerializedType {
const bytes = this.bytes;
const isPositive = bytes[0] & 0x40;
const sign = isPositive ? "" : "-";
bytes[0] &= 0x3f;
return `${sign}${bytes.readBigUInt64BE().toString()}`;
const msb = bigInt(bytes.slice(0, 4).readUInt32BE());
const lsb = bigInt(bytes.slice(4).readUInt32BE());
const num = msb.shiftLeft(32).or(lsb);
return `${sign}${num.toString()}`;
} else {
const parser = new BinaryParser(this.toString());
const mantissa = parser.read(8);

View File

@@ -1,5 +1,6 @@
import { BytesList } from "../serdes/binary-serializer";
import { BinaryParser } from "../serdes/binary-parser";
import * as bigInt from "big-integer";
type JSON = string | number | boolean | null | undefined | JSON[] | JsonObject;
@@ -20,7 +21,9 @@ class SerializedType {
return this.fromParser(parser, hint);
}
static from(value: SerializedType | JSON | bigint): SerializedType {
static from(
value: SerializedType | JSON | bigInt.BigInteger
): SerializedType {
throw new Error("from not implemented");
return this.from(value);
}

View File

@@ -1,7 +1,10 @@
import { UInt } from "./uint";
import { BinaryParser } from "../serdes/binary-parser";
import * as bigInt from "big-integer";
import { isInstance } from "big-integer";
const HEX_REGEX = /^[A-F0-9]{16}$/;
const mask = bigInt(0x00000000ffffffff);
/**
* Derived UInt class for serializing/deserializing 64 bit UInt
@@ -23,10 +26,12 @@ class UInt64 extends UInt {
/**
* Construct a UInt64 object
*
* @param val A UInt64, hex-string, bigint, or number
* @param val A UInt64, hex-string, bigInt, or number
* @returns A UInt64 object
*/
static from<T extends UInt64 | string | bigint | number>(val: T): UInt64 {
static from<T extends UInt64 | string | bigInt.BigInteger | number>(
val: T
): UInt64 {
if (val instanceof UInt64) {
return val;
}
@@ -37,8 +42,14 @@ class UInt64 extends UInt {
if (val < 0) {
throw new Error("value must be an unsigned integer");
}
buf.writeBigUInt64BE(BigInt(val));
return new UInt64(buf);
const number = bigInt(val);
const intBuf = [Buffer.alloc(4), Buffer.alloc(4)];
intBuf[0].writeUInt32BE(Number(number.shiftRight(32)));
intBuf[1].writeUInt32BE(Number(number.and(mask)));
return new UInt64(Buffer.concat(intBuf));
}
if (typeof val === "string") {
@@ -49,9 +60,12 @@ class UInt64 extends UInt {
return new UInt64(buf);
}
if (typeof val === "bigint") {
buf.writeBigUInt64BE(val);
return new UInt64(buf);
if (isInstance(val)) {
const intBuf = [Buffer.alloc(4), Buffer.alloc(4)];
intBuf[0].writeUInt32BE(Number(val.shiftRight(bigInt(32))));
intBuf[1].writeUInt32BE(Number(val.and(mask)));
return new UInt64(Buffer.concat(intBuf));
}
throw new Error("Cannot construct UInt64 from given value");
@@ -71,8 +85,10 @@ class UInt64 extends UInt {
*
* @returns the number represented buy this.bytes
*/
valueOf(): bigint {
return this.bytes.readBigUInt64BE();
valueOf(): bigInt.BigInteger {
const msb = bigInt(this.bytes.slice(0, 4).readUInt32BE());
const lsb = bigInt(this.bytes.slice(4).readUInt32BE());
return msb.shiftLeft(bigInt(32)).or(lsb);
}
/**

View File

@@ -1,13 +1,17 @@
import * as bigInt from "big-integer";
import { Comparable } from "./serialized-type";
/**
* Compare numbers and bigints n1 and n2
* Compare numbers and bigInts n1 and n2
*
* @param n1 First object to compare
* @param n2 Second object to compare
* @returns -1, 0, or 1, depending on how the two objects compare
*/
function compare(n1: number | bigint, n2: number | bigint): number {
function compare(
n1: number | bigInt.BigInteger,
n2: number | bigInt.BigInteger
): number {
return n1 < n2 ? -1 : n1 == n2 ? 0 : 1;
}
@@ -46,7 +50,7 @@ abstract class UInt extends Comparable {
*
* @returns the value
*/
abstract valueOf(): number | bigint;
abstract valueOf(): number | bigInt.BigInteger;
}
export { UInt };

View File

@@ -5,6 +5,7 @@ const { encode, decode } = require("../dist");
const { makeParser, BytesList, BinarySerializer } = binary;
const { coreTypes } = require("../dist/types");
const { UInt8, UInt16, UInt32, UInt64, STObject } = coreTypes;
const bigInt = require("big-integer");
const { loadFixture } = require("./utils");
const fixtures = loadFixture("data-driven-tests.json");
@@ -162,7 +163,7 @@ check(UInt64, 0xfeffffff, [0, 0, 0, 0, 254, 255, 255, 255]);
check(UInt64, -1, "throws");
check(UInt64, 0, [0, 0, 0, 0, 0, 0, 0, 0]);
check(UInt64, 1, [0, 0, 0, 0, 0, 0, 0, 1]);
check(UInt64, BigInt(1), [0, 0, 0, 0, 0, 0, 0, 1]);
check(UInt64, bigInt(1), [0, 0, 0, 0, 0, 0, 0, 1]);
function deliverMinTest() {
test("can serialize DeliverMin", () => {

File diff suppressed because it is too large Load Diff