-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix how the state of the fork block is handled #1016
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,8 +11,10 @@ import { Map as ImmutableMap, Record as ImmutableRecord } from "immutable"; | |
import { callbackify } from "util"; | ||
|
||
import { JsonRpcClient } from "../../jsonrpc/client"; | ||
import { GenesisAccount } from "../node-types"; | ||
import { PStateManager } from "../types/PStateManager"; | ||
import { StateManager } from "../types/StateManager"; | ||
import { makeAccount } from "../utils/makeAccount"; | ||
|
||
import { AccountState, makeAccountState } from "./Account"; | ||
import { randomHash } from "./random"; | ||
|
@@ -36,7 +38,8 @@ const notSupportedError = (method: string) => | |
|
||
export class ForkStateManager implements PStateManager { | ||
private _state: State = ImmutableMap(); | ||
private _stateRoot: string = randomHash(); | ||
private _initialStateRoot: string = randomHash(); | ||
private _stateRoot: string = this._initialStateRoot; | ||
private _stateRootToState: Map<string, State> = new Map(); | ||
private _originalStorageCache: Map<string, Buffer> = new Map(); | ||
private _stateCheckpoints: string[] = []; | ||
|
@@ -45,9 +48,17 @@ export class ForkStateManager implements PStateManager { | |
|
||
constructor( | ||
private readonly _jsonRpcClient: JsonRpcClient, | ||
private readonly _forkBlockNumber: BN | ||
private readonly _forkBlockNumber: BN, | ||
genesisAccounts: GenesisAccount[] = [] | ||
) { | ||
this._state = ImmutableMap(); | ||
|
||
for (const ga of genesisAccounts) { | ||
const { address, account } = makeAccount(ga); | ||
this._putAccount(address, account); | ||
} | ||
|
||
this._stateRootToState.set(this._initialStateRoot, this._state); | ||
} | ||
|
||
public copy(): ForkStateManager { | ||
|
@@ -104,20 +115,7 @@ export class ForkStateManager implements PStateManager { | |
} | ||
|
||
public async putAccount(address: Buffer, account: Account): Promise<void> { | ||
// Because the vm only ever modifies the nonce, balance and codeHash using this | ||
// method we ignore the stateRoot property | ||
const hexAddress = bufferToHex(address); | ||
let localAccount = this._state.get(hexAddress) ?? makeAccountState(); | ||
localAccount = localAccount | ||
.set("nonce", bufferToHex(account.nonce)) | ||
.set("balance", bufferToHex(account.balance)); | ||
|
||
// Code is set to empty string here to prevent unnecessary | ||
// JsonRpcClient.getCode calls in getAccount method | ||
if (account.codeHash.equals(KECCAK256_NULL)) { | ||
localAccount = localAccount.set("code", "0x"); | ||
} | ||
this._state = this._state.set(hexAddress, localAccount); | ||
this._putAccount(address, account); | ||
} | ||
|
||
public touchAccount(address: Buffer): void { | ||
|
@@ -319,6 +317,10 @@ export class ForkStateManager implements PStateManager { | |
if (this._stateCheckpoints.length !== 0) { | ||
throw checkpointedError("setBlockContext"); | ||
} | ||
if (blockNumber.eq(this._forkBlockNumber)) { | ||
this._setStateRoot(toBuffer(this._initialStateRoot)); | ||
return; | ||
} | ||
Comment on lines
+320
to
+323
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of adding this if statement, we could make the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did exactly the same reasoning, I'm glad that you agree 😅 |
||
if (blockNumber.gt(this._forkBlockNumber)) { | ||
this._setStateRoot(stateRoot); | ||
return; | ||
|
@@ -343,6 +345,23 @@ export class ForkStateManager implements PStateManager { | |
} | ||
} | ||
|
||
private _putAccount(address: Buffer, account: Account): void { | ||
// Because the vm only ever modifies the nonce, balance and codeHash using this | ||
// method we ignore the stateRoot property | ||
const hexAddress = bufferToHex(address); | ||
let localAccount = this._state.get(hexAddress) ?? makeAccountState(); | ||
localAccount = localAccount | ||
.set("nonce", bufferToHex(account.nonce)) | ||
.set("balance", bufferToHex(account.balance)); | ||
|
||
// Code is set to empty string here to prevent unnecessary | ||
// JsonRpcClient.getCode calls in getAccount method | ||
if (account.codeHash.equals(KECCAK256_NULL)) { | ||
localAccount = localAccount.set("code", "0x"); | ||
} | ||
this._state = this._state.set(hexAddress, localAccount); | ||
} | ||
|
||
private _setStateRoot(stateRoot: Buffer) { | ||
const newRoot = bufferToHex(stateRoot); | ||
const state = this._stateRootToState.get(newRoot); | ||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add a test covering the new if statement. Also this describe name in existing tests is no longer valid:
https://github.com/nomiclabs/hardhat/blob/b21474ce1df891edd7fb7b94f8bbc079c652b85a/packages/hardhat-core/test/internal/hardhat-network/provider/fork/ForkStateManager.ts#L613
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this one that I used while developing this: https://github.com/nomiclabs/hardhat/blob/b21474ce1df891edd7fb7b94f8bbc079c652b85a/packages/hardhat-core/test/internal/hardhat-network/provider/modules/eth.ts#L701