Suppose, I have the following bytecode (0x610101610102016000526001601ff3) that pushes two numbers to the stack, adds them and returns the value.

Now I want to write a function in Solidity that will take this bytecode as input and return the final result (i.e., the final stack, memory, and storage contents after the execution inside EVM). How can I write this function? Is it possible to do so (for example - using the solidity assembly)? Please suggest. Thanks in advance.


Surely, you may do this. Here are high-level steps:

  1. To the end of your bytecode append a few additional opcodes that copy stack and storage content into memory and return them together with memory content.
  2. Prepend you bytecode with a simple constructor that will just deploy your bytecode as a contract.
  3. Deploy modified bytecode and obtain deployed smart contract address.
  4. Call just deployed smart contract. This effectively will execute original bytecode and return stack, storage, and memory content after the execution.

The challanges here are how to determine stack depth and how to find out modified storage keys. May you make the bytecode being executed to follow some convention about these things, such as leave stack depth and storage keys on the stack after execution?

If you need to execute each bytecode only once, you may add SELFDESTRUCT opcode before RETURN in order to destroy the smart contract after the call.

  • Thanks @Mikhail Vladimirov for your response. Can you please explain your "point 4" more (probably with an example)? I did up to point 3 where I used "create" to deploy the bytecode and get the address. Since, there is no function in this newly deployed contract (or I don't know the abi), how can I call this contract and get the result after the execution? Thanks.
    – NB18
    Feb 26 '20 at 20:56
  • 1
    Use (bool status, bytes memory data) = addr.call (""); to call contract deployed at address addr and obtain call status and result data. See documentation for details. Feb 27 '20 at 6:24

Alternatively to Mikahil Vladimirovs answere, you could also implement a bytecode interpreter smart contract, which will parse the bytes within a loop, determine the opcodes and following data and finally execute the relevant EVM instructions in YUL code. For complete functionality, the interpreter smart contract must be called using "delegatecall".

I think this solution requires less gas for small sequences of instructions, whereas Mikhail Vladimirovs solution is more gas efficient for bigger sequences of instructions. One ethical concern in regards to Mikhail Vladimirovs solution is that it bloats the storage trie with zombie smart contracts, which every full node in the decentralized network has to carry.

EDIT: Using CREATE2 to create the contracts you can ensure that the same bytecode is not deployed twice. There will still be a lot of zombie contracts, but at least you can reuse a contract for the same bytecode.

Opcodes: https://github.com/crytic/evm-opcodes

YUL EVM Dialect: https://solidity.readthedocs.io/en/v0.6.3/yul.html#evm-dialect

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.