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

Support for CodeSection type for linking externally written/compiled bytecode with EOF supported Solidity contracts. #15211

Open
AmadiMichael opened this issue Jun 21, 2024 · 1 comment
Labels

Comments

@AmadiMichael
Copy link

Abstract

Currently in solidity, there's no native support for linking an externally compiled bytecode with a solidity contract and being able to call into it. Walkarounds for this have been made e.g dynamic huffidity which utilizes function pointers and manually returning bytecode from the constructor to achieve this but for obvious reasons have not been used in production (that i know of). Implementing native support for this feature, particularly with EOF (EVM Object Format) likely to come in Prague, could resolve these issues cleanly.

A scenario where this could have been helpful is with Tornado Cash. It uses a handwritten bytecode MiMCSponge implementation to be as optimal as possible but because it couldn't be linked with the solidity contract it had to be deployed as a separate contract that's called externally.

Motivation

I propose a CodeSection type, defined as a struct of 4 fields, each of which are relevant to create a valid TypeSection for the given container and for compile-time validation.

struct CodeSection {
   bytes bytecode;
   uint8 numOfInputs;
   uint8 numOfOutputs;
   uint16 maxStackHeight;
}

This is to be defined at the contract/file level and must be known at compile time so that it can be validated and linked together with the solidity code.

When used in inline assembly, a variable of type CodeSection is actually a uint256 constant that holds the code section index of the bytecode (similar to how functions types hold its implementation PC) and not the struct field's values. These values are only for compilation and become part of the bytecode afterwards.

Specification

Within any function, the code section can be called via solidity or inline assembly and outputs are to be completely consumed or acknowledged to exist at least.

Example with a code section that takes in 2 inputs and returns 2 outputs (a / b, a % b):

contract A {
   CodeSection huffCode = CodeSection({bytecode: 0x818106919004e4, numOfInputs: 2, numOfOutputs: 2, maxStackHeight: 4});

   // Solidity example
   function b(uint256 _a, uint256 _b,) external view returns(uint256 _c, uint256 _d) {
              (_c, _d) = huffCode(_a, _b);
              // (, _d) = huffCode(_a, _b);  // also valid, because it acknowledges the presence of other return/output values
   }

   // Inline assembly example
   function c(uint256 _a, uint256 _b) external view returns(uint256 _c, uint256 _d) {
         assembly {
               (_c, _d) := callf(huffCode, _a, _b)
               // (_c, ) := callf(huffCode, _a, _b) // also valid, because it acknowledges the presence of other return/output values
         }
   }
}

Under the hood, this would simply CALLF into huffCode's code section and execute it, then huffCode returns execution back to the calling code section with the given outputs pushed to its stack to continue execution.

Note: Since memory is shared between code sections, similar to inline assembly the concept of memory safe code sections would also be a thing i.e you can mark the code section call as memory safe i.e the bytecode maintains the memory allocation rules of solidity.

Backwards Compatibility

No backwards compatibility issues I can think of currently.

@AmadiMichael
Copy link
Author

An added benefit of this is calling solidity/assembly functions from an inline assembly block via CALLF.

Currently in solidity its not possible to call your contracts' solidity function while in an assembly block or an assembly block's function from another assembly block within the same function. It would be a helpful feature if a shared function can be set to have a distinct code section and hence can be callable from any inline assembly block within that contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant