ethereum / solidity

Solidity, the Smart Contract Programming Language
https://soliditylang.org
GNU General Public License v3.0
23.11k stars 5.73k forks source link

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

Closed AmadiMichael closed 1 day ago

AmadiMichael commented 3 months ago

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 commented 3 months ago

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.

github-actions[bot] commented 1 week ago

This issue has been marked as stale due to inactivity for the last 90 days. It will be automatically closed in 7 days.

github-actions[bot] commented 1 day ago

Hi everyone! This issue has been automatically closed due to inactivity. If you think this issue is still relevant in the latest Solidity version and you have something to contribute, feel free to reopen. However, unless the issue is a concrete proposal that can be implemented, we recommend starting a language discussion on the forum instead.