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 all 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
14 changes: 7 additions & 7 deletions components/ChainSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import { toKeyIndex } from 'util/string'
import { Icon, Label } from 'components/ui'

const ChainOption = (props: any) => {
const { data, children } = props
const { data, label } = props
const isCurrent = data.value === CURRENT_FORK

return (
<components.Option {...props}>
{children}
{label}
{isCurrent && <Label>Live</Label>}
</components.Option>
)
Expand Down Expand Up @@ -57,13 +57,13 @@ const ChainSelector = () => {
return
}

if (!router.query.fork) {
const latestFork = forks.at(-1)
const fork = forkOptions.find((fork) => fork.value === latestFork?.name)
const fork = router.query.fork
? forkOptions.find((fork) => fork.value === router.query.fork)
: forkOptions.find((fork) => fork.value === CURRENT_FORK)
if (fork) {
setForkValue(fork as any)
onForkChange(fork?.value as string)
onForkChange(fork.value)
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [router.isReady, defaultForkOption])

Expand Down
31 changes: 31 additions & 0 deletions components/EOFToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Image from 'next/image'
import eofIcon from 'public/eof_icon.png'
import { Tooltip } from 'react-tooltip'

import { Toggle } from 'components/ui'

const EOFToggle = () => {
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={() => {
console.log('clicked')
}}
isChecked={false}
/>
</span>
</div>
</div>
)
}

export default EOFToggle
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'
81 changes: 63 additions & 18 deletions context/ethereumContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ import { RunState } from '@ethereumjs/evm/dist/cjs/interpreter'
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 { RunTxOpts, 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'
// @ts-ignore it confused with pre-EOF version
import { createTxFromTxData as createTxFromTxDataEOF } from '@ethjs-eof/tx'
// @ts-ignore it confused with pre-EOF version
import { VM as EOFVM, runTx as runTxEOF } from '@ethjs-eof/vm'
import OpcodesMeta from 'opcodes.json'
import PrecompiledMeta from 'precompiled.json'
import {
Expand All @@ -27,15 +34,20 @@ import {
ITransientStorage,
} from 'types'

import { CURRENT_FORK, FORKS_WITH_TIMESTAMPS } from 'util/constants'
import {
CURRENT_FORK,
EOF_ENABLED_FORK,
EOF_FORK_NAME,
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 +62,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, 7692, 7698,
]

type ContextProps = {
common: Common | undefined
common: Common | EOFCommon | undefined
chains: IChain[]
forks: HardforkTransitionConfig[]
selectedChain: IChain | undefined
Expand Down Expand Up @@ -168,16 +183,19 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
chainId?: Chain,
fork?: string,
) => {
common = new Common({
const forkName = fork == EOF_FORK_NAME ? EOF_ENABLED_FORK : fork
common = new EOFCommon({
chain: Chain.Mainnet,
hardfork: fork || CURRENT_FORK,
hardfork: forkName || CURRENT_FORK,
eips: forkName === EOF_ENABLED_FORK ? EOF_EIPS : [],
})

vm = await VM.create({ common })
vm = await EOFVM.create({ common })

const evm = await EVM.create({
const evm = await createEVM({
common,
})

currentOpcodes = evm.getActiveOpcodes()

if (!skipChainsLoading) {
Expand Down Expand Up @@ -219,11 +237,11 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
if (fork) {
setSelectedFork(fork)
resetExecution()
initVmInstance(true, selectedChain?.id, fork.name)
initVmInstance(true, selectedChain?.id, forkName)
}
}

/**
/*
* Deploys the contract code to the EVM.
* @param byteCode The contract bytecode.
* @returns The deployed contract transaction data.
Expand All @@ -240,7 +258,11 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
nonce: account?.nonce,
}

return TransactionFactory.fromTxData(txData).sign(privateKey)
if (vm.evm instanceof EOFEVM) {
return createTxFromTxDataEOF(txData).sign(privateKey)
} else {
return TransactionFactory.fromTxData(txData).sign(privateKey)
}
}

/**
Expand Down Expand Up @@ -422,7 +444,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 All @@ -444,7 +466,6 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
setSelectedChain({ id: chainIds[0], name: chainNames[0] })

let currentForkFound = false

common.hardforks().forEach((fork) => {
// FIXME: After shanghai, timestamps are used, so support them in addition
// to blocks, and in the meantime use timestamp as the block num.
Expand All @@ -469,6 +490,11 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
}
})

forks.push({
name: EOF_FORK_NAME,
block: 1710338135,
})

setForks(forks)
}

Expand Down Expand Up @@ -549,10 +575,10 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
const origMethod = target[propKey]
return (...args: any[]) => {
const result = origMethod.apply(target, args)
if (propKey == 'clearContractStorage') {
if (propKey == 'clearContractStorage' || propKey == 'clearStorage') {
_clearContractStorage(args[0])
}
if (propKey == 'putContractStorage') {
if (propKey == 'putContractStorage' || propKey == 'putStorage') {
_putContractStorage(args[0], args[1], args[2])
}
return result
Expand Down Expand Up @@ -602,17 +628,36 @@ export const EthereumProvider: React.FC<{}> = ({ children }) => {
// This is necessary in order to handle storage operations easily.
const _setupStateManager = () => {
const evm = vm.evm

// Storage handler
const proxyStateManager = traceStorageMethodCalls(evm.stateManager)

if (evm instanceof EVM) {
// Storage handler
const proxyStateManager = traceStorageMethodCalls(evm.stateManager)
evm.stateManager.putContractStorage = proxyStateManager.putContractStorage
evm.stateManager.clearContractStorage =
proxyStateManager.clearContractStorage

// Transient storage handler
const transientStorageMethodProxy = traceTransientStorageMethodCalls(
evm.transientStorage,
)
evm.transientStorage.put = transientStorageMethodProxy.put
} else if (evm instanceof EOFEVM) {
// @ts-ignore confused package
evm.stateManager.putStorage = proxyStateManager.putStorage
// @ts-ignore confused package
evm.stateManager.clearStorage = proxyStateManager.clearStorage

// Transient storage handler
const transientStorageMethodProxy = traceTransientStorageMethodCalls(
evm.transientStorage,
)
evm.transientStorage.put = transientStorageMethodProxy.put

// NOTE: they renamed a few functions with the EOF changes
// @ts-ignore it's confused because of the pre eof version
evm.stateManager.putContractCode = evm.stateManager.putCode
vm.runTx = (opts: RunTxOpts) => runTxEOF(vm, opts)
}

storageMemory.clear()
Expand Down
33 changes: 33 additions & 0 deletions docs/opcodes/D0.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
fork: EOF
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` |

| * | Input | Output | * | * | Input | Output |
|--:|------:|-------:|--:|--:|------:|-------:|
| `1` | `0x00` | `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF` | * | `1` | `0x1F` | `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.
33 changes: 33 additions & 0 deletions docs/opcodes/D1.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
fork: EOF
group: Data Section Access
---

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

## Immediate argument

0. `offset`: 16-bit unsigned value 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` |

| * | Input | Output | * | * | Input | Output |
|--:|------:|-------:|--:|--:|------:|-------:|
| `1` | `0` | `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF` | * | `1` | `31` | `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