py-huff
is a Huff compiler written in Python.
Important: Python 3.10 or higher is required
git clone https://github.com/philogy/py-huff
cd py-huff
pip install -e .
Ready to use either py_huff
itself as a Python Huff compilation or the huffy
CLI wrapper.
Compile code adding minimal deploy code
huffy -b my_huff_contract.huff
Compile code (no deploy)
huffy -r my_huff_contract.huff
- Create a simpler huff compiler (
huff-rs
always 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
Besides the missing features as listed under Features this implementation has a few differences to
huff-rs
(as of 813b6b6
).
Unlike huff-rs
, py-huff
supports jump destinations larger or smaller than 2-bytes. The size of
the push opcode will automatically be adjusted to a smaller size. Note that like huff-rs
, py-huff
keeps the size of all push jump dests the same, meaning if your contract is more than 255 bytes long
all jump dest pushes will be PUSH2
s, even if earlier destinations would fit in 1 byte.
huff-rs
currently has some unclear jump label semantics (see #295), py-huff
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 or their parent's
- a reference to a label will select the deepest one e.g.
#define macro A() = takes(0) returns(0) { label: <-------------\ B() | label jump references ---/ } #define macro B() = takes(0) returns(0) { label: <--------------------------\ C() | } | | #define macro C() = takes(0) returns(0) { | D() | } | | #define macro D() = takes(0) returns(0) { | label jump references ----------------/ } #define macro E() = takes(0) returns(0) { label jump } #define macro MAIN() = takes(0) returns(0) { A() E() <throws> }
- ✅ Opcodes
- ✅ Hex literals (e.g.
0x238a
) - ✅ Jump labels
- ✅ Macros
- ✅ Macro arguments (✅ literals, ✅ jump labels, ✅ macro parameters)
- ✅ Nested macros (e.g.
A() -> B() -> C()
)
- ✅ Runtime bytecode
- ❌ Deploy bytecode
- ✅ Minimal deploy code
- ❌ Custom constructors
- ❌ Tables
- ✅ Code Tables
- ❌ Jump Tables (❌ normal, ❌ packed)
- ❌ Built-ins
- ❌
__EVENT_HASH
- ❌
__FUNC_SIG
- ❌
__codesize
- ✅
__tablestart
- ✅
__tablesize
- ❌
- ✅ Push literals (e.g.
push4 0x010
) - ❌ Fns (non-inlined macros)
- ❌ Recursion