evm2
evm2 copied to clipboard
e=vm² (pronounced evm-squared; the = is silent) is an evm that runs inside evm.
e=vm²
e=vm² (pronounced evm-squared; the = is silent), also spelled evm2, is an evm that runs inside evm.
Yo dawg I heard you like building
Huff - use this!
Added huff implementation:
run_huff.sh
and test_huff.sh
Compiling (old method)
evm
is a tool that comes with go-ethereum
.
evm compile evm.easm
Running (old method)
Use evm run
or the provided helper script:
./run.sh 0x<bytecode>
Debugging (old method)
./disas.sh
will compile evm2 and then show disassembly so, you can like, do things that help stuff.
Testing
(NOTE: code without a return statement will return evm2's memory)
return 0x33 * 2:
./test_huff.sh 60336002025952
"0000000000000000000000000000000000000000000000000000000000000066"
return [0x00, 0x20, 0x40]:
./test_huff.sh 595952595952595952
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040"
mstore8 & mstore:
./test_huff.sh 6040595360205952
"40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020"
emit LOG0(abi.encode(uint256(-1), uint256(0))):
(to see logs need to run evm --debug
)
# classic evm:
evm --debug --json --code 600019595260406000a0 run
# and for evm2:
evm --debug --json --code `huffc evm.huff --bin-runtime` --input 600019595260406000a0 run
#### LOGS ####
LOG0: 0000000000000000000000007265636569766572 bn=0 txi=0
00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
00000010 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
untested
untested but presumably works:
-
CALL
,STATICCALL
,DELEGATECALL
,CALLCODE
-
CREATE
,CREATE2
-
CODESIZE
(simply replaced toCALLDATASIZE
) -
CODECOPY
(simply replaced toCALLDATACOPY
)
TODO
Not yet implemented:
-
SELFDESTRUCT
- currently implemented asSTOP
... (probably should not be implemented at all)
Implemented without virtualization: (will shift all data 32 bytes)
-
GAS
(note: can implement HOSTGAS opcode in addition to virtualized GAS but is it useful?) -
CALLDATASIZE
(this would be CODESIZE of the input code) -
CALLDATACOPY
(this would be CODECOPY of the input code) -
RETURNDATASIZE
(supposedly ok) -
RETURNDATACOPY
(supposedly ok)
NOTE:
CODESIZE
& CODECOPY
are simply translated to CALLDATASIZE & CALLDATACOPY.
Fun fact
I used evm
to write pure bytecode, I couldn't even use labels for jumps I had to calculate offsets!
I wanted to do it in pure solidity or yul; I just couldn't get it to run properly.
Solidity has breaking changes every other day especially when it comes to inline assembly.
So I just ended up implementing from scratch.
Thanks to The Optimizor by 0x_Beans, by the end of which I was building mental models in pure assembly while typing bytecodes from memory.