From 7e56f3d392e52815c5c859772b99660e0fc38ef5 Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Tue, 7 Jul 2020 22:18:02 -0400 Subject: [PATCH] Fixed BigNumber string validation (#935). --- packages/bignumber/src.ts/bignumber.ts | 2 +- packages/testcases/ingest.js | 13 ++ packages/testcases/input/bignumber.json | 187 ++++++++++++++++++ packages/testcases/src.ts/index.ts | 6 + .../testcases/testcases/bignumber.json.gz | Bin 0 -> 635 bytes packages/tests/src.ts/test-utils.ts | 64 ++++-- 6 files changed, 251 insertions(+), 21 deletions(-) create mode 100644 packages/testcases/ingest.js create mode 100644 packages/testcases/input/bignumber.json create mode 100644 packages/testcases/testcases/bignumber.json.gz diff --git a/packages/bignumber/src.ts/bignumber.ts b/packages/bignumber/src.ts/bignumber.ts index 2955249d3c..8bf9197a35 100644 --- a/packages/bignumber/src.ts/bignumber.ts +++ b/packages/bignumber/src.ts/bignumber.ts @@ -202,7 +202,7 @@ export class BigNumber implements Hexable { if (value instanceof BigNumber) { return value; } if (typeof(value) === "string") { - if (value.match(/-?0x[0-9a-f]+/i)) { + if (value.match(/^-?0x[0-9a-f]+$/i)) { return new BigNumber(_constructorGuard, toHex(value)); } diff --git a/packages/testcases/ingest.js b/packages/testcases/ingest.js new file mode 100644 index 0000000000..5b9e4bc63a --- /dev/null +++ b/packages/testcases/ingest.js @@ -0,0 +1,13 @@ +"use strict"; + +const fs = require("fs"); +const { resolve } = require("path"); + +const { saveTests } = require("./lib/index"); + +function ingest(tag) { + const data = JSON.parse(fs.readFileSync(resolve(__dirname, "input", tag + ".json")).toString()); + saveTests(tag, data); +} + +ingest("bignumber") diff --git a/packages/testcases/input/bignumber.json b/packages/testcases/input/bignumber.json new file mode 100644 index 0000000000..f5f353373d --- /dev/null +++ b/packages/testcases/input/bignumber.json @@ -0,0 +1,187 @@ +[ + { + "testcase": "HexStrings - Zero; odd-length", + "value": "0x0", + "expectedValue": "0x00" + }, + { + "testcase": "HexStrings - Zero; padded", + "value": "0x00", + "expectedValue": "0x00" + }, + { + "testcase": "HexStrings - Negative Zero", + "value": "-0x00", + "expectedValue": "0x00" + }, + { + "testcase": "HexStrings - One", + "value": "0x1", + "expectedValue": "0x01" + }, + { + "testcase": "HexStrings - Negative One", + "value": "-0x1", + "expectedValue": "-0x01" + }, + { + "testcase": "HexStrings - Over 32-bits", + "value": "0xdeadbeef1", + "expectedValue": "0x0deadbeef1" + }, + { + "testcase": "HexStrings - Over 32-bits (negative)", + "value": "-0xdeadbeef1", + "expectedValue": "-0x0deadbeef1" + }, + { + "testcase": "HexStrings - Over 53-bits", + "value": "0xfffffffffffffff", + "expectedValue": "0x0fffffffffffffff" + }, + { + "testcase": "HexStrings - Over 53-bits (negative)", + "value": "-0xfffffffffffffff", + "expectedValue": "-0x0fffffffffffffff" + }, + { + "testcase": "HexStrings - Over 64-bits", + "value": "0xdeadbeefdeadbeef1", + "expectedValue": "0x0deadbeefdeadbeef1" + }, + { + "testcase": "HexStrings - Over 64-bits (negative)", + "value": "-0xdeadbeefdeadbeef1", + "expectedValue": "-0x0deadbeefdeadbeef1" + }, + { + "testcase": "DecimalStrings - Zero", + "value": "0", + "expectedValue": "0x00" + }, + { + "testcase": "DecimalStrings - One", + "value": "1", + "expectedValue": "0x01" + }, + { + "testcase": "DecimalStrings - Negative One", + "value": "-1", + "expectedValue": "-0x01" + }, + { + "testcase": "DecimalStrings - Life and such", + "value": "42", + "expectedValue": "0x2a" + }, + { + "testcase": "DecimalStrings - Life and such (negative)", + "value": "-42", + "expectedValue": "-0x2a" + }, + { + "testcase": "DecimalStrings - MAX_SAFE_INTEGER", + "value": "9007199254740991", + "expectedValue": "0x1fffffffffffff" + }, + { + "testcase": "DecimalStrings - MAX_SAFE_INTEGER (negative)", + "value": "-9007199254740991", + "expectedValue": "-0x1fffffffffffff" + }, + { + "testcase": "DecimalStrings - High value not on compact boundary", + "value": "9007199254740995", + "expectedValue": "0x20000000000003" + }, + { + "testcase": "DecimalStrings - Low value not on compact boundary", + "value": "-9007199254740995", + "expectedValue": "-0x20000000000003" + }, + { + "testcase": "Numbers - Zero", + "value": 0, + "expectedValue": "0x00" + }, + { + "testcase": "Numbers - One", + "value": 1, + "expectedValue": "0x01" + }, + { + "testcase": "Numbers - Negative One", + "value": -1, + "expectedValue": "-0x01" + }, + { + "testcase": "Numbers - BigNumber Safe", + "value": 9007199254740990, + "expectedValue": "0x1ffffffffffffe" + }, + { + "testcase": "Numbers - BigNumber Safe (negative)", + "value": -9007199254740990, + "expectedValue": "-0x1ffffffffffffe" + }, + { + "testcase": "Invalid - Empty value", + "value": "0x", + "expectedValue": null + }, + { + "testcase": "Invalid - The x of 0x0", + "value": "x", + "expectedValue": null + }, + { + "testcase": "Invalid - Negative at the end", + "value": "0123-", + "expectedValue": null + }, + { + "testcase": "Invalid - Negative in middle", + "value": "0123-456", + "expectedValue": null + }, + { + "testcase": "Invalid - Double negative", + "value": "--123", + "expectedValue": null + }, + { + "testcase": "Invalid - MAX_SAFE_INTEGER", + "value": 9007199254740991, + "expectedValue": null + }, + { + "testcase": "Invalid - -MAX_SAFE_INTEGER", + "value": -9007199254740991, + "expectedValue": null + }, + { + "testcase": "Invalid - Too high; safe value", + "value": 9007199254740996, + "expectedValue": null + }, + { + "testcase": "Invalid - Too low; save value", + "value": -9007199254740996, + "expectedValue": null + }, + { + "testcase": "Invalid - Random text", + "value": "hello world", + "expectedValue": null + }, + { + "testcase": "Invalid - Bad hex character", + "value": "0x123g", + "expectedValue": null + }, + { + "testcase": "Invalid - See #935", + "value": "0-0x1 whatever", + "expectedValue": null + } +] diff --git a/packages/testcases/src.ts/index.ts b/packages/testcases/src.ts/index.ts index 2b1134d2dd..86e17f1ebf 100644 --- a/packages/testcases/src.ts/index.ts +++ b/packages/testcases/src.ts/index.ts @@ -8,6 +8,12 @@ import { randomBytes, randomHexString, randomNumber } from "./random"; export { randomBytes, randomHexString, randomNumber }; export module TestCase { + export type BigNumber = { + testcase: string; + value: string | number; + expectedValue: string; + }; + export type HDWalletNode = { path: string; address: string; diff --git a/packages/testcases/testcases/bignumber.json.gz b/packages/testcases/testcases/bignumber.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..bc5a94ab93aeb63fff3e5333d536554c687bac6d GIT binary patch literal 635 zcmV->0)+h^iwFP!000001Fe@^Z`v>zhVS_mpV-YN)lv>XmG!Ds*;;9%QmLkC(^Q%G zBZ-vQC~+Xw)c?M47!(_a9GW}8dY|_@I{faz-yT3;VkUi>VgEDq@35H4G~z)91b$&E zu0SwGV&s7g`xoouOB&~!vsPhkzrkXGzC`xp%`aBJ2d@|P2n)&>GF`p1`~(9kqa|)Q ziavP{zyn9kwrv)*o4MB2iCLc1)_+)H3a&$Dk<2vr3@Mu-&MTrg9BE2}k9-%~Cq1xp zWYP{jbWaC5KYq;Nst22rD}%1*f^@Ml8dO)hLB(67e@CxX`6eB3*2*pVQ9|S6U85$U z#r$i!`jocW0Ge#o7HG8tG{U!NjzBqsEceyjK5&dNIJ6z1q6LgJ(g^qc`sefX`pfwF ze)2T_I(}3zo@HIyp63h)mjlc5%vG{$P1;#}MZh(!kk(%Aq9B9~54eyZIQSx2P+!7K zky$G!4Yv3TK&8OXb`VVU6u_p%I z%Ar39-$cRo15D{$kydhTOvh0(VpFDZ9@JVJ`06wm4czlmIbx-Oak7vv+rHE8ztauH z^Ef^$`xGJ+Am*@t1>Wm+k=@sxN{}T2x%N_QJ1%(-Lc}477>l*EtO0}Jr~~6xUO z^Bqc^Yf=(As8{cJb+5MPkZO>&!8 = loadTests("bignumber"); + tests.forEach((test) => { + if (test.expectedValue == null) { + it(test.testcase, function() { + assert.throws(() => { + const value = ethers.BigNumber.from(test.value); + console.log("ERROR", value); + }, (error: Error) => { + return true; + }); + }); + } else { + it(test.testcase, function() { + const value = ethers.BigNumber.from(test.value); + assert.equal(value.toHexString(), test.expectedValue); + + const value2 = ethers.BigNumber.from(value) + assert.equal(value2.toHexString(), test.expectedValue); + }); + } + }); + + [ + { value: "0x0", expected: "0x0" }, + { value: "-0x0", expected: "0x0" }, + { value: "0x5", expected: "0x5" }, + { value: "-0x5", expected: "0x5" }, + { value: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, + { value: "-0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, + { value: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, + { value: "-0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", expected: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, + ].forEach((test) => { + it(`absolute value (${ test.value })`, function() { + const value = ethers.BigNumber.from(test.value); + const expected = ethers.BigNumber.from(test.expected); + assert.ok(value.abs().eq(expected)); + }); + }); + + // @TODO: Add more tests here + +});