py-huff
py-huff copied to clipboard
PyHuff
PyHuff is a compiler for Huff, an EVM assembly language, written in Python.
[!WARNING] This repo is experimental, for a more tested Huff compiler see huff-rs
Installation
Important: Python 3.10 or higher is required
git clone https://github.com/philogy/py-huffcd py-huffpip install -e .
Ready to use either py_huff itself as a Python API for Huff as a CLI via huffy.
Usage
Compile code (Compiles constructor or adds default)
huffy -b my_huff_contract.huff
Compile code (no deploy)
huffy -r my_huff_contract.huff
Motivation
- Create a simpler huff compiler (
huff-rsalways felt overly complicated to me) - Improve some semantics around jump destinations
- Have a second implementation that can be used to differentially test the original
huff-rs - Make it potentially feasible for a Huff compiler to be included in the audit scope for METH
Differences vs. huff-rs
New Features
Constructor Helpers (Only usable from constructor)
__RUNTIME_START(): Generates aPUSHwith the code offset of where the runtime bytecode begins.__RUNTIME_SIZE(): Generates aPUSHwith the length in bytes of the runtime code. Can be used together with__RUNTIME_STARTto create a custom constructor:
#define macro CONSTRUCTOR() = takes(0) returns(0) {
// owner = msg.sender
caller
0x0
sstore
// return runtime
__RUNTIME_SIZE()
dup1
__RUNTIME_START()
0x0
codecopy
0x0
return
}
__RETURN_RUNTIME(offset: Op): Generates the default constructor, copying the runtime code to the offset pushed byoffset, equivalent to:
__RUNTIME_SIZE()
dup1
__RUNTIME_START()
<offset>
codecopy
<offset>
return
Missing Features
These are features that are planned for PyHuff but not yet implemented
- ❌ Jump Tables (❌ normal, ❌ packed, ✅ code (already present))
- ❌
__codesize - ❌ Fns (non-inlined macros)
- ❌ Recursion
Jump destinations
Unlike huff-rs, PyHuff supports jump destinations larger or smaller than 2-bytes. The size of
the push opcode will automatically be adjusted to a smaller size. Furthermore PyHuff has an
optimization step that will shorten earlier labels if they can fit into smaller push opcodes.
Jump Labels
huff-rs currently has some unclear jump label semantics (see #295), PyHuff attempts to introduce clear jump label scoping and semantics:
- each label has a scope tied to the macro it's present within
- duplicate label declarations in the same macro throws an error
- invoked macros can only access labels defined in their own context
- child macros can access labels defined in parents only if
- it's explicitly made available via a macro parameter
- it's prefixed with
global_
Default Constructor Code Return
PyHuff will only automatically add minimal initcode if you don't specify CONSTRUCTOR at all. This
is unlike huff-rs which will also add the minimal initcode to your constructor if it does not
reference return. PyHuff does not do this for the sake of simplicity and requiring you to be
explicit. The minimal code return can easily be added to your constructor via the
__RETURN_RUNTIME() built-in.