diff --git a/__tests__/utils/block.test.ts b/__tests__/utils/block.test.ts new file mode 100644 index 000000000..9407e3c29 --- /dev/null +++ b/__tests__/utils/block.test.ts @@ -0,0 +1,133 @@ +import { Block } from '../../src/utils/provider'; + +describe('new Block()', () => { + test('decimal number 0 BlockIdentifier', () => { + const block = new Block(0); + expect(block.identifier).toMatchObject({ block_number: 0 }); + expect(block.queryIdentifier).toBe('blockNumber=0'); + expect(block.hash).toBe(null); + expect(block.number).toBe(0); + expect(block.tag).toBe(null); + }); + + test('decimal number 631581 BlockIdentifier', () => { + const block1 = new Block(631581); + expect(block1.identifier).toMatchObject({ block_number: 631581 }); + expect(block1.queryIdentifier).toBe('blockNumber=631581'); + expect(block1.hash).toBe(null); + expect(block1.number).toBe(631581); + expect(block1.tag).toBe(null); + }); + + test('non-decimal number -1 BlockIdentifier', () => { + expect(() => { + const block = new Block(-1); + return block; + }).toThrow(TypeError); + }); + + test('decimal string `0` BlockIdentifier', () => { + const block = new Block('0'); + expect(block.identifier).toMatchObject({ block_number: 0 }); + expect(block.queryIdentifier).toBe('blockNumber=0'); + expect(block.hash).toBe(null); + expect(block.number).toBe(0); + expect(block.tag).toBe(null); + }); + + test('decimal string `631581` BlockIdentifier', () => { + const block1 = new Block('631581'); + expect(block1.identifier).toMatchObject({ block_number: 631581 }); + expect(block1.queryIdentifier).toBe('blockNumber=631581'); + expect(block1.hash).toBe(null); + expect(block1.number).toBe(631581); + expect(block1.tag).toBe(null); + }); + + test('non-decimal string `-1` BlockIdentifier', () => { + expect(() => { + const block = new Block('-1'); + return block; + }).toThrow(TypeError); + }); + + test('(Irregular support) hex string `0x0` BlockIdentifier.', () => { + const block = new Block('0x0'); + expect(block.identifier).toMatchObject({ block_hash: '0x0' }); + expect(block.queryIdentifier).toBe('blockHash=0x0'); + expect(block.hash).toBe('0x0'); + expect(block.number).toBe(null); + expect(block.tag).toBe(null); + }); + + test('hex string `0x2a70fb03fe363a2d6be843343a1d81ce6abeda1e9bd5cc6ad8fa9f45e30fdeb` BlockIdentifier', () => { + const block = new Block('0x2a70fb03fe363a2d6be843343a1d81ce6abeda1e9bd5cc6ad8fa9f45e30fdeb'); + expect(block.identifier).toMatchObject({ + block_hash: '0x2a70fb03fe363a2d6be843343a1d81ce6abeda1e9bd5cc6ad8fa9f45e30fdeb', + }); + expect(block.queryIdentifier).toBe( + 'blockHash=0x2a70fb03fe363a2d6be843343a1d81ce6abeda1e9bd5cc6ad8fa9f45e30fdeb' + ); + expect(block.hash).toBe('0x2a70fb03fe363a2d6be843343a1d81ce6abeda1e9bd5cc6ad8fa9f45e30fdeb'); + expect(block.number).toBe(null); + expect(block.tag).toBe(null); + }); + + test('BigInt 1100871802642964430494835386862140987097292376415056243504467124241116103854n BlockIdentifier', () => { + const block = new Block( + 1100871802642964430494835386862140987097292376415056243504467124241116103854n + ); + expect(block.identifier).toMatchObject({ + block_hash: '0x26f12449d649a5339d4891b312a381f23ebc1106792d169b42e6646e87304ae', + }); + expect(block.queryIdentifier).toBe( + 'blockHash=0x26f12449d649a5339d4891b312a381f23ebc1106792d169b42e6646e87304ae' + ); + expect(block.hash).toBe('0x26f12449d649a5339d4891b312a381f23ebc1106792d169b42e6646e87304ae'); + expect(block.number).toBe(null); + expect(block.tag).toBe(null); + }); + + test('String BigInt `1100871802642964430494835386862140987097292376415056243504467124241116103854n` BlockIdentifier', () => { + expect(() => { + const block = new Block( + '1100871802642964430494835386862140987097292376415056243504467124241116103854n' + ); + return block; + }).toThrow(TypeError); + }); + + test('string `pending` BlockIdentifier', () => { + const block1 = new Block('pending'); + expect(block1.identifier).toBe('pending'); + expect(block1.queryIdentifier).toBe('blockNumber=pending'); + expect(block1.hash).toBe(null); + expect(block1.number).toBe(null); + expect(block1.tag).toBe('pending'); + }); + + test('string `latest` BlockIdentifier', () => { + const block1 = new Block('latest'); + expect(block1.identifier).toBe('latest'); + expect(block1.queryIdentifier).toBe('blockNumber=latest'); + expect(block1.hash).toBe(null); + expect(block1.number).toBe(null); + expect(block1.tag).toBe('latest'); + }); + + test('False string `supernova` BlockIdentifier', () => { + expect(() => { + const block = new Block('supernova'); + return block; + }).toThrow(TypeError); + }); + + test('null BlockIdentifier', () => { + const block1 = new Block(null); + expect(block1.identifier).toBe('pending'); + expect(block1.queryIdentifier).toBe('blockNumber=pending'); + expect(block1.hash).toBe(null); + expect(block1.number).toBe(null); + expect(block1.tag).toBe('pending'); + }); +}); diff --git a/__tests__/utils/utils.test.ts b/__tests__/utils/utils.test.ts index f27e6fcf5..aa448a711 100644 --- a/__tests__/utils/utils.test.ts +++ b/__tests__/utils/utils.test.ts @@ -1,7 +1,6 @@ import * as starkCurve from '@scure/starknet'; import { constants, ec, hash, num, stark } from '../../src'; -import { Block } from '../../src/utils/provider'; import { isBigInt, isHex } from '../../src/utils/num'; const { IS_BROWSER } = constants; @@ -117,22 +116,6 @@ describe('calculateContractAddressFromHash()', () => { }); }); -describe('new Block()', () => { - test('Block identifier and queryIdentifier', () => { - const blockA = new Block(0); - expect(blockA.identifier).toMatchObject({ block_number: 0 }); - expect(blockA.queryIdentifier).toBe('blockNumber=0'); - - const blockB = new Block('latest'); - expect(blockB.identifier).toBe('latest'); - expect(blockB.queryIdentifier).toBe('blockNumber=latest'); - - const blockC = new Block('0x01'); - expect(blockC.identifier).toMatchObject({ block_hash: '0x01' }); - expect(blockC.queryIdentifier).toBe('blockHash=0x01'); - }); -}); - describe('Num utility functions', () => { describe('isBigInt', () => { test('should return true for big integers', () => { diff --git a/src/types/lib/index.ts b/src/types/lib/index.ts index e7c6d76ca..d96583f4a 100644 --- a/src/types/lib/index.ts +++ b/src/types/lib/index.ts @@ -210,9 +210,13 @@ export enum BlockTag { export type BlockNumber = BlockTag | null | number; /** - * hex string and BN are detected as block hashes + * hex string and BigInt are detected as block hashes + * * decimal string and number are detected as block numbers - * null appends nothing to the request url + * + * text string are detected as block tag + * + * null return 'pending' block tag */ export type BlockIdentifier = BlockNumber | BigNumberish; diff --git a/src/utils/provider.ts b/src/utils/provider.ts index d76e99218..16da9105c 100644 --- a/src/utils/provider.ts +++ b/src/utils/provider.ts @@ -20,9 +20,9 @@ import { isSierra } from './contract'; import { formatSpaces } from './hash'; import { parse, stringify } from './json'; import { isBigInt, isHex, isNumber, toHex } from './num'; +import { isDecimalString, isString } from './shortString'; import { compressProgram } from './stark'; import type { GetTransactionReceiptResponse } from './transactionReceipt'; -import { isString } from './shortString'; /** * Helper - Async Sleep for 'delay' time @@ -103,6 +103,15 @@ export function txIdentifier(txHash?: BigNumberish, txId?: BigNumberish): string export const validBlockTags = Object.values(BlockTag); +/** + * hex string and BigInt are detected as block hashes. identifier return { block_hash: hash } + * + * decimal string and number are detected as block numbers. identifier return { block_number: number } + * + * text string are detected as block tag. identifier return tag + * + * null is detected as 'pending' block tag. identifier return 'pending' + */ export class Block { hash: BlockIdentifier = null; @@ -112,10 +121,14 @@ export class Block { private setIdentifier(__identifier: BlockIdentifier) { if (isString(__identifier)) { - if (isHex(__identifier)) { + if (isDecimalString(__identifier)) { + this.number = parseInt(__identifier, 10); + } else if (isHex(__identifier)) { this.hash = __identifier; } else if (validBlockTags.includes(__identifier as BlockTag)) { this.tag = __identifier; + } else { + throw TypeError(`Block identifier unmanaged: ${__identifier}`); } } else if (isBigInt(__identifier)) { this.hash = toHex(__identifier); @@ -124,6 +137,10 @@ export class Block { } else { this.tag = BlockTag.pending; } + + if (isNumber(this.number) && this.number < 0) { + throw TypeError(`Block number (${this.number}) can't be negative`); + } } constructor(_identifier: BlockIdentifier) { diff --git a/src/utils/responseParser/rpc.ts b/src/utils/responseParser/rpc.ts index acce51203..4a006ed94 100644 --- a/src/utils/responseParser/rpc.ts +++ b/src/utils/responseParser/rpc.ts @@ -20,8 +20,6 @@ import { toBigInt } from '../num'; import { isString } from '../shortString'; import { estimateFeeToBounds, estimatedFeeToMaxFee } from '../stark'; import { ResponseParser } from '.'; -import { isString } from '../shortString'; - export class RPCResponseParser implements