huff-language / huff-rs

A low-level assembly language for the Ethereum Virtual Machine built in blazing-fast pure rust.
https://huff.sh
Apache License 2.0
590 stars 79 forks source link

[Feature Request] Add support for raw arbitrary bytes #318

Closed Mouradif closed 6 months ago

Mouradif commented 6 months ago

It is a common practice in some contracts to insert raw unreachable code to be used for a CODECOPY. It would be great if Huff allowed for that. I don't know what would be a good syntax for it but I'm thinking like a type that can be defined just like a macro + a built-in to fetch its progam counter. Let's imagine we call that type raw. A raw block could be defined like this:

#define raw PREPARE_ERC20_TRANSFER = {
  0xa9059cbb
  0x0000000000000000000000000000000000000000000000000000000000000000
  0x0000000000000000000000000000000000000000000000000000000000000000
}

Inside a "raw" block, no operation is allowed, only bytes of whatever length the dev wants for their own chosen level of readability. This block wouldn't interpret the bytes as PUSH operations, and would just concatenate all the bytes. All the raw blocks could be inserted at the end of the contract's code just like constructor arguments would be.

Then in order to use those bytes for a CODECOPY, we would only need the program counter where the block is, then it could be used like this. In order for the compiler to not confuse it with a jump label we could use curly braces since there's no other scenario where you could use those inside a macro:

#define macro MAKE_ERC20_TRANSFER(recipient, amount) = {
  0x44                                   // [size]
  {PREPARE_ERC20_TRANSFER}               // [offset, size]
  0x00                                   // [destOffset, offset, size]
  codecopy                               // []
  <recipient>                            // [recipient]
  0x04                                   // [0x04, recipient]
  mstore                                 // []
  <amount>                               // [amount]
  0x24                                   // [0x24, recipient]
  mstore                                 // []
  // ... 
}

Then maybe to take it one step further, instead of hard-coding the size here (0x44), maybe a new built-in could be introduces to return the size of that raw block.

I know Huff aims to have as little abstraction as possible but I think this is an acceptable level in the sense that it doesn't do more than what it shows. Also, I feel like this feature kinda makes Huff even lower level than what it is in the sense that it allows to do something that is currently not possible in Huff, and only possible with writing your own raw bytecode.

Mouradif commented 6 months ago

While going through the compiler code, I discovered the existence of the __VERBATIM built-in. Works for me, would be great to document it.