Skip to content

Commit

Permalink
vm, client: continuing v6 breaking changes (#1815)
Browse files Browse the repository at this point in the history
* vm: v6 breaking changes

* update benchmark util to use gasUsed as bigint

* VM: fixed gasUsed rebase related bug

Co-authored-by: Holger Drewes <Holger.Drewes@gmail.com>
  • Loading branch information
2 people authored and g11tech committed Jun 2, 2022
1 parent 4266744 commit c345203
Show file tree
Hide file tree
Showing 29 changed files with 137 additions and 244 deletions.
8 changes: 4 additions & 4 deletions packages/client/lib/execution/receipt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { PreByzantiumTxReceipt, PostByzantiumTxReceipt, TxReceipt } from '@ether
import { Log } from '@ethereumjs/vm/dist/evm/types'
import Bloom from '@ethereumjs/vm/dist/bloom'
import { TypedTransaction } from '@ethereumjs/tx'
import { rlp, intToBuffer, bufferToInt } from 'ethereumjs-util'
import { rlp, intToBuffer, bufferToInt, bigIntToBuffer, bufferToBigInt } from 'ethereumjs-util'
import { MetaDBManager, DBKey } from '../util/metaDBManager'
import type { Block } from '@ethereumjs/block'

Expand Down Expand Up @@ -302,7 +302,7 @@ export class ReceiptsManager extends MetaDBManager {
value.map((r) => [
(r as PreByzantiumTxReceipt).stateRoot ??
intToBuffer((r as PostByzantiumTxReceipt).status),
r.gasUsed,
bigIntToBuffer(r.gasUsed),
this.rlp(RlpConvert.Encode, RlpType.Logs, r.logs),
])
)
Expand All @@ -315,14 +315,14 @@ export class ReceiptsManager extends MetaDBManager {
// Pre-Byzantium Receipt
return {
stateRoot: r[0],
gasUsed,
gasUsed: bufferToBigInt(gasUsed),
logs,
} as PreByzantiumTxReceipt
} else {
// Post-Byzantium Receipt
return {
status: bufferToInt(r[0]),
gasUsed,
gasUsed: bufferToBigInt(gasUsed),
logs,
} as PostByzantiumTxReceipt
}
Expand Down
8 changes: 6 additions & 2 deletions packages/client/lib/net/protocol/ethprotocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ export class EthProtocol extends Protocol {
let encodedReceipt = rlp.encode([
(receipt as PreByzantiumTxReceipt).stateRoot ??
(receipt as PostByzantiumTxReceipt).status,
receipt.gasUsed,
bigIntToBuffer(receipt.gasUsed),
receipt.bitvector,
receipt.logs,
])
Expand All @@ -253,7 +253,11 @@ export class EthProtocol extends Protocol {
// Legacy receipt if r[0] >= 0xc0, otherwise typed receipt with first byte as TransactionType
const decoded = rlp.decode(r[0] >= 0xc0 ? r : r.slice(1)) as any
const [stateRootOrStatus, cumulativeGasUsed, logsBloom, logs] = decoded
const receipt = { gasUsed: cumulativeGasUsed, bitvector: logsBloom, logs } as TxReceipt
const receipt = {
gasUsed: bufferToBigInt(cumulativeGasUsed),
bitvector: logsBloom,
logs,
} as TxReceipt
if (stateRootOrStatus.length === 32) {
;(receipt as PreByzantiumTxReceipt).stateRoot = stateRootOrStatus
} else {
Expand Down
2 changes: 1 addition & 1 deletion packages/client/lib/rpc/modules/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ const jsonRpcReceipt = async (
blockNumber: bigIntToHex(block.header.number),
from: tx.getSenderAddress().toString(),
to: tx.to?.toString() ?? null,
cumulativeGasUsed: bufferToHex(receipt.gasUsed),
cumulativeGasUsed: bigIntToHex(receipt.gasUsed),
effectiveGasPrice: bigIntToHex(effectiveGasPrice),
gasUsed: bigIntToHex(gasUsed),
contractAddress: contractAddress?.toString() ?? null,
Expand Down
2 changes: 2 additions & 0 deletions packages/client/lib/service/fullethereumservice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Hardfork } from '@ethereumjs/common'
import { Skeleton } from '../sync/skeleton'
import { bigIntToBuffer } from 'ethereumjs-util'
import { EthereumService, EthereumServiceOptions } from './ethereumservice'
import { TxPool } from './txpool'
import { BeaconSynchronizer, FullSynchronizer } from '../sync'
Expand Down Expand Up @@ -259,6 +260,7 @@ export class FullEthereumService extends EthereumService {
let receiptsSize = 0
for (const hash of hashes) {
const blockReceipts = await receiptsManager.getReceipts(hash, true, true)
blockReceipts.forEach((r) => (r.gasUsed = bigIntToBuffer(r.gasUsed) as any))
if (!blockReceipts) continue
receipts.push(...blockReceipts)
receiptsSize += Buffer.byteLength(JSON.stringify(blockReceipts))
Expand Down
2 changes: 1 addition & 1 deletion packages/client/lib/util/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const main = async () => {
const stateManager = new DefaultStateManager({ trie, common })
// Ensure we run on the right root
stateManager.setStateRoot(Buffer.from('${(
await execution.vm.stateManager.getStateRoot(true)
await execution.vm.stateManager.getStateRoot()
).toString('hex')}', 'hex'))
Expand Down
6 changes: 3 additions & 3 deletions packages/client/test/net/protocol/ethprotocol.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { FeeMarketEIP1559Transaction } from '@ethereumjs/tx'
import { Chain } from '../../../lib/blockchain/chain'
import { Config } from '../../../lib/config'
import { EthProtocol } from '../../../lib/net/protocol'
import { bigIntToBuffer, bufferToBigInt, intToBuffer } from 'ethereumjs-util'
import { bigIntToBuffer, bufferToBigInt } from 'ethereumjs-util'

tape('[EthProtocol]', (t) => {
t.test('should get properties', (t) => {
Expand Down Expand Up @@ -150,14 +150,14 @@ tape('[EthProtocol]', (t) => {
const receipts = [
{
status: 1 as 0 | 1,
gasUsed: intToBuffer(100),
gasUsed: BigInt(100),
bitvector: Buffer.alloc(256),
logs: [[Buffer.alloc(20), [Buffer.alloc(32), Buffer.alloc(32, 1)], Buffer.alloc(10)]],
txType: 2,
},
{
status: 0 as 0 | 1,
gasUsed: intToBuffer(1000),
gasUsed: BigInt(1000),
bitvector: Buffer.alloc(256, 1),
logs: [[Buffer.alloc(20, 1), [Buffer.alloc(32, 1), Buffer.alloc(32, 1)], Buffer.alloc(10)]],
txType: 0,
Expand Down
5 changes: 2 additions & 3 deletions packages/client/test/service/fullethereumservice.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import tape from 'tape'
import td from 'testdouble'
import Common from '@ethereumjs/common'
import { Log } from '@ethereumjs/vm/dist/evm/types'
import { intToBuffer } from 'ethereumjs-util'
import { Config } from '../../lib/config'
import { Event } from '../../lib/types'
import { Chain } from '../../lib/blockchain'
Expand Down Expand Up @@ -161,7 +160,7 @@ tape('[FullEthereumService]', async (t) => {
const receipts = [
{
status: 1 as 0 | 1,
gasUsed: intToBuffer(100),
gasUsed: BigInt(100),
bitvector: Buffer.alloc(256),
logs: [
[Buffer.alloc(20), [Buffer.alloc(32), Buffer.alloc(32, 1)], Buffer.alloc(10)],
Expand All @@ -170,7 +169,7 @@ tape('[FullEthereumService]', async (t) => {
},
{
status: 0 as 0 | 1,
gasUsed: intToBuffer(1000),
gasUsed: BigInt(1000),
bitvector: Buffer.alloc(256, 1),
logs: [
[Buffer.alloc(20, 1), [Buffer.alloc(32, 1), Buffer.alloc(32, 1)], Buffer.alloc(10)],
Expand Down
6 changes: 3 additions & 3 deletions packages/vm/benchmarks/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ export const verifyResult = (block: Block, result: RunBlockResult) => {
// check if there are receipts
const { receipts } = result
if (receipts) {
let cumGasUsed = 0
let cumGasUsed = BigInt(0)
for (let index = 0; index < receipts.length; index++) {
let gasUsedExpected = parseInt(receipts[index].gasUsed.toString('hex'), 16)
let cumGasUsedActual = parseInt(receipts[index].gasUsed.toString('hex'), 16)
let gasUsedExpected = receipts[index].gasUsed
let cumGasUsedActual = receipts[index].gasUsed
let gasUsed = cumGasUsedActual - cumGasUsed
if (gasUsed !== gasUsedExpected) {
console.log(`[DEBUG]
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/src/buildBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export class BlockBuilder {
await this.rewardMiner()
}

const stateRoot = await this.vm.stateManager.getStateRoot(true)
const stateRoot = await this.vm.stateManager.getStateRoot()
const transactionsTrie = await this.transactionsTrie()
const receiptTrie = await this.receiptTrie()
const logsBloom = this.logsBloom()
Expand Down
12 changes: 3 additions & 9 deletions packages/vm/src/evm/eei.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,7 @@ export default class EEI {
getBlockCoinbase(): bigint {
let coinbase: Address
if (this._common.consensusAlgorithm() === ConsensusAlgorithm.Clique) {
// Backwards-compatibilty check
// TODO: can be removed along VM v5 release
if ('cliqueSigner' in this._env.block.header) {
coinbase = this._env.block.header.cliqueSigner()
} else {
coinbase = Address.zero()
}
coinbase = this._env.block.header.cliqueSigner()
} else {
coinbase = this._env.block.header.coinbase
}
Expand Down Expand Up @@ -581,7 +575,7 @@ export default class EEI {
}

// this should always be safe
this.useGas(results.gasUsed, 'CALL, STATICCALL, DELEGATECALL, CALLCODE')
this.useGas(results.execResult.gasUsed, 'CALL, STATICCALL, DELEGATECALL, CALLCODE')

// Set return value
if (
Expand Down Expand Up @@ -654,7 +648,7 @@ export default class EEI {
}

// this should always be safe
this.useGas(results.gasUsed, 'CREATE')
this.useGas(results.execResult.gasUsed, 'CREATE')

// Set return buffer in case revert happened
if (
Expand Down
46 changes: 19 additions & 27 deletions packages/vm/src/evm/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
MAX_INTEGER,
} from 'ethereumjs-util'
import { Block } from '@ethereumjs/block'
import { Hardfork } from '@ethereumjs/common'
import { ERROR, VmError } from '../exceptions'
import { StateManager } from '../state/index'
import { PrecompileFunc } from './precompiles'
Expand All @@ -31,17 +32,17 @@ const debugGas = createDebugLogger('vm:evm:gas')
*/
export interface EVMResult {
/**
* Amount of gas used by the transaction
*/
gasUsed: bigint
/**
* Address of created account durint transaction, if any
* Address of created account during transaction, if any
*/
createdAddress?: Address
/**
* Contains the results from running the code, if any, as described in {@link runCode}
*/
execResult: ExecResult
/**
* Total amount of gas to be refunded from all nested calls.
*/
gasRefund?: bigint
}

/**
Expand All @@ -50,15 +51,15 @@ export interface EVMResult {
export interface ExecResult {
runState?: RunState
/**
* Description of the exception, if any occured
* Description of the exception, if any occurred
*/
exceptionError?: VmError
/**
* Amount of gas left
*/
gas?: bigint
/**
* Amount of gas the code used to run
* Amount of gas the transaction used to run
*/
gasUsed: bigint
/**
Expand All @@ -73,10 +74,6 @@ export interface ExecResult {
* A map from the accounts that have self-destructed to the addresses to send their funds to
*/
selfdestruct?: { [k: string]: Buffer }
/**
* Total amount of gas to be refunded from all nested calls.
*/
gasRefund?: bigint
}

export interface NewContractEvent {
Expand Down Expand Up @@ -195,26 +192,27 @@ export default class EVM {
result = await this._executeCreate(message)
}
if (this._vm.DEBUG) {
const { gasUsed, exceptionError, returnValue, gasRefund } = result.execResult
const { gasUsed, exceptionError, returnValue } = result.execResult
debug(
`Received message execResult: [ gasUsed=${gasUsed} exceptionError=${
exceptionError ? `'${exceptionError.error}'` : 'none'
} returnValue=0x${short(returnValue)} gasRefund=${gasRefund ?? 0} ]`
} returnValue=0x${short(returnValue)} gasRefund=${result.gasRefund ?? 0} ]`
)
}
const err = result.execResult.exceptionError
// This clause captures any error which happened during execution
// If that is the case, then set the _refund tracker to the old refund value
if (err) {
// TODO: Move `gasRefund` to a tx-level result object
// instead of `ExecResult`.
this._refund = oldRefund
result.execResult.selfdestruct = {}
}
result.execResult.gasRefund = this._refund
result.gasRefund = this._refund

if (err) {
if (this._vm._common.gteHardfork('homestead') || err.error != ERROR.CODESTORE_OUT_OF_GAS) {
if (
this._vm._common.gteHardfork(Hardfork.Homestead) ||
err.error != ERROR.CODESTORE_OUT_OF_GAS
) {
result.execResult.logs = []
await this._state.revert()
this._transientStorage.revert()
Expand Down Expand Up @@ -278,7 +276,6 @@ export default class EVM {
}
if (exit) {
return {
gasUsed: BigInt(0),
execResult: {
gasUsed: BigInt(0),
exceptionError: errorMessage, // Only defined if addToBalance failed
Expand All @@ -305,7 +302,6 @@ export default class EVM {
}

return {
gasUsed: result.gasUsed,
execResult: result,
}
}
Expand All @@ -318,7 +314,6 @@ export default class EVM {
if (this._vm._common.isActivatedEIP(3860)) {
if (message.data.length > this._vm._common.param('vm', 'maxInitCodeSize')) {
return {
gasUsed: message.gasLimit,
createdAddress: message.to,
execResult: {
returnValue: Buffer.alloc(0),
Expand Down Expand Up @@ -346,7 +341,6 @@ export default class EVM {
debug(`Returning on address collision`)
}
return {
gasUsed: message.gasLimit,
createdAddress: message.to,
execResult: {
returnValue: Buffer.alloc(0),
Expand All @@ -367,7 +361,7 @@ export default class EVM {

toAccount = await this._state.getAccount(message.to)
// EIP-161 on account creation and CREATE execution
if (this._vm._common.gteHardfork('spuriousDragon')) {
if (this._vm._common.gteHardfork(Hardfork.SpuriousDragon)) {
toAccount.nonce += BigInt(1)
}

Expand All @@ -394,7 +388,6 @@ export default class EVM {
}
if (exit) {
return {
gasUsed: BigInt(0),
createdAddress: message.to,
execResult: {
gasUsed: BigInt(0),
Expand Down Expand Up @@ -426,7 +419,7 @@ export default class EVM {
let allowedCodeSize = true
if (
!result.exceptionError &&
this._vm._common.gteHardfork('spuriousDragon') &&
this._vm._common.gteHardfork(Hardfork.SpuriousDragon) &&
result.returnValue.length > this._vm._common.param('vm', 'maxCodeSize')
) {
allowedCodeSize = false
Expand Down Expand Up @@ -470,7 +463,7 @@ export default class EVM {
result.gasUsed = totalGas
}
} else {
if (this._vm._common.gteHardfork('homestead')) {
if (this._vm._common.gteHardfork(Hardfork.Homestead)) {
if (this._vm.DEBUG) {
debug(`Not enough gas or code size not allowed (>= Homestead)`)
}
Expand Down Expand Up @@ -498,7 +491,7 @@ export default class EVM {
}
} else if (CodestoreOOG) {
// This only happens at Frontier. But, let's do a sanity check;
if (!this._vm._common.gteHardfork('homestead')) {
if (!this._vm._common.gteHardfork(Hardfork.Homestead)) {
// Pre-Homestead behavior; put an empty contract.
// This contract would be considered "DEAD" in later hard forks.
// It is thus an unecessary default item, which we have to save to dik
Expand All @@ -510,7 +503,6 @@ export default class EVM {
}

return {
gasUsed: result.gasUsed,
createdAddress: message.to,
execResult: result,
}
Expand Down
7 changes: 1 addition & 6 deletions packages/vm/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,6 @@ export interface VMOpts {
* A {@link StateManager} instance to use as the state store (Beta API)
*/
stateManager?: StateManager
/**
* A {@link SecureTrie} instance for the state tree (ignored if stateManager is passed)
* @deprecated will be removed in next major version release
*/
state?: Trie
/**
* A {@link Blockchain} object for storing/retrieving blocks
*/
Expand Down Expand Up @@ -306,7 +301,7 @@ export default class VM extends AsyncEventEmitter {
if (opts.stateManager) {
this.stateManager = opts.stateManager
} else {
const trie = opts.state ?? new Trie()
const trie = new Trie()
this.stateManager = new DefaultStateManager({
trie,
common: this._common,
Expand Down
Loading

0 comments on commit c345203

Please sign in to comment.