Skip to content
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

VM: stateManager -> add modifyAccountFields method #1369

Merged
merged 10 commits into from
Jul 27, 2021
3 changes: 3 additions & 0 deletions packages/vm/src/state/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ export interface StorageDump {
[key: string]: string
}

export type AccountFields = Partial<Pick<Account, 'nonce' | 'balance' | 'stateRoot' | 'codeHash'>>

export interface StateManager {
copy(): StateManager
getAccount(address: Address): Promise<Account>
putAccount(address: Address, account: Account): Promise<void>
deleteAccount(address: Address): Promise<void>
touchAccount(address: Address): void
modifyAccountFields(address: Address, accountFields: AccountFields): Promise<void>
putContractCode(address: Address, value: Buffer): Promise<void>
getContractCode(address: Address): Promise<Buffer>
getContractStorage(address: Address, key: Buffer): Promise<Buffer>
Expand Down
19 changes: 18 additions & 1 deletion packages/vm/src/state/stateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { encode, decode } from 'rlp'
import Common, { Chain, Hardfork } from '@ethereumjs/common'
import { genesisStateByName } from '@ethereumjs/common/dist/genesisStates'
import { StateManager, StorageDump } from './interface'
import { AccountFields, StateManager, StorageDump } from './interface'
import Cache from './cache'
import { getActivePrecompiles, ripemdPrecompileAddress } from '../evm/precompiles'
import { short } from '../evm/opcodes'
Expand Down Expand Up @@ -157,11 +157,28 @@ export default class DefaultStateManager implements StateManager {
* This happens when the account is triggered for a state-changing
* event. Touched accounts that are empty will be cleared
* at the end of the tx.
* @param address - Address of the account to touch
*/
touchAccount(address: Address): void {
this._touched.add(address.buf.toString('hex'))
}

/**
* Gets the account associated with `address`, modifies the given account
* fields, then saves the account into state. Account fields can include
* `nonce`, `balance`, `stateRoot`, and `codeHash`.
* @param address - Address of the account to modify
* @param accountFields - Object containing account fields and values to modify
*/
async modifyAccountFields(address: Address, accountFields: AccountFields): Promise<void> {
const account = await this.getAccount(address)
account.nonce = accountFields.nonce ?? account.nonce
account.balance = accountFields.balance ?? account.balance
account.stateRoot = accountFields.stateRoot ?? account.stateRoot
account.codeHash = accountFields.codeHash ?? account.codeHash
await this.putAccount(address, account)
}

/**
* Adds `value` to the state trie as code, and sets `codeHash` on the account
* corresponding to `address` to reference this.
Expand Down
23 changes: 23 additions & 0 deletions packages/vm/tests/api/state/stateManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,29 @@ tape('StateManager', (t) => {
st.end()
}
)

t.test('should modify account fields correctly', async (st) => {
const stateManager = new DefaultStateManager()
const account = createAccount()
const address = new Address(Buffer.from('a94f5374fce5edbc8e2a8697c15331677e6ebf0b', 'hex'))

await stateManager.putAccount(address, account)

await stateManager.modifyAccountFields(address, { balance: new BN(1234) })

const res1 = await stateManager.getAccount(address)

st.equal(res1.balance.toString('hex'), '4d2')

await stateManager.modifyAccountFields(address, { nonce: new BN(1) })

const res2 = await stateManager.getAccount(address)

st.equal(res2.nonce.toNumber(), 1)

st.end()
})

t.test(
'should generate the genesis state root correctly for mainnet from ethereum/tests data',
async (st) => {
Expand Down