From 76035a148e7863fa1dbe440920eca34498480aa9 Mon Sep 17 00:00:00 2001 From: Iris Date: Fri, 13 Jan 2023 16:40:14 +0100 Subject: [PATCH] feat: add support for get_state_update in provider --- __tests__/defaultProvider.test.ts | 8 +++++++ src/provider/default.ts | 5 ++++ src/provider/interface.ts | 9 ++++++++ src/provider/rpc.ts | 7 ++++-- src/provider/sequencer.ts | 9 ++++++++ src/types/api/sequencer.ts | 33 +++++++++++++++++++++++++-- src/types/provider.ts | 21 ++++++++++++++++- src/utils/responseParser/rpc.ts | 22 ++++++++++++++++++ src/utils/responseParser/sequencer.ts | 19 +++++++++++++++ www/docs/API/Provider/provider.md | 26 +++++++++++++++++++++ 10 files changed, 154 insertions(+), 5 deletions(-) diff --git a/__tests__/defaultProvider.test.ts b/__tests__/defaultProvider.test.ts index 96d6aa138..3c715674a 100644 --- a/__tests__/defaultProvider.test.ts +++ b/__tests__/defaultProvider.test.ts @@ -81,6 +81,14 @@ describe('defaultProvider', () => { const block = await testProvider.getBlock('latest'); return expect(block).toHaveProperty('block_number'); }); + + test('getStateUpdate()', async () => { + const stateUpdate = await testProvider.getStateUpdate('latest'); + expect(stateUpdate).toHaveProperty('block_hash'); + expect(stateUpdate).toHaveProperty('new_root'); + expect(stateUpdate).toHaveProperty('old_root'); + expect(stateUpdate).toHaveProperty('state_diff'); + }); }); test('getNonceForAddress()', async () => { diff --git a/src/provider/default.ts b/src/provider/default.ts index 84b59188e..c69514f1d 100644 --- a/src/provider/default.ts +++ b/src/provider/default.ts @@ -17,6 +17,7 @@ import { InvocationBulk, InvocationsDetailsWithNonce, InvokeFunctionResponse, + StateUpdateResponse, Status, TransactionSimulationResponse, } from '../types'; @@ -202,4 +203,8 @@ export class Provider implements ProviderInterface { ): Promise { return this.provider.getSimulateTransaction(invocation, invocationDetails, blockIdentifier); } + + public async getStateUpdate(blockIdentifier?: BlockIdentifier): Promise { + return this.provider.getStateUpdate(blockIdentifier); + } } diff --git a/src/provider/interface.ts b/src/provider/interface.ts index 7e7cc9dd4..92b3e248a 100644 --- a/src/provider/interface.ts +++ b/src/provider/interface.ts @@ -18,6 +18,7 @@ import type { InvocationBulk, InvocationsDetailsWithNonce, InvokeFunctionResponse, + StateUpdateResponse, Status, TransactionSimulationResponse, } from '../types'; @@ -318,4 +319,12 @@ export abstract class ProviderInterface { invocationDetails: InvocationsDetailsWithNonce, blockIdentifier?: BlockIdentifier ): Promise; + + /** + * Gets the state changes in a specific block + * + * @param blockIdentifier - block identifier + * @returns StateUpdateResponse + */ + public abstract getStateUpdate(blockIdentifier?: BlockIdentifier): Promise; } diff --git a/src/provider/rpc.ts b/src/provider/rpc.ts index 255f5ca3e..c2232a636 100644 --- a/src/provider/rpc.ts +++ b/src/provider/rpc.ts @@ -16,6 +16,7 @@ import { InvocationsDetailsWithNonce, InvokeFunctionResponse, RPC, + StateUpdateResponse, TransactionSimulationResponse, } from '../types'; import fetch from '../utils/fetchPonyfill'; @@ -167,9 +168,11 @@ export class RpcProvider implements ProviderInterface { public async getStateUpdate( blockIdentifier: BlockIdentifier = this.blockIdentifier - ): Promise { + ): Promise { const block_id = new Block(blockIdentifier).identifier; - return this.fetchEndpoint('starknet_getStateUpdate', { block_id }); + return this.fetchEndpoint('starknet_getStateUpdate', { block_id }).then( + this.responseParser.parseGetStateUpdateResponse + ); } public async getStorageAt( diff --git a/src/provider/sequencer.ts b/src/provider/sequencer.ts index fd4631603..f0b55cb42 100644 --- a/src/provider/sequencer.ts +++ b/src/provider/sequencer.ts @@ -22,6 +22,7 @@ import { InvocationsDetailsWithNonce, InvokeFunctionResponse, Sequencer, + StateUpdateResponse, TransactionSimulationResponse, TransactionTraceResponse, } from '../types'; @@ -587,4 +588,12 @@ export class SequencerProvider implements ProviderInterface { } ).then(this.responseParser.parseFeeSimulateTransactionResponse); } + + public async getStateUpdate( + blockIdentifier: BlockIdentifier = this.blockIdentifier + ): Promise { + return this.fetchEndpoint('get_state_update', { blockIdentifier }).then( + this.responseParser.parseGetStateUpdateResponse + ); + } } diff --git a/src/types/api/sequencer.ts b/src/types/api/sequencer.ts index 6b32c2f3e..7080a5520 100644 --- a/src/types/api/sequencer.ts +++ b/src/types/api/sequencer.ts @@ -70,6 +70,21 @@ export type CallL1Handler = { payload: Array; }; +export type StateDiffItem = { + key: string; + value: string; +}; + +export type DeployedContractItem = { + address: string; + class_hash: string; +}; + +export type Nonces = { + contract_address: string; + nonce: string; +}; + export namespace Sequencer { export type DeclareTransaction = { type: 'DECLARE'; @@ -260,6 +275,20 @@ export namespace Sequencer { export type EstimateFeeResponseBulk = AllowArray; + export type StateUpdateResponse = { + block_hash: string; + new_root: string; + old_root: string; + state_diff: { + storage_diffs: Array<{ + [address: string]: Array; + }>; + declared_contract_hashes: Array; + deployed_contracts: Array; + nonces: Array; + }; + }; + export type Endpoints = { get_contract_addresses: { QUERY: never; @@ -362,10 +391,10 @@ export namespace Sequencer { }; get_state_update: { QUERY: { - blockHash: string; + blockIdentifier: BlockIdentifier; }; REQUEST: never; - RESPONSE: any; + RESPONSE: StateUpdateResponse; }; get_full_contract: { QUERY: { diff --git a/src/types/provider.ts b/src/types/provider.ts index 3a8ea005d..344fe8a31 100644 --- a/src/types/provider.ts +++ b/src/types/provider.ts @@ -4,7 +4,12 @@ */ import BN from 'bn.js'; -import { TransactionTraceResponse } from './api/sequencer'; +import { + DeployedContractItem, + Nonces, + StateDiffItem, + TransactionTraceResponse, +} from './api/sequencer'; import { AllowArray, Call, @@ -140,3 +145,17 @@ export interface TransactionSimulationResponse { trace: TransactionTraceResponse; fee_estimation: EstimateFeeResponse; } + +export interface StateUpdateResponse { + block_hash: string; + new_root: string; + old_root: string; + state_diff: { + storage_diffs: Array<{ + [address: string]: Array; + }>; + declared_contract_hashes: Array; + deployed_contracts: Array; + nonces: Array; + }; +} diff --git a/src/utils/responseParser/rpc.ts b/src/utils/responseParser/rpc.ts index 549cd1a20..0de2f3b9c 100644 --- a/src/utils/responseParser/rpc.ts +++ b/src/utils/responseParser/rpc.ts @@ -8,6 +8,7 @@ import { GetBlockResponse, GetTransactionResponse, RPC, + StateUpdateResponse, } from '../../types'; import { toBN } from '../number'; import { ResponseParser } from '.'; @@ -67,4 +68,25 @@ export class RPCResponseParser result: res, }; } + + public parseGetStateUpdateResponse(res: RPC.StateUpdate): StateUpdateResponse { + const storageDiff = [] + .concat(res.state_diff.storage_diffs as []) + .map(({ address, storage_entries }) => { + return { + [address]: storage_entries, + }; + }); + return { + block_hash: res.block_hash, + new_root: res.new_root, + old_root: res.old_root, + state_diff: { + storage_diffs: storageDiff, + declared_contract_hashes: res.state_diff.declared_contract_hashes, + deployed_contracts: res.state_diff.deployed_contracts, + nonces: res.state_diff.nonces, + }, + }; + } } diff --git a/src/utils/responseParser/sequencer.ts b/src/utils/responseParser/sequencer.ts index 572a00bde..361d4dd29 100644 --- a/src/utils/responseParser/sequencer.ts +++ b/src/utils/responseParser/sequencer.ts @@ -13,6 +13,7 @@ import { GetTransactionResponse, InvokeFunctionResponse, Sequencer, + StateUpdateResponse, TransactionSimulationResponse, } from '../../types'; import { toBN } from '../number'; @@ -193,4 +194,22 @@ export class SequencerAPIResponseParser extends ResponseParser { class_hash: res.class_hash as string, }; } + + public parseGetStateUpdateResponse(res: Sequencer.StateUpdateResponse): StateUpdateResponse { + const nonces = [].concat(res.state_diff.nonces as []).map(({ contract_address, nonce }) => { + return { + contract_address, + nonce: nonce as string, + }; + }); + return { + ...res, + state_diff: { + storage_diffs: res.state_diff.storage_diffs, + declared_contract_hashes: res.state_diff.declared_contract_hashes, + deployed_contracts: res.state_diff.deployed_contracts, + nonces, + }, + }; + } } diff --git a/www/docs/API/Provider/provider.md b/www/docs/API/Provider/provider.md index 7cd3b315e..bf76a4a1a 100644 --- a/www/docs/API/Provider/provider.md +++ b/www/docs/API/Provider/provider.md @@ -250,3 +250,29 @@ Estimate fee for declare transaction. provider.**waitForTransaction**(txHash [ , retryInterval]) => _Promise < GetTransactionReceiptResponse >_ Wait for the transaction to be accepted on L2 or L1. + +--- + +### getStateUpdate() + +provider.**getStateUpdate**(transaction, details) => _Promise < StateUpdateResponse >_ + +Gets the state changes in a specific block + +###### StateUpdateResponse + +```typescript +{ + block_hash: string; + new_root: string; + old_root: string; + state_diff: { + storage_diffs: Array<{ + [address: string]: Array; + }>; + declared_contract_hashes: Array; + deployed_contracts: Array; + nonces: Array; + }; +}; +```