Skip to content

Commit

Permalink
Bump ethereumjs libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
2xic committed Mar 14, 2024
1 parent 601d79d commit f3baa0e
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 753 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/node_modules
/.pnp
.pnp.js
.yarn

# testing
/coverage
Expand Down
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
10 changes: 7 additions & 3 deletions components/Editor/SolidityAdvanceModeTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import React, {
} from 'react'

import { EvmError } from '@ethereumjs/evm/src/exceptions'
import { Address } from '@ethereumjs/util'
import abi from 'ethereumjs-abi'
import { Address, BN, bufferToHex } from 'ethereumjs-util'
import { BN, bufferToHex } from 'ethereumjs-util'
import Select, { OnChangeValue } from 'react-select'

import { isEmpty } from 'util/string'
Expand All @@ -32,7 +33,7 @@ interface Props {
) => Promise<
| {
error?: EvmError | undefined
returnValue: Buffer
returnValue: Uint8Array
createdAddress: Address | undefined
}
| undefined
Expand Down Expand Up @@ -207,6 +208,9 @@ const SolidityAdvanceModeTab: FC<Props> = ({
getCallValue(),
Address.fromString(deployedContractAddress),
)
if (!transaction) {
return
}

const result = await startTransaction(transaction)
if (
Expand All @@ -217,7 +221,7 @@ const SolidityAdvanceModeTab: FC<Props> = ({
log(
`run method complete, the response is ${abi.rawDecode(
selectedMethod.outputs.map((mi) => mi.type),
result.returnValue,
Buffer.from(result.returnValue),
)}`,
)
} else if (!result.error) {
Expand Down
9 changes: 7 additions & 2 deletions components/Editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import React, {
Fragment,
} from 'react'

import { bufferToHex } from '@ethereumjs/util'
import { encode, decode } from '@kunigi/string-compression'
import cn from 'classnames'
import copy from 'copy-to-clipboard'
import { bufferToHex } from 'ethereumjs-util'
import { useRouter } from 'next/router'
import Select, { OnChangeValue } from 'react-select'
import SCEditor from 'react-simple-code-editor'
Expand Down Expand Up @@ -144,18 +144,23 @@ const Editor = ({ readOnly = false }: Props) => {
loadInstructions(bc)
setIsCompiling(false)

if (!transaction) {
return
}

const result = await startTransaction(transaction)
if (
codeType === CodeType.Solidity &&
!result.error &&
result.returnValue
) {
setMethodByteCode(bufferToHex(result.returnValue))
setMethodByteCode(bufferToHex(Buffer.from(result.returnValue)))
}
return result
} catch (error) {
log((error as Error).message, 'error')
setIsCompiling(false)
return undefined
}
},
[
Expand Down
89 changes: 57 additions & 32 deletions context/ethereumContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ import { Buffer } from 'buffer'
import React, { createContext, useEffect, useState, useRef } from 'react'

import { Block } from '@ethereumjs/block'
import { Common, Chain } from '@ethereumjs/common'
import { HardforkConfig } from '@ethereumjs/common/src/types'
import { RunState, InterpreterStep } from '@ethereumjs/evm/dist/interpreter'
import { EvmError } from '@ethereumjs/evm/src/exceptions'
import { Opcode } from '@ethereumjs/evm/src/opcodes'
import { getActivePrecompiles } from '@ethereumjs/evm/src/precompiles'
import { TypedTransaction, TxData, Transaction } from '@ethereumjs/tx'
import { Common, Chain, HardforkTransitionConfig } from '@ethereumjs/common'
import {
EVM,
EvmError,
EVMResult,
getActivePrecompiles,
InterpreterStep,
} from '@ethereumjs/evm'
import { Opcode, OpcodeList } from '@ethereumjs/evm/src/opcodes'
import { TypedTransaction, TxData, TransactionFactory } from '@ethereumjs/tx'
import { Address, Account } from '@ethereumjs/util'
import { VM } from '@ethereumjs/vm'
//
import OpcodesMeta from 'opcodes.json'
import PrecompiledMeta from 'precompiled.json'
import {
Expand All @@ -31,8 +33,12 @@ import {
} from 'util/gas'
import { toHex, fromBuffer } from 'util/string'

// NOTE: Importing the type directly caused issues
type RunState = EVMResult['execResult']['runState']

let vm: VM
let common: Common
let currentOpcodes: OpcodeList | undefined

const storageMemory = new Map()
const privateKey = Buffer.from(
Expand All @@ -49,9 +55,9 @@ export const prevrandaoDocName = '44_merge'
type ContextProps = {
common: Common | undefined
chains: IChain[]
forks: HardforkConfig[]
forks: HardforkTransitionConfig[]
selectedChain: IChain | undefined
selectedFork: HardforkConfig | undefined
selectedFork: HardforkTransitionConfig | undefined
opcodes: IReferenceItem[]
precompiled: IReferenceItem[]
instructions: IInstruction[]
Expand All @@ -66,12 +72,12 @@ type ContextProps = {
byteCode: string,
value: bigint,
to?: Address,
) => Promise<TypedTransaction | TxData>
) => Promise<TypedTransaction | TxData | undefined>
loadInstructions: (byteCode: string) => void
startExecution: (byteCode: string, value: bigint, data: string) => void
startTransaction: (tx: TypedTransaction | TxData) => Promise<{
error?: EvmError
returnValue: Buffer
returnValue: Uint8Array
createdAddress: Address | undefined
}>
continueExecution: () => void
Expand Down Expand Up @@ -109,7 +115,7 @@ export const EthereumContext = createContext<ContextProps>({
onForkChange: () => undefined,
transactionData: () =>
new Promise((resolve) => {
resolve({})
resolve(undefined)
}),
loadInstructions: () => undefined,
startExecution: () => undefined,
Expand All @@ -130,9 +136,9 @@ export const CheckIfAfterMergeHardfork = (forkName?: string) => {

export const EthereumProvider: React.FC<{}> = ({ children }) => {
const [chains, setChains] = useState<IChain[]>([])
const [forks, setForks] = useState<HardforkConfig[]>([])
const [forks, setForks] = useState<HardforkTransitionConfig[]>([])
const [selectedChain, setSelectedChain] = useState<IChain>()
const [selectedFork, setSelectedFork] = useState<HardforkConfig>()
const [selectedFork, setSelectedFork] = useState<HardforkTransitionConfig>()
const [opcodes, setOpcodes] = useState<IReferenceItem[]>([])
const [precompiled, setPrecompiled] = useState<IReferenceItem[]>([])
const [instructions, setInstructions] = useState<IInstruction[]>([])
Expand Down Expand Up @@ -169,6 +175,11 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {

vm = await VM.create({ common })

const evm = new EVM({
common,
})
currentOpcodes = evm.getActiveOpcodes()

if (!skipChainsLoading) {
_loadChainAndForks(common)
}
Expand All @@ -178,7 +189,7 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
_setupStateManager()
_setupAccount()

vm.evm.events!.on(
vm.evm.events?.on(
'step',
(e: InterpreterStep, contFunc: ((result?: any) => void) | undefined) => {
_stepInto(e, contFunc)
Expand Down Expand Up @@ -226,20 +237,24 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
gasLimit,
gasPrice: 10,
data: '0x' + data,
nonce: account.nonce,
nonce: account?.nonce,
}

return Transaction.fromTxData(txData).sign(privateKey)
return TransactionFactory.fromTxData(txData).sign(privateKey)
}

/**
* Loads contract instructions to the context state.
* @param byteCode The contract bytecode.
*/
const loadInstructions = (byteCode: string) => {
const opcodes = vm.evm.getActiveOpcodes!()
const opcodes = currentOpcodes
const instructions: IInstruction[] = []

if (!opcodes) {
return
}

for (let i = 0; i < byteCode.length; i += 2) {
const instruction = parseInt(byteCode.slice(i, i + 2), 16)
// The id to reference back with breakpoints
Expand Down Expand Up @@ -292,7 +307,7 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
* Starts EVM execution of the instructions.
* @param tx The transaction data to run from.
*/
const startTransaction = (tx: TypedTransaction | TxData) => {
const startTransaction = (tx: TypedTransaction | TxData | undefined) => {
// always start paused
isExecutionPaused.current = true
setIsExecuting(true)
Expand Down Expand Up @@ -409,7 +424,7 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
const _loadChainAndForks = (common: Common) => {
const chainIds: number[] = []
const chainNames: string[] = []
const forks: HardforkConfig[] = []
const forks: HardforkTransitionConfig[] = []

// iterate over TS enum to pick key,val
for (const chain in Chain) {
Expand Down Expand Up @@ -488,7 +503,7 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
const _loadOpcodes = () => {
const opcodes: IReferenceItem[] = []

vm.evm.getActiveOpcodes!().forEach((op: Opcode) => {
currentOpcodes?.forEach((op: Opcode) => {
const opcode = extractDocFromOpcode(op)

opcode.minimumFee = parseInt(
Expand Down Expand Up @@ -552,9 +567,14 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
// respectively AFTER applying the original methods.
// This is necessary in order to handle storage operations easily.
const _setupStateManager = () => {
const proxyStateManager = traceMethodCalls(vm.evm.eei)
vm.evm.eei.putContractStorage = proxyStateManager.putContractStorage
vm.evm.eei.clearContractStorage = proxyStateManager.clearContractStorage
const evm = vm.evm
if (evm instanceof EVM) {
const proxyStateManager = traceMethodCalls(evm.stateManager)
vm.evm.stateManager.putContractStorage =
proxyStateManager.putContractStorage
vm.evm.stateManager.clearContractStorage =
proxyStateManager.clearContractStorage
}

storageMemory.clear()
}
Expand Down Expand Up @@ -587,17 +607,17 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
exceptionError,
}: {
totalGasSpent: bigint
runState?: RunState
runState: RunState | undefined
newContractAddress?: Address
returnValue?: Buffer
returnValue?: Uint8Array
exceptionError?: EvmError
}) => {
if (runState) {
const { programCounter: pc, stack, memory, memoryWordCount } = runState
_setExecutionState({
pc,
totalGasSpent,
stack: stack._store,
stack: stack.getStack(),
memory: memory._store,
memoryWordCount,
returnValue,
Expand Down Expand Up @@ -681,10 +701,10 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
pc: number
totalGasSpent: bigint
stack: bigint[]
memory: Buffer
memory: Uint8Array
memoryWordCount: bigint
currentGas?: bigint | number
returnValue?: Buffer
returnValue?: Uint8Array
}) => {
const storage: IStorage[] = []

Expand All @@ -698,10 +718,15 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
programCounter: pc,
stack: stack.map((value) => value.toString(16)).reverse(),
totalGas: totalGasSpent.toString(),
memory: fromBuffer(memory).substring(0, Number(memoryWordCount) * 64),
memory: fromBuffer(Buffer.from(memory)).substring(
0,
Number(memoryWordCount) * 64,
),
storage,
currentGas: currentGas ? currentGas.toString() : undefined,
returnValue: returnValue ? returnValue.toString('hex') : undefined,
returnValue: returnValue
? Buffer.from(returnValue).toString('hex')
: undefined,
})
}

Expand Down
19 changes: 19 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { withPlausibleProxy } = require('next-plausible')

// eslint-disable-next-line @typescript-eslint/no-var-requires
const nodeModuleReplacement = require('./webpack/nodeModuleReplacement')

module.exports = withPlausibleProxy()({
reactStrictMode: true,
serverRuntimeConfig: {
Expand All @@ -21,6 +24,19 @@ module.exports = withPlausibleProxy()({
],
})

// NOTE: Needed to clear the import assert from rustbn used by ethereumjs
config.module.rules.push({
test: /\.js$/,
include: [dir],
use: [
{
loader: './webpack/importAssertTransformer.js',
},
],
})
// NOTE: Needed to transform various node imports from ethereumjs
config.plugins.push(nodeModuleReplacement.default)

config.resolve.fallback = {
fs: false,
stream: false,
Expand All @@ -29,7 +45,10 @@ module.exports = withPlausibleProxy()({
process: require.resolve('process/browser'),
assert: require.resolve('assert/'),
events: require.resolve('events/'),
buffer: require.resolve('buffer/'),
}
// NOTE: Needed because rustbn used by ethereumjs is having a top level await
config.experiments.topLevelAwait = true

return config
},
Expand Down
18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,20 @@
"@types/react-dom": "17.0.2"
},
"dependencies": {
"@ethereumjs/block": "^4.2.0",
"@ethereumjs/common": "^3.1.0",
"@ethereumjs/evm": "^1.3.0",
"@ethereumjs/statemanager": "^1.0.3",
"@ethereumjs/tx": "^4.1.0",
"@ethereumjs/util": "^8.0.4",
"@ethereumjs/vm": "^6.4.0",
"@ethereumjs/block": "^5.1.1",
"@ethereumjs/common": "^4.2.0",
"@ethereumjs/evm": "^2.2.1",
"@ethereumjs/statemanager": "^2.2.2",
"@ethereumjs/tx": "^5.2.1",
"@ethereumjs/util": "^9.0.2",
"@ethereumjs/vm": "^7.2.1",
"@kunigi/string-compression": "1.0.2",
"@mdx-js/loader": "^2.3.0",
"@mdx-js/react": "^2.3.0",
"@types/ethereumjs-abi": "^0.6.3",
"assert": "^2.0.0",
"babel-preset-es2020": "^1.0.2",
"buffer": "^6.0.3",
"classnames": "^2.3.1",
"copy-to-clipboard": "^3.3.1",
"ethereumjs-abi": "^0.6.8",
Expand All @@ -49,7 +50,8 @@
"react-select": "^5.1.0",
"react-simple-code-editor": "^0.11.2",
"react-table": "^7.7.0",
"react-tooltip": "^4.2.21"
"react-tooltip": "^4.2.21",
"readable-stream": "^4.5.2"
},
"devDependencies": {
"@babel/core": "^7.19.1",
Expand Down
Loading

0 comments on commit f3baa0e

Please sign in to comment.