Skip to content

Client/StateManager: storageRangeAt() RPC call / EVMStateManager Interface Extension#2922

Merged
holgerd77 merged 7 commits into
ethereumjs:masterfrom
KoningR:debug-storagerangeat
Aug 9, 2023
Merged

Client/StateManager: storageRangeAt() RPC call / EVMStateManager Interface Extension#2922
holgerd77 merged 7 commits into
ethereumjs:masterfrom
KoningR:debug-storagerangeat

Conversation

@KoningR

@KoningR KoningR commented Jul 28, 2023

Copy link
Copy Markdown
Contributor

This PR implements debug_storageRangeAt() as discussed in ethereum/go-ethereum#14350. An implementation is only provided for DefaultStateManager, not for EthersStateManager. Additionally, hashed key preimages are always null because there does not seem to be a good way to retrieve them currently.

@codecov

codecov Bot commented Jul 29, 2023

Copy link
Copy Markdown

Codecov Report

Merging #2922 (bc2bc69) into master (f704378) will decrease coverage by 2.90%.
The diff coverage is n/a.

Additional details and impacted files

Impacted file tree graph

Flag Coverage Δ
block 88.66% <ø> (ø)
blockchain 92.58% <ø> (ø)
client ?
common ?
ethash ?
evm 69.93% <ø> (ø)
rlp ∅ <ø> (∅)
statemanager ?
trie 89.98% <ø> (+0.03%) ⬆️
tx 95.96% <ø> (ø)
util 86.77% <ø> (ø)
vm 79.20% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

[validators.transaction()],
[validators.blockOption],
])
this.storageRangeAt = middleware(this.storageRangeAt.bind(this), 5, [[validators.hex]])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the validators here will only validate the first arg, reading from comments need 5 validators

/**
* Returns a limited set of storage keys belonging to an account.
* @param params An array of 5 parameters:
* 1. The hash of the block that contains the requested account storage.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* 1. The hash of the block that contains the requested account storage.
* 1. The hash of the block at which to get storage from the state.

just making it less ambiguous

* Returns a limited set of storage keys belonging to an account.
* @param params An array of 5 parameters:
* 1. The hash of the block that contains the requested account storage.
* 2. The number index of the requested transaction within the block.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* 2. The number index of the requested transaction within the block.
* 2. The transaction index of the requested block post which to get the storage.

* 1. The hash of the block that contains the requested account storage.
* 2. The number index of the requested transaction within the block.
* 3. The address of the account.
* 4. The smallest (hashed) storage key that will be returned. To include the entire range, pass '0x00'.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* 4. The smallest (hashed) storage key that will be returned. To include the entire range, pass '0x00'.
* 4. The starting (hashed) key from which storage will be returned. To include the entire range, pass '0x00'.

* 2. The number index of the requested transaction within the block.
* 3. The address of the account.
* 4. The smallest (hashed) storage key that will be returned. To include the entire range, pass '0x00'.
* 5. The maximum number of storage values that will be returned.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* 5. The maximum number of storage values that will be returned.
* 5. The maximum number of storage values that could be returned.


let block: Block
try {
block = await this.service.chain.getBlock(blockHashBytes)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
block = await this.service.chain.getBlock(blockHashBytes)
block = await this.chain.getBlock(blockHashBytes)

this.chain is available

}
}

if (txIndex + 1 > block.transactions.length) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (txIndex + 1 > block.transactions.length) {
if (txIndex >= block.transactions.length) {

more comprehensible about the check

}

try {
const block = await this.service.chain.getBlock(hexToBytes(blockHash))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't the block already read above (in params check) also this.chain can be directly refereed

try {
address = Address.fromString(account)
blockHashBytes = hexToBytes(blockHash)
startKeyBytes = hexToBytes(startKey)

@g11tech g11tech Jul 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

startKey could be directly converted to bigint using a hexToBig... helper , and if limit is also coming as hex encoded it needs to be converted to number/bigint as well as per the requirement

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There does not appear to exist a hexToBigInt() helper. I have however moved the function calls to the same line.

@ScottyPoi ScottyPoi Jul 31, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the hex is '0x' prefixed, you can just use the BigInt constructor like: BigInt('0xabcde')

* @returns A {@link StorageRange} object that will contain at most `limit` entries in its `storage` field.
* The object will also contain `nextKey`, the next (hashed) storage key after the range included in `storage`.
*/
async storageRangeAt(params: [string, number, string, string, number]) {

@g11tech g11tech Jul 29, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
async storageRangeAt(params: [string, number, string, string, number]) {
async storageRangeAt(params: [string, string, string, string, string]) {

most like it will come as a hex encoded number ... not sure about that but do check and update/confirm

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@holgerd77

Copy link
Copy Markdown
Member

Thanks a lot for this PR! 🙏🙂❤️

@KoningR

KoningR commented Jul 31, 2023

Copy link
Copy Markdown
Contributor Author

It appears that parameters txIndex and limit are indeed passed as number instead of as hex strings. Currently, I have omitted validation for these parameters because I could not find a suitable validator in validation.ts. Is it suggested that I parse the input myself or is there a proper validator for the number type?

@holgerd77

Copy link
Copy Markdown
Member

It appears that parameters txIndex and limit are indeed passed as number instead of as hex strings. Currently, I have omitted validation for these parameters because I could not find a suitable validator in validation.ts. Is it suggested that I parse the input myself or is there a proper validator for the number type?

If you are open to do maybe add a very simple get int() validator to validation.ts, as simple as the bool one:

/**
   * bool validator to check if type is boolean
   * @param params parameters of method
   * @param index index of parameter
   */
  get bool() {
    return (params: any[], index: number) => {
      if (typeof params[index] !== 'boolean') {
        return {
          code: INVALID_PARAMS,
          message: `invalid argument ${index}: argument is not boolean`,
        }
      }
    }
  }

[validators.transaction()],
[validators.blockOption],
])
// TODO: txIndex and limit are currently not input validated.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need new validator types for these?

context.createdAddressNoStorage = thirdResult.createdAddress!!
})

it<TestSetup>('Should return the correct (number of) key value pairs.', async ({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the <TestSetup> type parameter do? is it just a label, or does it change the it function?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a typesafe way of passing variables from beforeEach() to tests (see here). For legibility, I had already annotated the TestSetup interface.

throw new Error('Missing VM.')
}

if (txIndex < 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we don't already have a validator for index parameters, it could be worth adding one. especially if there are other methods are doing this themselves

return await vmCopy.stateManager.dumpStorageRange(
// Validator already verified that `account` and `startKey` are properly formatted.
Address.fromString(account),
bytesToBigInt(hexToBytes(startKey)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bytesToBigInt(hexToBytes(startKey)),
BigInt(startKey),

@ScottyPoi

Copy link
Copy Markdown
Contributor

It appears that parameters txIndex and limit are indeed passed as number instead of as hex strings. Currently, I have omitted validation for these parameters because I could not find a suitable validator in validation.ts. Is it suggested that I parse the input myself or is there a proper validator for the number type?

If you are open to do maybe add a very simple get int() validator to validation.ts, as simple as the bool one:

/**
   * bool validator to check if type is boolean
   * @param params parameters of method
   * @param index index of parameter
   */
  get bool() {
    return (params: any[], index: number) => {
      if (typeof params[index] !== 'boolean') {
        return {
          code: INVALID_PARAMS,
          message: `invalid argument ${index}: argument is not boolean`,
        }
      }
    }
  }

Are there methods that use signed integers (negative numbers)? "index" will always be unsigned, so it might be better to add getUint, which throws if the input is < 0

@KoningR KoningR requested a review from ScottyPoi August 4, 2023 13:35

@ScottyPoi ScottyPoi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thanks for including all the tests, and for adding the validator! super helpful 👍

@jochem-brouwer jochem-brouwer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@holgerd77 holgerd77 changed the title Initial version of storageRangeAt(). Client/StateManager: storageRangeAt() RPC call / EVMStateManager Interface Extension Aug 9, 2023

@g11tech g11tech left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@holgerd77 holgerd77 merged commit fa8a518 into ethereumjs:master Aug 9, 2023
@gitpoap-bot

gitpoap-bot Bot commented Aug 9, 2023

Copy link
Copy Markdown

Congrats, your important contribution to this open-source project has earned you a GitPOAP!

GitPOAP: 2023 EthereumJS Contributor:

GitPOAP: 2023 EthereumJS Contributor GitPOAP Badge

Head to gitpoap.io & connect your GitHub account to mint!

Learn more about GitPOAPs here.

@holgerd77

Copy link
Copy Markdown
Member

@KoningR Hi there, thanks again for this great work! 🤩

We'll directly that this into the upcoming releases (so: today)!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants