Skip to content

Commit

Permalink
feat: new Block utility object, rpc fetch clenup, open rpc fetch api
Browse files Browse the repository at this point in the history
  • Loading branch information
tabaktoni committed Sep 2, 2022
1 parent 5c56584 commit 0d381c8
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 110 deletions.
16 changes: 7 additions & 9 deletions __tests__/defaultProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,11 @@ describe('defaultProvider', () => {

describeIfNotDevnet('Provider', () => {
const provider = getTestProvider();
let latestBlock;
describe(`Provider methods if not devnet`, () => {
describe('getBlock', () => {
test('pending', async () => {
const latestBlock = await provider.getBlock();
test('getBlock by tag pending', async () => {
latestBlock = await provider.getBlock();
expect(latestBlock).toHaveProperty('block_hash');
expect(latestBlock).toHaveProperty('parent_hash');
expect(latestBlock).toHaveProperty('block_number');
Expand All @@ -153,11 +154,8 @@ describe('defaultProvider', () => {
expect(Array.isArray(latestBlock.transactions)).toBe(true);
});

test('Block Hash 0x8a30a1212d142cb0053fe9921e1dbf64f651d328565bd2e7ac24059c270f43', async () => {
const block = await provider.getBlock(
'0x8a30a1212d142cb0053fe9921e1dbf64f651d328565bd2e7ac24059c270f43'
);

test('getBlock by Hash', async () => {
const block = await provider.getBlock(latestBlock.block_hash);
expect(block).toHaveProperty('block_hash');
expect(block).toHaveProperty('parent_hash');
expect(block).toHaveProperty('block_number');
Expand All @@ -168,8 +166,8 @@ describe('defaultProvider', () => {
expect(Array.isArray(block.transactions)).toBe(true);
});

test('Block Number 102634', async () => {
const block = await provider.getBlock(102634);
test('getBlock by Number', async () => {
const block = await provider.getBlock(latestBlock.block_number);
expect(block).toHaveProperty('block_hash');
expect(block).toHaveProperty('parent_hash');
expect(block).toHaveProperty('block_number');
Expand Down
14 changes: 13 additions & 1 deletion __tests__/rpcProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,22 @@ describeIfRpc('RPCProvider', () => {
rpcProvider = getTestProvider() as RpcProvider;
});

describe('RPC methods', () => {
describe('RPC methods', async () => {
const latestBlock = await rpcProvider.getBlock('latest');

test('getChainId', async () => {
const chainId = await rpcProvider.getChainId();
expect(chainId).toBe('0x534e5f474f45524c49');
});

test('getBlockWithTxHashes', async () => {
const blockResponse = await rpcProvider.getBlockWithTxHashes(latestBlock.block_number);
expect(blockResponse).toHaveProperty('transactions');
});

test('getBlockWithTxs', async () => {
const blockResponse = await rpcProvider.getBlockWithTxs(latestBlock.block_number);
expect(blockResponse).toHaveProperty('transactions');
});
});
});
17 changes: 17 additions & 0 deletions __tests__/utils/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs';

import { constants, hash, json, number, stark } from '../../src';
import { Block } from '../../src/provider/utils';
import { pedersen } from '../../src/utils/hash';

const { IS_BROWSER } = constants;
Expand Down Expand Up @@ -112,3 +113,19 @@ 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');
});
});
72 changes: 30 additions & 42 deletions src/provider/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { parseCalldata, parseContract, wait } from '../utils/provider';
import { RPCResponseParser } from '../utils/responseParser/rpc';
import { randomAddress } from '../utils/stark';
import { ProviderInterface } from './interface';
import { BlockIdentifier, BlockIdentifierClass } from './utils';
import { Block, BlockIdentifier } from './utils';

export type RpcProviderOptions = { nodeUrl: string };

Expand All @@ -44,37 +44,32 @@ export class RpcProvider implements ProviderInterface {
});
}

public fetch(method: any, params: any): Promise<any> {
return fetch(this.nodeUrl, {
method: 'POST',
body: stringify({ method, jsonrpc: '2.0', params, id: 0 }),
headers: { 'Content-Type': 'application/json' },
});
}

protected errorHandler(error: any) {
if (error) {
const { code, message } = error;
throw new Error(`${code}: ${message}`);
}
}

protected async fetchEndpoint<T extends keyof RPC.Methods>(
method: T,
request?: RPC.Methods[T]['REQUEST']
): Promise<RPC.Methods[T]['RESPONSE']> {
const requestData = {
method,
jsonrpc: '2.0',
params: request,
id: 0,
};

try {
const rawResult = await fetch(this.nodeUrl, {
method: 'POST',
body: stringify(requestData),
headers: {
'Content-Type': 'application/json',
},
});
const rawResult = await this.fetch(method, request);
const { error, result } = await rawResult.json();
if (error) {
const { code, message } = error;
throw new Error(`${code}: ${message}`);
} else {
return result as RPC.Methods[T]['RESPONSE'];
}
this.errorHandler(error);
return result as RPC.Methods[T]['RESPONSE'];
} catch (error: any) {
const data = error?.response?.data;
if (data?.message) {
throw new Error(`${data.code}: ${data.message}`);
}
this.errorHandler(error?.response?.data);
throw error;
}
}
Expand All @@ -93,17 +88,15 @@ export class RpcProvider implements ProviderInterface {
public async getBlockWithTxHashes(
blockIdentifier: BlockIdentifier = 'pending'
): Promise<RPC.GetBlockWithTxHashesResponse> {
const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
return this.fetchEndpoint('starknet_getBlockWithTxHashes', [
blockIdentifierGetter.getIdentifier(),
]);
const block = new Block(blockIdentifier);
return this.fetchEndpoint('starknet_getBlockWithTxHashes', [block.identifier]);
}

public async getBlockWithTxs(
blockIdentifier: BlockIdentifier = 'pending'
): Promise<RPC.GetBlockWithTxs> {
const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
return this.fetchEndpoint('starknet_getBlockWithTxs', [blockIdentifierGetter.getIdentifier()]);
const block = new Block(blockIdentifier);
return this.fetchEndpoint('starknet_getBlockWithTxs', [block.identifier]);
}

public async getNonce(contractAddress: string): Promise<any> {
Expand All @@ -116,11 +109,11 @@ export class RpcProvider implements ProviderInterface {
blockIdentifier: BlockIdentifier = 'pending'
): Promise<BigNumberish> {
const parsedKey = toHex(toBN(key));
const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
const block = new Block(blockIdentifier);
return this.fetchEndpoint('starknet_getStorageAt', [
contractAddress,
parsedKey,
blockIdentifierGetter.getIdentifier(),
block.identifier,
]);
}

Expand Down Expand Up @@ -149,11 +142,8 @@ export class RpcProvider implements ProviderInterface {
}

public async getClassAt(contractAddress: string, blockIdentifier: BlockIdentifier): Promise<any> {
const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
return this.fetchEndpoint('starknet_getClassAt', [
blockIdentifierGetter.getIdentifier(),
contractAddress,
]);
const block = new Block(blockIdentifier);
return this.fetchEndpoint('starknet_getClassAt', [block.identifier, contractAddress]);
}

public async getEstimateFee(
Expand Down Expand Up @@ -292,10 +282,8 @@ export class RpcProvider implements ProviderInterface {
public async getTransactionCount(
blockIdentifier: BlockIdentifier
): Promise<RPC.GetTransactionCountResponse> {
const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
return this.fetchEndpoint('starknet_getBlockTransactionCount', [
blockIdentifierGetter.getIdentifier(),
]);
const block = new Block(blockIdentifier);
return this.fetchEndpoint('starknet_getBlockTransactionCount', [block.identifier]);
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/provider/sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { randomAddress } from '../utils/stark';
import { buildUrl } from '../utils/url';
import { GatewayError, HttpError } from './errors';
import { ProviderInterface } from './interface';
import { BlockIdentifier, getFormattedBlockIdentifier } from './utils';
import { Block, BlockIdentifier } from './utils';

type NetworkName = 'mainnet-alpha' | 'goerli-alpha';

Expand Down Expand Up @@ -129,7 +129,8 @@ export class SequencerProvider implements ProviderInterface {
const queryString = Object.entries(query)
.map(([key, value]) => {
if (key === 'blockIdentifier') {
return `${getFormattedBlockIdentifier(value)}`;
const block = new Block(value);
return `${block.queryIdentifier}`;
}
return `${key}=${value}`;
})
Expand Down
99 changes: 43 additions & 56 deletions src/provider/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable max-classes-per-file */
import type { BlockNumber } from '../types';
import { BigNumberish, isHex, toBN, toHex } from '../utils/number';

Expand Down Expand Up @@ -33,73 +34,59 @@ export function txIdentifier(txHash?: BigNumberish, txId?: BigNumberish): string
// null appends nothing to the request url

export type BlockIdentifier = BlockNumber | BigNumberish;
type BlockIdentifierObject =
| { type: 'BLOCK_NUMBER'; data: BlockNumber }
| { type: 'BLOCK_HASH'; data: BigNumberish };

export class BlockIdentifierClass {
blockIdentifier: BlockIdentifier;
export class Block {
hash: BlockIdentifier = null;

constructor(blockIdentifier: BlockIdentifier) {
this.blockIdentifier = blockIdentifier;
number: BlockIdentifier = null;

tag: BlockIdentifier = null;

private setIdentifier: (_identifier: BlockIdentifier) => void;

constructor(_identifier: BlockIdentifier) {
this.setIdentifier = function (__identifier: BlockIdentifier) {
if (typeof __identifier === 'string' && isHex(__identifier)) {
this.hash = __identifier;
} else if (typeof __identifier === 'number') {
this.number = __identifier;
} else {
this.tag = __identifier;
}
};

this.setIdentifier(_identifier);
}

getIdentifier() {
if (typeof this.blockIdentifier === 'string' && isHex(this.blockIdentifier)) {
return { block_hash: this.blockIdentifier };
get queryIdentifier(): any {
if (this.number !== null) {
return `blockNumber=${this.number}`;
}

if (typeof this.blockIdentifier === 'number') {
return { block_number: this.blockIdentifier };
if (this.hash !== null) {
return `blockHash=${this.hash}`;
}

return this.blockIdentifier;
return `blockNumber=${this.tag}`;
}
}

/**
* Identifies the block to be queried.
*
* @param blockIdentifier - block identifier
* @returns block identifier object
*/
export function getBlockIdentifier(blockIdentifier: BlockIdentifier): BlockIdentifierObject {
if (blockIdentifier === null || blockIdentifier === 'latest') {
return { type: 'BLOCK_NUMBER', data: 'latest' }; // default to latest block
}
if (blockIdentifier === 'pending') {
return { type: 'BLOCK_NUMBER', data: 'pending' };
}
if (typeof blockIdentifier === 'number' || typeof blockIdentifier === 'bigint') {
return { type: 'BLOCK_NUMBER', data: blockIdentifier };
}
if (typeof blockIdentifier === 'string' && blockIdentifier.startsWith('0x')) {
return { type: 'BLOCK_HASH', data: blockIdentifier };
}
if (typeof blockIdentifier === 'string' && !Number.isNaN(parseInt(blockIdentifier, 10))) {
return { type: 'BLOCK_NUMBER', data: parseInt(blockIdentifier, 10) };
}
if (typeof blockIdentifier === 'string') {
throw new Error(`Invalid block identifier: ${blockIdentifier}`);
}
return { type: 'BLOCK_HASH', data: blockIdentifier };
}
get identifier(): any {
if (this.number !== null) {
return { block_number: this.number };
}

/**
* Gets the block identifier for API request
*
* [Reference](https://github.com/starkware-libs/cairo-lang/blob/fc97bdd8322a7df043c87c371634b26c15ed6cee/src/starkware/starknet/services/api/feeder_gateway/feeder_gateway_client.py#L164-L173)
*
* @param blockIdentifier
* @returns block identifier for API request
*/
export function getFormattedBlockIdentifier(blockIdentifier: BlockIdentifier = null): string {
const blockIdentifierObject = getBlockIdentifier(blockIdentifier);
if (blockIdentifierObject.type === 'BLOCK_NUMBER' && blockIdentifierObject.data === null) {
return '';
if (this.hash !== null) {
return { block_hash: this.hash };
}

return this.tag;
}
if (blockIdentifierObject.type === 'BLOCK_NUMBER') {
return `blockNumber=${blockIdentifierObject.data}`;

set identifier(_identifier: BlockIdentifier) {
this.setIdentifier(_identifier);
}
return `blockHash=${toHex(toBN(blockIdentifierObject.data))}`;

valueOf = () => this.number;

toString = () => this.hash;
}

0 comments on commit 0d381c8

Please sign in to comment.