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
This commit is contained in:
prathamesh0
2021-12-28 16:08:05 +05:30
committed by nabarun
parent 475c34b3fa
commit 5f03ad5029
26 changed files with 121 additions and 167 deletions
+24 -26
View File
@@ -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);
+32 -32
View File
@@ -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);
});
});
+2 -48
View File
@@ -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;
}