e=vm² (pronounced evm-squared; the = is silent), also spelled evm2, is an evm that runs inside evm.
Added huff implementation:
run_huff.sh and test_huff.sh
evm is a tool that comes with go-ethereum.
evm compile evm.easmUse evm run or the provided helper script:
./run.sh 0x<bytecode>./disas.sh will compile evm2 and then show disassembly so, you can like, do things that help stuff.
(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 but presumably works:
CALL,STATICCALL,DELEGATECALL,CALLCODECREATE,CREATE2CODESIZE(simply replaced toCALLDATASIZE)CODECOPY(simply replaced toCALLDATACOPY)
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.
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.