From 5f03ad5029e9110fceab42fe4917040c1b9a165e Mon Sep 17 00:00:00 2001 From: prathamesh0 <42446521+prathamesh0@users.noreply.github.com> Date: Thu, 2 Dec 2021 18:07:17 +0530 Subject: [PATCH] Use pg-type numeric for bigint in entities and use custom decimal in graph-node (#71) * Use pg-type numeric for bigint columns in typeorm entities * Use custom decimal implementation from util in graph-node --- packages/codegen/src/utils/type-mappings.ts | 2 +- packages/eden-watcher/src/entity/Account.ts | 4 +- packages/eden-watcher/src/entity/Block.ts | 14 ++-- packages/eden-watcher/src/entity/Claim.ts | 8 +-- .../eden-watcher/src/entity/Distribution.ts | 4 +- packages/eden-watcher/src/entity/Epoch.ts | 6 +- packages/eden-watcher/src/entity/Network.ts | 6 +- packages/eden-watcher/src/entity/Producer.ts | 6 +- .../eden-watcher/src/entity/ProducerEpoch.ts | 4 +- .../entity/ProducerRewardCollectorChange.ts | 2 +- .../src/entity/ProducerSetChange.ts | 2 +- .../src/entity/RewardScheduleEntry.ts | 6 +- packages/eden-watcher/src/entity/Slash.ts | 4 +- packages/eden-watcher/src/entity/Slot.ts | 8 +-- packages/eden-watcher/src/entity/SlotClaim.ts | 8 +-- packages/eden-watcher/src/entity/Staker.ts | 4 +- packages/graph-node/package.json | 2 - packages/graph-node/src/loader.ts | 50 +++++++-------- packages/graph-node/src/numbers.test.ts | 64 +++++++++---------- packages/graph-node/src/utils.ts | 50 +-------------- packages/graph-node/test/utils/index.ts | 3 +- .../graph-test-watcher/src/entity/Author.ts | 14 ++-- .../graph-test-watcher/src/entity/Blog.ts | 2 +- .../graph-test-watcher/src/entity/Category.ts | 2 +- .../graph-test-watcher/src/entity/_Test.ts | 2 +- packages/util/src/graph-decimal.ts | 11 ++-- 26 files changed, 121 insertions(+), 167 deletions(-) diff --git a/packages/codegen/src/utils/type-mappings.ts b/packages/codegen/src/utils/type-mappings.ts index 72818300..ea72811b 100644 --- a/packages/codegen/src/utils/type-mappings.ts +++ b/packages/codegen/src/utils/type-mappings.ts @@ -25,7 +25,7 @@ _tsToGql.set('boolean', 'Boolean'); // Typescript to Postgres type-mapping. _tsToPg.set('string', 'varchar'); _tsToPg.set('number', 'integer'); -_tsToPg.set('bigint', 'bigint'); +_tsToPg.set('bigint', 'numeric'); _tsToPg.set('boolean', 'boolean'); // Graphql to Typescript type-mapping. diff --git a/packages/eden-watcher/src/entity/Account.ts b/packages/eden-watcher/src/entity/Account.ts index 1f06b93d..741b2172 100644 --- a/packages/eden-watcher/src/entity/Account.ts +++ b/packages/eden-watcher/src/entity/Account.ts @@ -17,9 +17,9 @@ export class Account { @Column('integer') blockNumber!: number; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) totalClaimed!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) totalSlashed!: bigint; } diff --git a/packages/eden-watcher/src/entity/Block.ts b/packages/eden-watcher/src/entity/Block.ts index d8c0400e..83b99833 100644 --- a/packages/eden-watcher/src/entity/Block.ts +++ b/packages/eden-watcher/src/entity/Block.ts @@ -40,24 +40,24 @@ export class Block { @Column('varchar') receiptsRoot!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) number!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) gasUsed!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) gasLimit!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) timestamp!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) difficulty!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) totalDifficulty!: bigint; - @Column('bigint', { nullable: true, transformer: bigintTransformer }) + @Column('numeric', { nullable: true, transformer: bigintTransformer }) size!: bigint; } diff --git a/packages/eden-watcher/src/entity/Claim.ts b/packages/eden-watcher/src/entity/Claim.ts index e0e26698..3b1a4fd8 100644 --- a/packages/eden-watcher/src/entity/Claim.ts +++ b/packages/eden-watcher/src/entity/Claim.ts @@ -17,18 +17,18 @@ export class Claim { @Column('integer') blockNumber!: number; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) timestamp!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) index!: bigint; @Column('varchar') account!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) totalEarned!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) claimed!: bigint; } diff --git a/packages/eden-watcher/src/entity/Distribution.ts b/packages/eden-watcher/src/entity/Distribution.ts index 1617652b..a376a8a3 100644 --- a/packages/eden-watcher/src/entity/Distribution.ts +++ b/packages/eden-watcher/src/entity/Distribution.ts @@ -20,10 +20,10 @@ export class Distribution { @Column('varchar') distributor!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) timestamp!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) distributionNumber!: bigint; @Column('varchar') diff --git a/packages/eden-watcher/src/entity/Epoch.ts b/packages/eden-watcher/src/entity/Epoch.ts index e8bb3b24..b8dea145 100644 --- a/packages/eden-watcher/src/entity/Epoch.ts +++ b/packages/eden-watcher/src/entity/Epoch.ts @@ -21,7 +21,7 @@ export class Epoch { @Column('boolean') finalized!: boolean; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) epochNumber!: bigint; @Column('varchar', { nullable: true }) @@ -30,10 +30,10 @@ export class Epoch { @Column('varchar', { nullable: true }) endBlock!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) producerBlocks!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) allBlocks!: bigint; @Column('numeric', { default: 0, transformer: decimalTransformer }) diff --git a/packages/eden-watcher/src/entity/Network.ts b/packages/eden-watcher/src/entity/Network.ts index 066c78fe..0792dec4 100644 --- a/packages/eden-watcher/src/entity/Network.ts +++ b/packages/eden-watcher/src/entity/Network.ts @@ -29,12 +29,12 @@ export class Network { @Column('varchar', { array: true }) stakers!: string[]; - @Column('bigint', { nullable: true, transformer: bigintTransformer }) + @Column('numeric', { nullable: true, transformer: bigintTransformer }) numStakers!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) totalStaked!: bigint; - @Column('bigint', { transformer: bigintArrayTransformer, array: true }) + @Column('numeric', { transformer: bigintArrayTransformer, array: true }) stakedPercentiles!: bigint[]; } diff --git a/packages/eden-watcher/src/entity/Producer.ts b/packages/eden-watcher/src/entity/Producer.ts index e47472fe..57a62cdd 100644 --- a/packages/eden-watcher/src/entity/Producer.ts +++ b/packages/eden-watcher/src/entity/Producer.ts @@ -22,12 +22,12 @@ export class Producer { @Column('varchar', { nullable: true }) rewardCollector!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) rewards!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) confirmedBlocks!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) pendingEpochBlocks!: bigint; } diff --git a/packages/eden-watcher/src/entity/ProducerEpoch.ts b/packages/eden-watcher/src/entity/ProducerEpoch.ts index bf86124f..f32a842f 100644 --- a/packages/eden-watcher/src/entity/ProducerEpoch.ts +++ b/packages/eden-watcher/src/entity/ProducerEpoch.ts @@ -24,10 +24,10 @@ export class ProducerEpoch { @Column('varchar') epoch!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) totalRewards!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) blocksProduced!: bigint; @Column('numeric', { default: 0, transformer: decimalTransformer }) diff --git a/packages/eden-watcher/src/entity/ProducerRewardCollectorChange.ts b/packages/eden-watcher/src/entity/ProducerRewardCollectorChange.ts index c95fdb14..9437fd59 100644 --- a/packages/eden-watcher/src/entity/ProducerRewardCollectorChange.ts +++ b/packages/eden-watcher/src/entity/ProducerRewardCollectorChange.ts @@ -16,7 +16,7 @@ export class ProducerRewardCollectorChange { @Column('integer') blockNumber!: number; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) _blockNumber!: bigint; @Column('varchar') diff --git a/packages/eden-watcher/src/entity/ProducerSetChange.ts b/packages/eden-watcher/src/entity/ProducerSetChange.ts index 21a77b51..1d024fde 100644 --- a/packages/eden-watcher/src/entity/ProducerSetChange.ts +++ b/packages/eden-watcher/src/entity/ProducerSetChange.ts @@ -21,7 +21,7 @@ export class ProducerSetChange { @Column('integer') blockNumber!: number; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) _blockNumber!: bigint; @Column('varchar') diff --git a/packages/eden-watcher/src/entity/RewardScheduleEntry.ts b/packages/eden-watcher/src/entity/RewardScheduleEntry.ts index 6754d26b..b811ba85 100644 --- a/packages/eden-watcher/src/entity/RewardScheduleEntry.ts +++ b/packages/eden-watcher/src/entity/RewardScheduleEntry.ts @@ -16,12 +16,12 @@ export class RewardScheduleEntry { @Column('integer') blockNumber!: number; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) startTime!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) epochDuration!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) rewardsPerEpoch!: bigint; } diff --git a/packages/eden-watcher/src/entity/Slash.ts b/packages/eden-watcher/src/entity/Slash.ts index 7865abcf..067791d4 100644 --- a/packages/eden-watcher/src/entity/Slash.ts +++ b/packages/eden-watcher/src/entity/Slash.ts @@ -17,12 +17,12 @@ export class Slash { @Column('integer') blockNumber!: number; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) timestamp!: bigint; @Column('varchar') account!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) slashed!: bigint; } diff --git a/packages/eden-watcher/src/entity/Slot.ts b/packages/eden-watcher/src/entity/Slot.ts index 3758c1d7..9846a7d8 100644 --- a/packages/eden-watcher/src/entity/Slot.ts +++ b/packages/eden-watcher/src/entity/Slot.ts @@ -24,16 +24,16 @@ export class Slot { @Column('varchar') delegate!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) winningBid!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) oldBid!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) startTime!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) expirationTime!: bigint; @Column('numeric', { default: 0, transformer: decimalTransformer }) diff --git a/packages/eden-watcher/src/entity/SlotClaim.ts b/packages/eden-watcher/src/entity/SlotClaim.ts index 4893679b..1d4acf7b 100644 --- a/packages/eden-watcher/src/entity/SlotClaim.ts +++ b/packages/eden-watcher/src/entity/SlotClaim.ts @@ -24,16 +24,16 @@ export class SlotClaim { @Column('varchar') owner!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) winningBid!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) oldBid!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) startTime!: bigint; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) expirationTime!: bigint; @Column('numeric', { default: 0, transformer: decimalTransformer }) diff --git a/packages/eden-watcher/src/entity/Staker.ts b/packages/eden-watcher/src/entity/Staker.ts index 375f976e..b888dbaa 100644 --- a/packages/eden-watcher/src/entity/Staker.ts +++ b/packages/eden-watcher/src/entity/Staker.ts @@ -16,9 +16,9 @@ export class Staker { @Column('integer') blockNumber!: number; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) staked!: bigint; - @Column('bigint', { nullable: true, transformer: bigintTransformer }) + @Column('numeric', { nullable: true, transformer: bigintTransformer }) rank!: bigint; } diff --git a/packages/graph-node/package.json b/packages/graph-node/package.json index 79b90433..055fc9fc 100644 --- a/packages/graph-node/package.json +++ b/packages/graph-node/package.json @@ -46,12 +46,10 @@ "@vulcanize/util": "^0.1.0", "bn.js": "^4.11.9", "debug": "^4.3.1", - "decimal.js": "^10.3.1", "fs-extra": "^10.0.0", "js-yaml": "^4.1.0", "json-bigint": "^1.0.0", "json-diff": "^0.5.4", - "lodash": "^4.17.21", "reflect-metadata": "^0.1.13", "toml": "^3.0.0", "typeorm": "^0.2.32", diff --git a/packages/graph-node/src/loader.ts b/packages/graph-node/src/loader.ts index 7b9f160b..fcb912ae 100644 --- a/packages/graph-node/src/loader.ts +++ b/packages/graph-node/src/loader.ts @@ -16,18 +16,14 @@ import BN from 'bn.js'; import debug from 'debug'; import loader from '@vulcanize/assemblyscript/lib/loader'; -import { IndexerInterface } from '@vulcanize/util'; +import { IndexerInterface, GraphDecimal, getGraphDigitsAndExp } from '@vulcanize/util'; import { TypeId, Level } from './types'; import { Block, fromEthereumValue, toEthereumValue, - resolveEntityFieldConflicts, - GraphDecimal, - digitsToString, - MIN_EXP, - MAX_EXP + resolveEntityFieldConflicts } from './utils'; import { Database } from './database'; @@ -255,15 +251,16 @@ export const instantiate = async ( // Creating decimal x. const xBigDecimal = await BigDecimal.wrap(x); const xStringPtr = await xBigDecimal.toString(); - const xDecimal = new GraphDecimal(__getString(xStringPtr)); + const xDecimalString = __getString(xStringPtr); + const xDecimal = new GraphDecimal(xDecimalString); // Create decimal y. const yBigDecimal = await BigDecimal.wrap(y); const yStringPtr = await yBigDecimal.toString(); - const yDecimal = new GraphDecimal(__getString(yStringPtr)); + const yDecimalString = __getString(yStringPtr); // Performing the decimal division operation. - const divResult = xDecimal.dividedBy(yDecimal); + const divResult = xDecimal.dividedBy(yDecimalString); const ptr = await __newString(divResult.toString()); const divResultBigDecimal = await BigDecimal.fromString(ptr); @@ -284,10 +281,6 @@ export const instantiate = async ( const expStringPtr = await expBigInt.toString(); const exp = __getString(expStringPtr); - if (parseInt(exp) < MIN_EXP || parseInt(exp) > MAX_EXP) { - throw new Error(`Big decimal exponent '${exp}' is outside the '${MIN_EXP}' to '${MAX_EXP}' range`); - } - const decimal = new GraphDecimal(`${digits}e${exp}`); const ptr = __newString(decimal.toFixed()); @@ -296,21 +289,23 @@ export const instantiate = async ( 'bigDecimal.fromString': async (s: number) => { const string = __getString(s); - // Creating a decimal with the configured precision applied. - const decimal = new GraphDecimal(string).toSignificantDigits(); + // Creating a decimal using custom decimal implementation. + const decimal = new GraphDecimal(string); - // Convert from digits array to BigInt. - const digits = digitsToString(decimal.d); + // Get digits string and exp using decimal 'd' and 'e' properties. + const { digits, exp } = getGraphDigitsAndExp(decimal.value.d, decimal.value.e); + + // Create a digits BigInt using digits string and decimal sign 's' property. const digitsBigNumber = BigNumber.from(digits); - const signBigNumber = BigNumber.from(decimal.s); + const signBigNumber = BigNumber.from(decimal.value.s); const digitsStringPtr = await __newString(digitsBigNumber.mul(signBigNumber).toString()); const digitsBigInt = await BigInt.fromString(digitsStringPtr); - // Calculate exp after converting digits to BigInt above. - const exp = decimal.e - digits.length + 1; + // Create an exp BigInt. const expStringPtr = await __newString(exp.toString()); const expBigInt = await BigInt.fromString(expStringPtr); + // Create a BigDecimal using digits and exp BigInts. const bigDecimal = await BigDecimal.__new(digitsBigInt); bigDecimal.exp = expBigInt; @@ -321,14 +316,15 @@ export const instantiate = async ( const xBigDecimal = await BigDecimal.wrap(x); const xStringPtr = await xBigDecimal.toString(); const xDecimalString = __getString(xStringPtr); + const xDecimal = new GraphDecimal(xDecimalString); // Create decimal y string. const yBigDecimal = await BigDecimal.wrap(y); const yStringPtr = await yBigDecimal.toString(); const yDecimalString = __getString(yStringPtr); - // Perform the decimal sum operation. - const sumResult = GraphDecimal.sum(xDecimalString, yDecimalString); + // Perform the decimal plus operation. + const sumResult = xDecimal.plus(yDecimalString); const ptr = await __newString(sumResult.toString()); const sumResultBigDecimal = await BigDecimal.fromString(ptr); @@ -339,14 +335,15 @@ export const instantiate = async ( const xBigDecimal = await BigDecimal.wrap(x); const xStringPtr = await xBigDecimal.toString(); const xDecimalString = __getString(xStringPtr); + const xDecimal = new GraphDecimal(xDecimalString); // Create decimal y string. const yBigDecimal = await BigDecimal.wrap(y); const yStringPtr = await yBigDecimal.toString(); const yDecimalString = __getString(yStringPtr); - // Perform the decimal sub operation. - const subResult = GraphDecimal.sub(xDecimalString, yDecimalString); + // Perform the decimal minus operation. + const subResult = xDecimal.minus(yDecimalString); const ptr = await __newString(subResult.toString()); const subResultBigDecimal = await BigDecimal.fromString(ptr); @@ -357,14 +354,15 @@ export const instantiate = async ( const xBigDecimal = await BigDecimal.wrap(x); const xStringPtr = await xBigDecimal.toString(); const xDecimalString = __getString(xStringPtr); + const xDecimal = new GraphDecimal(xDecimalString); // Create decimal y string. const yBigDecimal = await BigDecimal.wrap(y); const yStringPtr = await yBigDecimal.toString(); const yDecimalString = __getString(yStringPtr); - // Perform the decimal mul operation. - const mulResult = GraphDecimal.mul(xDecimalString, yDecimalString); + // Perform the decimal times operation. + const mulResult = xDecimal.times(yDecimalString); const ptr = await __newString(mulResult.toString()); const mulResultBigDecimal = await BigDecimal.fromString(ptr); diff --git a/packages/graph-node/src/numbers.test.ts b/packages/graph-node/src/numbers.test.ts index 033269bd..a482c5bf 100644 --- a/packages/graph-node/src/numbers.test.ts +++ b/packages/graph-node/src/numbers.test.ts @@ -4,15 +4,15 @@ import path from 'path'; import { expect } from 'chai'; -import Decimal from 'decimal.js'; import BN from 'bn.js'; +import { GraphDecimal } from '@vulcanize/util'; + import { instantiate } from './loader'; import { getTestDatabase, getTestIndexer } from '../test/utils'; import { Database } from './database'; import { Indexer } from '../test/utils/indexer'; import { - PRECISION, UINT128_MAX, UINT256_MAX, INT256_MIN, @@ -370,25 +370,25 @@ describe('numbers wasm tests', () => { it('should get bigDecimal for DECIMAL128_MAX', async () => { const ptr = await testBigDecimalFromString(await __newString(DECIMAL128_MAX)); - const expected = new Decimal(DECIMAL128_MAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should get bigDecimal for DECIMAL128_MIN', async () => { const ptr = await testBigDecimalFromString(await __newString(DECIMAL128_MIN)); - const expected = new Decimal(DECIMAL128_MIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should get bigDecimal for DECIMAL128_NMAX', async () => { const ptr = await testBigDecimalFromString(await __newString(DECIMAL128_NMAX)); - const expected = new Decimal(DECIMAL128_NMAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_NMAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should get bigDecimal for DECIMAL128_PMIN', async () => { const ptr = await testBigDecimalFromString(await __newString(DECIMAL128_PMIN)); - const expected = new Decimal(DECIMAL128_PMIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_PMIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); }); @@ -407,37 +407,37 @@ describe('numbers wasm tests', () => { it('should execute bigDecimal plus for DECIMAL128_MAX and 0', async () => { const ptr = await testBigDecimalPlus(await __newString(DECIMAL128_MAX), await __newString('0')); - const expected = new Decimal(DECIMAL128_MAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal plus for DECIMAL128_MIN and 0', async () => { const ptr = await testBigDecimalPlus(await __newString(DECIMAL128_MIN), await __newString('0')); - const expected = new Decimal(DECIMAL128_MIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal plus for DECIMAL128_PMIN and 0', async () => { const ptr = await testBigDecimalPlus(await __newString(DECIMAL128_PMIN), await __newString('0')); - const expected = new Decimal(DECIMAL128_PMIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_PMIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal plus for DECIMAL128_NMAX and 0', async () => { const ptr = await testBigDecimalPlus(await __newString(DECIMAL128_NMAX), await __newString('0')); - const expected = new Decimal(DECIMAL128_NMAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_NMAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal plus for DECIMAL128_MAX and DECIMAL128_MIN', async () => { const ptr = await testBigDecimalPlus(await __newString(DECIMAL128_MAX), await __newString(DECIMAL128_MIN)); - const expected = new Decimal('0').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('0').toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal plus for DECIMAL128_PMIN and DECIMAL128_NMAX', async () => { const ptr = await testBigDecimalPlus(await __newString(DECIMAL128_PMIN), await __newString(DECIMAL128_NMAX)); - const expected = new Decimal('0').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('0').toFixed(); expect(__getString(ptr)).to.equal(expected); }); }); @@ -456,61 +456,61 @@ describe('numbers wasm tests', () => { it('should execute bigDecimal minus for DECIMAL128_MAX and 0', async () => { const ptr = await testBigDecimalMinus(await __newString(DECIMAL128_MAX), await __newString('0')); - const expected = new Decimal(DECIMAL128_MAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal minus for 0 and DECIMAL128_MAX', async () => { const ptr = await testBigDecimalMinus(await __newString('0'), await __newString(DECIMAL128_MAX)); - const expected = new Decimal(DECIMAL128_MIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal minus for DECIMAL128_MIN and 0', async () => { const ptr = await testBigDecimalMinus(await __newString(DECIMAL128_MIN), await __newString('0')); - const expected = new Decimal(DECIMAL128_MIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal minus for 0 and DECIMAL128_MIN', async () => { const ptr = await testBigDecimalMinus(await __newString('0'), await __newString(DECIMAL128_MIN)); - const expected = new Decimal(DECIMAL128_MAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal minus for DECIMAL128_PMIN and 0', async () => { const ptr = await testBigDecimalMinus(await __newString(DECIMAL128_PMIN), await __newString('0')); - const expected = new Decimal(DECIMAL128_PMIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_PMIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal minus for 0 and DECIMAL128_PMIN', async () => { const ptr = await testBigDecimalMinus(await __newString('0'), await __newString(DECIMAL128_PMIN)); - const expected = new Decimal(DECIMAL128_NMAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_NMAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal minus for DECIMAL128_NMAX and 0', async () => { const ptr = await testBigDecimalMinus(await __newString(DECIMAL128_NMAX), await __newString('0')); - const expected = new Decimal(DECIMAL128_NMAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_NMAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal minus for 0 and DECIMAL128_NMAX', async () => { const ptr = await testBigDecimalMinus(await __newString('0'), await __newString(DECIMAL128_NMAX)); - const expected = new Decimal(DECIMAL128_PMIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_PMIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal minus for DECIMAL128_MIN and DECIMAL128_MIN', async () => { const ptr = await testBigDecimalMinus(await __newString(DECIMAL128_MIN), await __newString(DECIMAL128_MIN)); - const expected = new Decimal('0').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('0').toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal minus for DECIMAL128_PMIN and DECIMAL128_PMIN', async () => { const ptr = await testBigDecimalMinus(await __newString(DECIMAL128_PMIN), await __newString(DECIMAL128_PMIN)); - const expected = new Decimal('0').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('0').toFixed(); expect(__getString(ptr)).to.equal(expected); }); }); @@ -544,25 +544,25 @@ describe('numbers wasm tests', () => { it('should execute bigDecimal times for DECIMAL128_MAX and 1', async () => { const ptr = await testBigDecimalTimes(await __newString(DECIMAL128_MAX), await __newString('1')); - const expected = new Decimal(DECIMAL128_MAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal times for DECIMAL128_MAX and -1', async () => { const ptr = await testBigDecimalTimes(await __newString(DECIMAL128_MAX), await __newString('-1')); - const expected = new Decimal(DECIMAL128_MIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_MIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal times for DECIMAL128_PMIN and 1', async () => { const ptr = await testBigDecimalTimes(await __newString(DECIMAL128_PMIN), await __newString('1')); - const expected = new Decimal(DECIMAL128_PMIN).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_PMIN).toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal times for DECIMAL128_PMIN and -1', async () => { const ptr = await testBigDecimalTimes(await __newString(DECIMAL128_PMIN), await __newString('-1')); - const expected = new Decimal(DECIMAL128_NMAX).toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal(DECIMAL128_NMAX).toFixed(); expect(__getString(ptr)).to.equal(expected); }); @@ -576,7 +576,7 @@ describe('numbers wasm tests', () => { it('should execute bigDecimal times for DECIMAL128_MAX and DECIMAL128_NMAX', async () => { const ptr = await testBigDecimalTimes(await __newString(DECIMAL128_MAX), await __newString(DECIMAL128_NMAX)); - const expected = new Decimal('-99.99999999999999999999999999999999').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('-99.99999999999999999999999999999999').toFixed(); expect(__getString(ptr)).to.equal(expected); }); }); @@ -595,19 +595,19 @@ describe('numbers wasm tests', () => { it('should execute bigDecimal dividedBy for negative decimal and DECIMAL128_MAX', async () => { const ptr = await testBigDecimalDividedBy(await __newString('-10000.00'), await __newString(DECIMAL128_MAX)); - const expected = new Decimal('-1e-6141').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('-1e-6141').toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal dividedBy for DECIMAL128_MAX and DECIMAL128_MAX', async () => { const ptr = await testBigDecimalDividedBy(await __newString(DECIMAL128_MAX), await __newString(DECIMAL128_MAX)); - const expected = new Decimal('1').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('1').toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal dividedBy for DECIMAL128_MAX and DECIMAL128_MIN', async () => { const ptr = await testBigDecimalDividedBy(await __newString(DECIMAL128_MAX), await __newString(DECIMAL128_MIN)); - const expected = new Decimal('-1').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('-1').toFixed(); expect(__getString(ptr)).to.equal(expected); }); @@ -621,13 +621,13 @@ describe('numbers wasm tests', () => { it('should execute bigDecimal dividedBy for 0 and DECIMAL128_MAX', async () => { const ptr = await testBigDecimalDividedBy(await __newString('0'), await __newString(DECIMAL128_MAX)); - const expected = new Decimal('0').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('0').toFixed(); expect(__getString(ptr)).to.equal(expected); }); it('should execute bigDecimal dividedBy for DECIMAL128_PMIN and DECIMAL128_NMAX', async () => { const ptr = await testBigDecimalDividedBy(await __newString(DECIMAL128_PMIN), await __newString(DECIMAL128_NMAX)); - const expected = new Decimal('-1').toSignificantDigits(PRECISION).toFixed(); + const expected = new GraphDecimal('-1').toFixed(); expect(__getString(ptr)).to.equal(expected); }); }); diff --git a/packages/graph-node/src/utils.ts b/packages/graph-node/src/utils.ts index 50dd1300..38d5c9ca 100644 --- a/packages/graph-node/src/utils.ts +++ b/packages/graph-node/src/utils.ts @@ -3,21 +3,15 @@ import path from 'path'; import fs from 'fs-extra'; import debug from 'debug'; import yaml from 'js-yaml'; -import Decimal from 'decimal.js'; import { ColumnType } from 'typeorm'; import { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata'; +import { GraphDecimal } from '@vulcanize/util'; + import { TypeId, EthereumValueKind, ValueKind } from './types'; const log = debug('vulcanize:utils'); -// Customize Decimal according the limits of IEEE-754 decimal128. -// Reference: https://github.com/graphprotocol/graph-node/blob/v0.24.2/graph/src/data/store/scalar.rs#L42 -export const MIN_EXP = -6143; -export const MAX_EXP = 6144; -export const PRECISION = 34; -export const GraphDecimal = Decimal.clone({ precision: PRECISION }); - export const INT256_MIN = '-57896044618658097711785492504343953926634992332820282019728792003956564819968'; export const INT256_MAX = '57896044618658097711785492504343953926634992332820282019728792003956564819967'; export const UINT128_MAX = '340282366920938463463374607431768211455'; @@ -33,9 +27,6 @@ export const DECIMAL128_PMIN = '1e-6143'; // Maximum -ve decimal value. export const DECIMAL128_NMAX = '-1e-6143'; -// Constant used in function digitsToString. -const LOG_BASE = 7; - interface Transaction { hash: string; index: number; @@ -570,40 +561,3 @@ export const resolveEntityFieldConflicts = (entity: any): any => { return entity; }; - -// Get digits in a string from an array of digit numbers (Decimal().d) -// https://github.com/MikeMcl/decimal.js/blob/master/decimal.mjs#L2516 -export function digitsToString (d: any) { - let i, k, ws; - const indexOfLastWord = d.length - 1; - let str = ''; - let w = d[0]; - - if (indexOfLastWord > 0) { - str += w; - for (i = 1; i < indexOfLastWord; i++) { - ws = d[i] + ''; - k = LOG_BASE - ws.length; - if (k) str += getZeroString(k); - str += ws; - } - - w = d[i]; - ws = w + ''; - k = LOG_BASE - ws.length; - if (k) str += getZeroString(k); - } else if (w === 0) { - return '0'; - } - - // Remove trailing zeros of last w. - for (; w % 10 === 0;) w /= 10; - - return str + w; -} - -function getZeroString (k: any) { - let zs = ''; - for (; k--;) zs += '0'; - return zs; -} diff --git a/packages/graph-node/test/utils/index.ts b/packages/graph-node/test/utils/index.ts index 1e92aa1b..638e9792 100644 --- a/packages/graph-node/test/utils/index.ts +++ b/packages/graph-node/test/utils/index.ts @@ -23,7 +23,8 @@ export const getDummyEventData = (): EventData => { difficulty: '0', gasLimit: '0', gasUsed: '0', - author: ZERO_ADDRESS + author: ZERO_ADDRESS, + size: '0' }; const tx = { diff --git a/packages/graph-test-watcher/src/entity/Author.ts b/packages/graph-test-watcher/src/entity/Author.ts index 4f1ed612..bd3c3ec2 100644 --- a/packages/graph-test-watcher/src/entity/Author.ts +++ b/packages/graph-test-watcher/src/entity/Author.ts @@ -18,21 +18,21 @@ export class Author { @Column('integer') blockNumber!: number; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) blogCount!: bigint; @Column('varchar') - name!: string + name!: string; @Column('integer') - paramInt!: number + paramInt!: number; - @Column('bigint', { transformer: bigintTransformer }) - paramBigInt!: number + @Column('numeric', { transformer: bigintTransformer }) + paramBigInt!: bigint; @Column('varchar') - paramBytes!: string + paramBytes!: string; @Column('numeric', { default: 0, transformer: decimalTransformer }) - rating!: Decimal + rating!: Decimal; } diff --git a/packages/graph-test-watcher/src/entity/Blog.ts b/packages/graph-test-watcher/src/entity/Blog.ts index 40ce50bb..80b2f592 100644 --- a/packages/graph-test-watcher/src/entity/Blog.ts +++ b/packages/graph-test-watcher/src/entity/Blog.ts @@ -32,7 +32,7 @@ export class Blog { @Column('boolean') isActive!: boolean - @Column('bigint', { transformer: bigintArrayTransformer, array: true }) + @Column('numeric', { transformer: bigintArrayTransformer, array: true }) reviews!: bigint[]; @Column('varchar') diff --git a/packages/graph-test-watcher/src/entity/Category.ts b/packages/graph-test-watcher/src/entity/Category.ts index 29c7aed0..f866e9b3 100644 --- a/packages/graph-test-watcher/src/entity/Category.ts +++ b/packages/graph-test-watcher/src/entity/Category.ts @@ -17,7 +17,7 @@ export class Category { @Column('integer') blockNumber!: number; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) count!: bigint; @Column('varchar') diff --git a/packages/graph-test-watcher/src/entity/_Test.ts b/packages/graph-test-watcher/src/entity/_Test.ts index d0faf620..7681c4bb 100644 --- a/packages/graph-test-watcher/src/entity/_Test.ts +++ b/packages/graph-test-watcher/src/entity/_Test.ts @@ -20,7 +20,7 @@ export class _Test { @Column('varchar', { length: 42 }) contractAddress!: string; - @Column('bigint', { transformer: bigintTransformer }) + @Column('numeric', { transformer: bigintTransformer }) value!: bigint; @Column('text', { nullable: true }) diff --git a/packages/util/src/graph-decimal.ts b/packages/util/src/graph-decimal.ts index 0bca9a8c..7a7f2a1c 100644 --- a/packages/util/src/graph-decimal.ts +++ b/packages/util/src/graph-decimal.ts @@ -150,10 +150,10 @@ export class GraphDecimal { // Return n.value if n is an instance of GraphDecimal. if (n instanceof GraphDecimal) { n = n.value; - exp = _getGraphExp(n.d, n.e); + ({ exp } = getGraphDigitsAndExp(n.d, n.e)); } else { const decimal = new Decimal(n); - exp = _getGraphExp(decimal.d, decimal.e); + ({ exp } = getGraphDigitsAndExp(decimal.d, decimal.e)); } if (exp < MIN_EXP || exp > MAX_EXP) { @@ -165,11 +165,14 @@ export class GraphDecimal { } // Get exponent from Decimal d and e according to format in graph-node. -function _getGraphExp (d: any, e: number): number { +export function getGraphDigitsAndExp (d: any, e: number): { digits: string, exp: number } { const digits = _digitsToString(d); const exp = e - digits.length + 1; - return exp; + return { + digits, + exp + }; } // Get digits in a string from an array of digit numbers (Decimal().d)