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

feat: adding EOFv1 opcodes #339

Closed
wants to merge 38 commits into from
Closed
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e2f83c6
feat: add EOF toggle
hangleang Jul 30, 2024
23aa697
add ethereumjs-monorepo as submodule
hangleang Jul 31, 2024
2af2edc
fix: update @ethereumjs/* pkgs, update context
hangleang Jul 31, 2024
ea0d33f
Revert "fix: update @ethereumjs/* pkgs, update context"
hangleang Aug 1, 2024
4de8a89
fix: add @ethjs-eof/* pkgs, fix babel transpiler
hangleang Aug 1, 2024
2091a90
feat: add list of EOF opcodes overview
hangleang Aug 2, 2024
5f9c572
fix: ignore confused package on IDE
hangleang Aug 2, 2024
8505d9a
chore: move EOF opcodes to cancun for simplicity
hangleang Aug 3, 2024
f4b564b
fix: don't show EOF on prev forks
hangleang Aug 3, 2024
2c5f56c
feat: add relative jump opcodes content
hangleang Aug 3, 2024
afd2431
feat: add EXT*CALL content & fee calculation
hangleang Aug 3, 2024
c8cf1b9
feat: add contract creation & fee calculation
hangleang Aug 4, 2024
347ec25
feat: add subroutines content
hangleang Aug 6, 2024
ced137e
fix: change section name
hangleang Aug 6, 2024
a352d23
feat: add data section access content
hangleang Aug 6, 2024
5ab7861
fix: update content, opcode params
hangleang Aug 6, 2024
1c76065
feat: add stack manipulation content
hangleang Aug 6, 2024
23eefe8
feat: add tooltip on EOF toggle
hangleang Aug 6, 2024
290660b
fix: dark theme bg color
hangleang Aug 6, 2024
be4ab3d
fix: toggle styling
hangleang Aug 7, 2024
2401f8e
fix: change reverted reason
hangleang Aug 9, 2024
68876f9
chore: naming consistency
hangleang Aug 20, 2024
e560bda
chore: naming consistency on `EXTCALL`
hangleang Aug 20, 2024
3d6610d
chore: naming consistency on `EXTSTATICCALL`
hangleang Aug 20, 2024
eda0334
fix: compiler warning on confusing packages name
hangleang Aug 20, 2024
ea8c4b9
chore: add immediate argument section
hangleang Aug 20, 2024
a147255
chore: change to immediate argument
hangleang Aug 20, 2024
8f20229
chore: remove immediate args from stack inputs
hangleang Aug 20, 2024
e94ce26
fix: ignore the replace package name
hangleang Aug 20, 2024
695ad27
fix: apply Brage suggestion on fixing playground
hangleang Aug 21, 2024
5aedc7b
fix: remove memory stack changes in returndataload opcode
hangleang Aug 25, 2024
bfbf99f
fix: remove another memory stack changes in returndataload opcode
hangleang Aug 25, 2024
25bb330
chore: update doc reference
hangleang Aug 25, 2024
9b6e2fd
fix: move eof opcodes into its own hardfork
hangleang Aug 25, 2024
ae42a86
fix: eslint
hangleang Aug 25, 2024
8773dee
fix: faking EOF hardfork display
hangleang Aug 29, 2024
f6c62c3
chore(docs): easy peasy commit to rename forkname
hangleang Aug 29, 2024
26c137d
fix: dynamic fee calculation and formula not shown
hangleang Aug 30, 2024
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
12 changes: 12 additions & 0 deletions .babelrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"presets": [
[
"next/babel",
{
"preset-env": {
"exclude": ["transform-exponentiation-operator"]
}
}
]
]
}
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ public
@/
tailwind.config.js
.eslintrc.js

# monorepo
ethereumjs-monorepo
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "ethereumjs-monorepo"]
path = ethereumjs-monorepo
url = https://github.com/ethereumjs/ethereumjs-monorepo.git
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
**/*.mdx
pnpm-lock.yaml
ethereumjs-monorepo
39 changes: 39 additions & 0 deletions components/EOFToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useContext, useCallback } from 'react'

import Image from 'next/image'
import eofIcon from 'public/eof_icon.png'
import { Tooltip } from 'react-tooltip'

import { EthereumContext } from 'context/ethereumContext'

import { Toggle } from 'components/ui'

const EOFToggle = () => {
const { showEOF, toggleEOFShow } = useContext(EthereumContext)

const handleEOFToggle = useCallback(() => {
toggleEOFShow()
}, [toggleEOFShow])

return (
<div className="flex justify-end items-center rounded">
<div className="flex items-center mr-2">
<span
className="flex items-center pl-2 text-gray-400 dark:text-black-400"
data-tooltip-content="Toggle viewing EOF opcodes"
data-tooltip-id={`tip-toggle-eof`}
>
<Image alt="EOF icon" src={eofIcon} width={30} height={30} />
<Tooltip className="tooltip" id={`tip-toggle-eof`} />
<Toggle
id="eof-toggle"
onChange={handleEOFToggle}
isChecked={showEOF}
/>
</span>
</div>
</div>
)
}

export default EOFToggle
2 changes: 2 additions & 0 deletions components/layouts/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ThemeSelector from 'components/ThemeSelector'
import { Container, Logo, Hamburger } from 'components/ui'

import ChainSelector from '../ChainSelector'
import EOFToggle from '../EOFToggle'

const Nav = () => {
const [isMenuVisible, setIsMenuVisible] = useState(false)
Expand Down Expand Up @@ -52,6 +53,7 @@ const Nav = () => {

<div className="items-center ml-auto flex">
<ChainSelector />
<EOFToggle />
<ThemeSelector />
</div>

Expand Down
39 changes: 39 additions & 0 deletions components/ui/Toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { ChangeEvent } from 'react'

type Props = {
id: string
onChange: (event: ChangeEvent<HTMLInputElement>) => void
isChecked: boolean
text?: string
isDisabled?: boolean
}

export const Toggle: React.FC<Props> = ({
id,
onChange,
isChecked,
text,
isDisabled,
}) => {
return (
<label className="flex items-center cursor-pointer relative text-sm">
<input
id={id}
type="checkbox"
checked={isChecked}
disabled={isDisabled || false}
onChange={onChange}
className="peer sr-only"
/>
<label htmlFor={id} className="hidden">
{''}
</label>
<div className="peer h-6 w-11 rounded-full bg-gray-200 dark:bg-gray-900 border-2 after:absolute after:left-[5px] after:top-1 after:h-4 after:w-4 after:rounded-full after:bg-white after:transition-all after:content-[''] peer-checked:bg-indigo-800 peer-checked:after:translate-x-[1.1rem]"></div>
{text && (
<span className="ml-2 text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white">
{text}
</span>
)}
</label>
)
}
1 change: 1 addition & 0 deletions components/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './Message'
export * from './Radio'
export * from './RelativeLink'
export * from './StackBox'
export * from './Toggle'
93 changes: 87 additions & 6 deletions context/ethereumContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import { Opcode, OpcodeList } from '@ethereumjs/evm/src/opcodes'
import { TypedTransaction, TxData, TransactionFactory } from '@ethereumjs/tx'
import { Address, Account, bytesToHex } from '@ethereumjs/util'
import { VM } from '@ethereumjs/vm'
import { Common as EOFCommon } from '@ethjs-eof/common'
// @ts-ignore it confused with pre-EOF version
import { createEVM, EVM as EOFEVM } from '@ethjs-eof/evm'
import { VM as EOFVM } from '@ethjs-eof/vm'
import OpcodesMeta from 'opcodes.json'
import PrecompiledMeta from 'precompiled.json'
import {
Expand All @@ -27,15 +31,19 @@ import {
ITransientStorage,
} from 'types'

import { CURRENT_FORK, FORKS_WITH_TIMESTAMPS } from 'util/constants'
import {
CURRENT_FORK,
EOF_ENABLED_FORK,
FORKS_WITH_TIMESTAMPS,
} from 'util/constants'
import {
calculateOpcodeDynamicFee,
calculatePrecompiledDynamicFee,
} from 'util/gas'
import { toHex, fromBuffer } from 'util/string'

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

const storageMemory = new Map()
Expand All @@ -50,9 +58,12 @@ const contractAddress = Address.generate(accountAddress, 1n)
const gasLimit = 0xffffffffffffn
const postMergeHardforkNames: Array<string> = ['merge', 'shanghai', 'cancun']
export const prevrandaoDocName = '44_merge'
const EOF_EIPS = [
663, 3540, 3670, 4200, 4750, 5450, 6206, 7069, 7480, 7620, 7698,
]

type ContextProps = {
common: Common | undefined
common: Common | EOFCommon | undefined
chains: IChain[]
forks: HardforkTransitionConfig[]
selectedChain: IChain | undefined
Expand All @@ -64,6 +75,7 @@ type ContextProps = {
isExecuting: boolean
executionState: IExecutionState
vmError: string | undefined
showEOF: boolean

onChainChange: (chainId: number) => void
onForkChange: (forkName: string) => void
Expand All @@ -84,6 +96,7 @@ type ContextProps = {
removeBreakpoint: (instructionId: number) => void
nextExecution: () => void
resetExecution: () => void
toggleEOFShow: () => void
}

const initialExecutionState: IExecutionState = {
Expand All @@ -110,6 +123,7 @@ export const EthereumContext = createContext<ContextProps>({
isExecuting: false,
executionState: initialExecutionState,
vmError: undefined,
showEOF: false,

onChainChange: () => undefined,
onForkChange: () => undefined,
Expand All @@ -125,6 +139,7 @@ export const EthereumContext = createContext<ContextProps>({
removeBreakpoint: () => undefined,
nextExecution: () => undefined,
resetExecution: () => undefined,
toggleEOFShow: () => undefined,
})

export const CheckIfAfterMergeHardfork = (forkName?: string) => {
Expand All @@ -150,6 +165,7 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
string | undefined
>()
const [vmError, setVmError] = useState<string | undefined>()
const [showEOF, setShowEOF] = useState(false)

const nextStepFunction = useRef<any>()
const isExecutionPaused = useRef(true)
Expand Down Expand Up @@ -197,6 +213,44 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
)
}

/**
* Initializes the EVM instance.
*/
const initVmInstanceWithEOF = async (
skipChainsLoading?: boolean,
chainId?: Chain,
fork?: string,
) => {
common = new EOFCommon({
chain: Chain.Mainnet,
hardfork: fork || CURRENT_FORK,
eips: fork == EOF_ENABLED_FORK ? EOF_EIPS : [],
})

vm = await EOFVM.create({ common })

const evm = await createEVM({
common,
})
currentOpcodes = evm.getActiveOpcodes()

if (!skipChainsLoading) {
_loadChainAndForks(common)
}

_loadOpcodes()
_loadPrecompiled()
_setupStateManager()
_setupAccount()

vm.evm.events?.on(
'step',
(e: InterpreterStep, contFunc: ((result?: any) => void) | undefined) => {
_stepInto(e, contFunc)
},
)
}

/**
* Callback on changing the EVM chain.
* @param chainId The chain ID.
Expand All @@ -219,7 +273,20 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
if (fork) {
setSelectedFork(fork)
resetExecution()
initVmInstance(true, selectedChain?.id, fork.name)
initVmInstance(true, selectedChain?.id, forkName)
}
}

/**
* Toggle EOF opcodes show in the list.
*/
const toggleEOFShow = () => {
setShowEOF(!showEOF)
resetExecution()
if (!showEOF && selectedFork?.name === EOF_ENABLED_FORK) {
initVmInstanceWithEOF(true, selectedChain?.id, selectedFork?.name)
} else {
initVmInstance(true, selectedChain?.id, selectedFork?.name)
}
}

Expand Down Expand Up @@ -422,7 +489,7 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
}
}

const _loadChainAndForks = (common: Common) => {
const _loadChainAndForks = (common: Common | EOFCommon) => {
const chainIds: number[] = []
const chainNames: string[] = []
const forks: HardforkTransitionConfig[] = []
Expand Down Expand Up @@ -613,6 +680,18 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
evm.transientStorage,
)
evm.transientStorage.put = transientStorageMethodProxy.put
} else if (evm instanceof EOFEVM) {
// Storage handler
const proxyStateManager = traceStorageMethodCalls(evm.stateManager)
// @ts-ignore confused package
evm.stateManager.putStorage = proxyStateManager.putContractStorage
// @ts-ignore confused package
evm.stateManager.clearStorage = proxyStateManager.clearContractStorage
// Transient storage handler
const transientStorageMethodProxy = traceTransientStorageMethodCalls(
evm.transientStorage,
)
evm.transientStorage.put = transientStorageMethodProxy.put
}

storageMemory.clear()
Expand Down Expand Up @@ -832,6 +911,7 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
isExecuting,
executionState,
vmError,
showEOF,

onChainChange,
onForkChange,
Expand All @@ -844,6 +924,7 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
removeBreakpoint,
nextExecution,
resetExecution,
toggleEOFShow,
}}
>
{children}
Expand Down
38 changes: 38 additions & 0 deletions docs/opcodes/D0.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
fork: Prague
group: Data Section Access
---

*Index 1 is top of the stack. See [PUSH](/#60).*

## Stack input

0. `offset`: byte offset in the data section.

## Stack output

0. `data`: 32-byte value of the data section. All bytes after the end of the data section are set to 0.

## Examples

| Data Section |
|---------|
| `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF` |

| Memory Stack |
|---------|
| `0x0120` |

| * | Input | Output |
|--:|------:|-------:|
| `1` | | `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF` |
| `2` | | `0xFF00000000000000000000000000000000000000000000000000000000000000` |

*TBD: Reproduce in playground*

## Error cases

The state changes done by the current context are [reverted](#FD) in those cases:
- Not enough gas.
- Not enough values on the stack.
- Legacy bytecode.
Loading