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

Bump ethereumjs libraries #304

Merged
merged 1 commit into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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