Skip to content

Commit

Permalink
VM/EVM: move selfdestruct type to set (#2806)
Browse files Browse the repository at this point in the history
* vm/evm: move selfdestruct type to set

* evm: selfdestruct updates

* vm: fix test runner

* vm: fix setting hardfork correctly
  • Loading branch information
jochem-brouwer committed Jun 22, 2023
1 parent b2df147 commit 2e785fa
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 29 deletions.
14 changes: 7 additions & 7 deletions packages/evm/src/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ export class EVM implements EVMInterface {
this.journal
)
if (message.selfdestruct) {
interpreter._result.selfdestruct = message.selfdestruct as { [key: string]: Uint8Array }
interpreter._result.selfdestruct = message.selfdestruct
}
if (message.createdAddresses) {
interpreter._result.createdAddresses = message.createdAddresses
Expand All @@ -738,7 +738,7 @@ export class EVM implements EVMInterface {
result = {
...result,
logs: [],
selfdestruct: {},
selfdestruct: new Set(),
createdAddresses: new Set(),
}
}
Expand Down Expand Up @@ -798,7 +798,7 @@ export class EVM implements EVMInterface {
isCompiled: opts.isCompiled,
isStatic: opts.isStatic,
salt: opts.salt,
selfdestruct: opts.selfdestruct ?? {},
selfdestruct: opts.selfdestruct ?? new Set(),
createdAddresses: opts.createdAddresses ?? new Set(),
delegatecall: opts.delegatecall,
versionedHashes: opts.versionedHashes,
Expand Down Expand Up @@ -868,7 +868,7 @@ export class EVM implements EVMInterface {
// (this only happens the Frontier/Chainstart fork)
// then the error is dismissed
if (err && err.error !== ERROR.CODESTORE_OUT_OF_GAS) {
result.execResult.selfdestruct = {}
result.execResult.selfdestruct = new Set()
result.execResult.createdAddresses = new Set()
result.execResult.gasRefund = BigInt(0)
}
Expand Down Expand Up @@ -914,7 +914,7 @@ export class EVM implements EVMInterface {
caller: opts.caller,
value: opts.value,
depth: opts.depth,
selfdestruct: opts.selfdestruct ?? {},
selfdestruct: opts.selfdestruct ?? new Set(),
isStatic: opts.isStatic,
versionedHashes: opts.versionedHashes,
})
Expand Down Expand Up @@ -1073,9 +1073,9 @@ export interface ExecResult {
*/
logs?: Log[]
/**
* A map from the accounts that have self-destructed to the addresses to send their funds to
* A set of accounts to selfdestruct
*/
selfdestruct?: { [k: string]: Uint8Array }
selfdestruct?: Set<string>
/**
* Map of addresses which were created (used in EIP 6780)
*/
Expand Down
34 changes: 25 additions & 9 deletions packages/evm/src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export interface RunResult {
logs: Log[]
returnValue?: Uint8Array
/**
* A map from the accounts that have self-destructed to the addresses to send their funds to
* A set of accounts to selfdestruct
*/
selfdestruct: { [k: string]: Uint8Array }
selfdestruct: Set<string>

/**
* A map which tracks which addresses were created (used in EIP 6780)
Expand Down Expand Up @@ -160,7 +160,7 @@ export class Interpreter {
this._result = {
logs: [],
returnValue: undefined,
selfdestruct: {},
selfdestruct: new Set(),
}
}

Expand Down Expand Up @@ -840,7 +840,7 @@ export class Interpreter {
}

async _baseCall(msg: Message): Promise<bigint> {
const selfdestruct = { ...this._result.selfdestruct }
const selfdestruct = new Set(this._result.selfdestruct)
msg.selfdestruct = selfdestruct
msg.gasRefund = this._runState.gasRefund

Expand Down Expand Up @@ -882,7 +882,9 @@ export class Interpreter {
}

if (!results.execResult.exceptionError) {
Object.assign(this._result.selfdestruct, selfdestruct)
for (const addressToSelfdestructHex of selfdestruct) {
this._result.selfdestruct.add(addressToSelfdestructHex)
}
if (this._common.isActivatedEIP(6780)) {
// copy over the items to result via iterator
for (const item of createdAddresses!) {
Expand Down Expand Up @@ -910,7 +912,7 @@ export class Interpreter {
data: Uint8Array,
salt?: Uint8Array
): Promise<bigint> {
const selfdestruct = { ...this._result.selfdestruct }
const selfdestruct = new Set(this._result.selfdestruct)
const caller = this._env.address
const depth = this._env.depth + 1

Expand Down Expand Up @@ -954,6 +956,12 @@ export class Interpreter {
versionedHashes: this._env.versionedHashes,
})

let createdAddresses: Set<string>
if (this._common.isActivatedEIP(6780)) {
createdAddresses = new Set(this._result.createdAddresses)
message.createdAddresses = createdAddresses
}

const results = await this._evm.runCall({ message })

if (results.execResult.logs) {
Expand All @@ -975,7 +983,15 @@ export class Interpreter {
!results.execResult.exceptionError ||
results.execResult.exceptionError.error === ERROR.CODESTORE_OUT_OF_GAS
) {
Object.assign(this._result.selfdestruct, selfdestruct)
for (const addressToSelfdestructHex of selfdestruct) {
this._result.selfdestruct.add(addressToSelfdestructHex)
}
if (this._common.isActivatedEIP(6780)) {
// copy over the items to result via iterator
for (const item of createdAddresses!) {
this._result.createdAddresses!.add(item)
}
}
// update stateRoot on current contract
const account = await this._stateManager.getAccount(this._env.address)
if (!account) {
Expand Down Expand Up @@ -1017,11 +1033,11 @@ export class Interpreter {

async _selfDestruct(toAddress: Address): Promise<void> {
// only add to refund if this is the first selfdestruct for the address
if (this._result.selfdestruct[bytesToHex(this._env.address.bytes)] === undefined) {
if (!this._result.selfdestruct.has(bytesToHex(this._env.address.bytes))) {
this.refundGas(this._common.param('gasPrices', 'selfdestructRefund'))
}

this._result.selfdestruct[bytesToHex(this._env.address.bytes)] = toAddress.bytes
this._result.selfdestruct.add(bytesToHex(this._env.address.bytes))

// Add to beneficiary balance
let toAccount = await this._stateManager.getAccount(toAddress)
Expand Down
9 changes: 4 additions & 5 deletions packages/evm/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ interface MessageOpts {
isCompiled?: boolean
salt?: Uint8Array
/**
* A map of addresses to selfdestruct, see {@link Message.selfdestruct}
* A set of addresses to selfdestruct, see {@link Message.selfdestruct}
*/
selfdestruct?: { [key: string]: boolean } | { [key: string]: Uint8Array }
selfdestruct?: Set<string>
/**
* Map of addresses which were created (used in EIP 6780)
*/
Expand All @@ -53,10 +53,9 @@ export class Message {
salt?: Uint8Array
containerCode?: Uint8Array /** container code for EOF1 contracts - used by CODECOPY/CODESIZE */
/**
* Map of addresses to selfdestruct. Key is the unprefixed address.
* Value is a boolean when marked for destruction and replaced with a Uint8Array containing the address where the remaining funds are sent.
* Set of addresses to selfdestruct. Key is the unprefixed address.
*/
selfdestruct?: { [key: string]: boolean } | { [key: string]: Uint8Array }
selfdestruct?: Set<string>
/**
* Map of addresses which were created (used in EIP 6780)
*/
Expand Down
8 changes: 4 additions & 4 deletions packages/evm/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ export interface EVMRunCallOpts {
*/
salt?: Uint8Array
/**
* Addresses to selfdestruct. Defaults to none.
* Addresses to selfdestruct. Defaults to the empty set.
*/
selfdestruct?: { [k: string]: boolean }
selfdestruct?: Set<string>
/**
* Created addresses in current context. Used in EIP 6780
*/
Expand Down Expand Up @@ -171,9 +171,9 @@ export interface EVMRunCodeOpts {
*/
isStatic?: boolean
/**
* Addresses to selfdestruct. Defaults to none.
* Addresses to selfdestruct. Defaults to the empty set.
*/
selfdestruct?: { [k: string]: boolean }
selfdestruct?: Set<string>
/**
* The address of the account that is executing this code (`address(this)`). Defaults to the zero address.
*/
Expand Down
5 changes: 2 additions & 3 deletions packages/vm/src/runTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,8 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise<RunTxResult> {
* Cleanup accounts
*/
if (results.execResult.selfdestruct !== undefined) {
const keys = Object.keys(results.execResult.selfdestruct)
for (const k of keys) {
const address = new Address(hexToBytes(k))
for (const addressToSelfdestructHex of results.execResult.selfdestruct) {
const address = new Address(hexToBytes(addressToSelfdestructHex))
if (this._common.isActivatedEIP(6780)) {
// skip cleanup of addresses not in createdAddresses
if (!results.execResult.createdAddresses!.has(address.toString())) {
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/test/tester/runners/BlockchainTestsRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export async function runBlockchainTest(options: any, testData: any, t: tape.Tes
await blockBuilder.revert() // will only revert if checkpointed
}

const block = Block.fromRLPSerializedBlock(blockRlp, { common })
const block = Block.fromRLPSerializedBlock(blockRlp, { common, setHardfork: TD })
await blockchain.putBlock(block)

// This is a trick to avoid generating the canonical genesis
Expand Down

0 comments on commit 2e785fa

Please sign in to comment.