Skip to content
This repository was archived by the owner on Oct 20, 2024. It is now read-only.

Commit a7403c9

Browse files
Maddiaa0PhilogyMaddiaa0
authored
feat(huffc): enable specifying evm version (#281)
* feat: make literal gen reusable and default to push0 * feat: update tests to reflect push0 codegen change * feat: make changes, cleanup doc tests * feat: evm version scaffold * feat: user can specify whether to implement push0 * chore(huffc): bump packages version * fix: update tests to use evm_version * feat: add paris codegen tests * fix: clippy * fix: update benchmarks clean * fix: rename is_shanghai to has_push0 * revert: accidental removal of help * chore: update lock * chore(lint): clippy + fmt --------- Co-authored-by: Philogy <[email protected]> Co-authored-by: Maddiaa0 <[email protected]>
1 parent 10aa9d0 commit a7403c9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+661
-358
lines changed

Cargo.lock

+217-183
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+21-24
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
> `huff-rs` is a [Huff](https://github.com/huff-language) compiler built in rust.
66
7-
87
## What is a Huff?
98

109
Huff is a low-level programming language designed for developing highly optimized smart contracts that run on the Ethereum Virtual Machine (EVM). Huff does not hide the inner workings of the EVM. Instead, Huff exposes its programming stack to the developer for manual manipulation.
@@ -17,7 +16,6 @@ While EVM experts can use Huff to write highly-efficient smart contracts for use
1716

1817
To dive deeper into [Huff](https://github.com/huff-language), visit the [Official Huff Docs](https://huff.sh)(also available on [github](https://github.com/huff-language/huff-docs)).
1918

20-
2119
## Installation
2220

2321
_Something not working? Send a message in [discord](https://discord.huff.sh)._
@@ -33,14 +31,16 @@ To avoid redirecting the script directly into bash, download and run the [huffup
3331
To install the Huff compiler, simply run `huffup`.
3432

3533
If you have the old [huffc (TypeScript version)](https://github.com/huff-language/huffc) npm package installed globally, you can remove it with:
34+
3635
```bash
3736
sudo yarn global remove huffc
3837
```
3938

40-
To make sure you are running the rust version, you can run `huffc --version` and it should respond with `huff_cli <version>`. If it responds with `2.0.0` that means you are running the Typescript version.
39+
To make sure you are running the rust version, you can run `huffc --version` and it should respond with `huff_cli <version>`. If it responds with `2.0.0` that means you are running the Typescript version.
40+
4141
```bash
4242
$ huffc --version
43-
huff_cli 0.3.1
43+
huff_cli 0.3.2
4444
```
4545

4646
**Alternatively**
@@ -59,43 +59,41 @@ OR
5959
cargo install --git https://raw.githubusercontent.com/huff-language/huff-rs --locked huff_cli
6060
```
6161

62-
6362
## How Fast?
6463

6564
**Compilation Benchmarks**
6665

6766
| Compiler | Cold (No Cache) | Light Cache | Deep Cache | Full Cache |
6867
| -------------------------------- | --------------- | ----------- | ---------- | ---------- |
69-
| [huff-language/huff-rs][huff-rs] | XXXms | XXXms | XXXms | XXXms |
70-
| [huff-language/huffc][huffc] | XXXms | XXXms | XXXms | XXXms |
68+
| [huff-language/huff-rs][huff-rs] | XXXms | XXXms | XXXms | XXXms |
69+
| [huff-language/huffc][huffc] | XXXms | XXXms | XXXms | XXXms |
7170

7271
_Note: Compilation benchmarks were performed on [huff-examples erc20](https://github.com/huff-language/huff-examples/tree/main/erc20/contracts/ERC20.huff)._
7372

74-
7573
## Architecture
7674

7775
![Huff Compiler Architecture](./assets/huffc.png)
7876

79-
8077
## Modules
81-
* [huff_core](./huff_core): The core module to huff-rs. Resolves source file paths, executes compilation, and exports artifacts.
82-
* [huff_cli](./huff_cli): The command line interface for the Huff compiler.
83-
* [huff_js](./huff_js): A wasm compatible interface to the Huff compiler for JavaScript bindings.
84-
* [huff_lexer](./huff_lexer): Takes in the source of a `.huff` file and generates a vector of `Token`s.
85-
* [huff_parser](./huff_parser): Crafts a `Contract` AST from the vector of `Token`s generated by [huff_lexer](./huff_lexer).
86-
* [huff_codegen](./huff_codegen): EVM Bytecode generation module that accepts an AST generated by [huff_parser](./huff_parser).
87-
* [huff_utils](./huff_utils): Various utilities and types used by all modules.
88-
* [huffup](./huffup): Update or revert to a specific huff-rs branch with ease. (Forked from [foundry](https://github.com/foundry-rs/foundry))
8978

79+
- [huff_core](./huff_core): The core module to huff-rs. Resolves source file paths, executes compilation, and exports artifacts.
80+
- [huff_cli](./huff_cli): The command line interface for the Huff compiler.
81+
- [huff_js](./huff_js): A wasm compatible interface to the Huff compiler for JavaScript bindings.
82+
- [huff_lexer](./huff_lexer): Takes in the source of a `.huff` file and generates a vector of `Token`s.
83+
- [huff_parser](./huff_parser): Crafts a `Contract` AST from the vector of `Token`s generated by [huff_lexer](./huff_lexer).
84+
- [huff_codegen](./huff_codegen): EVM Bytecode generation module that accepts an AST generated by [huff_parser](./huff_parser).
85+
- [huff_utils](./huff_utils): Various utilities and types used by all modules.
86+
- [huffup](./huffup): Update or revert to a specific huff-rs branch with ease. (Forked from [foundry](https://github.com/foundry-rs/foundry))
9087

9188
## Contributing
9289

9390
All contributions are welcome! We want to make contributing to this project as easy and transparent as possible, whether it's:
94-
- Reporting a bug
95-
- Discussing the current state of the code
96-
- Submitting a fix
97-
- Proposing new features
98-
- Becoming a maintainer
91+
92+
- Reporting a bug
93+
- Discussing the current state of the code
94+
- Submitting a fix
95+
- Proposing new features
96+
- Becoming a maintainer
9997

10098
We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/huff-language/huff-rs/issues/new); it's that easy!
10199

@@ -141,7 +139,6 @@ When the PR checklist isn't complete, it is **highly** recommended to make it a
141139

142140
For breaking changes: make sure to edit the [excalidraw asset](https://excalidraw.com/#json=9YvTZp-rY9NOQnX9TC8Dz,sVM8vpgvQqGiXNXrBNshTg) and export the file to [./assets/huffc.excalidraw](./assets/huffc.excalidraw) along with an image to [./assets/huffc.png](./assets/huffc.png).
143141

144-
145142
## Safety
146143

147144
> **Warning**
@@ -150,13 +147,13 @@ For breaking changes: make sure to edit the [excalidraw asset](https://excalidra
150147
> Expect rapid iteration and **use at your own risk**.
151148
>
152149
> This code is **not designed for safety**.
150+
>
153151
> - There are untested invariants in the code that may break.
154152
> - **You can easily shoot yourself in the foot if you're not careful.**
155153
> - You should thoroughly read the documentation and examples.
156154
>
157155
> We **do not give any warranties** and **will not be liable for any loss** incurred through any use of this codebase.
158156
159-
160157
## Acknowledgements
161158

162159
The original [Huff Language](https://github.com/huff-language) compiler: [`huffc`](https://github.com/huff-language/huffc).

huff_cli/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "huff_cli"
3-
version = "0.3.1"
3+
version = "0.3.2"
44
edition = "2021"
55
authors = ["refcell", "clabby", "exp.table", "maddiaa"]
66
readme = "README.md"

huff_cli/README.md

+68-22
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,87 @@ The `huffc` CLI is written using [clap's](https://docs.rs/clap) [derive feature]
55
## huffc
66

77
```
8-
huffc 0.3.1
8+
huffc 0.3.2
99
Huff Language Compiler built in Pure Rust.
1010
1111
USAGE:
12-
huffc [OPTIONS] [--] [PATH]
12+
huffc [OPTIONS] [PATH] [SUBCOMMAND]
1313
1414
ARGS:
1515
<PATH> The contract(s) to compile
1616
1717
OPTIONS:
18-
-a, --artifacts Whether to generate artifacts or not
19-
-b, --bytecode Generate and log bytecode
20-
-d, --output-directory <OUTPUTDIR> The output directory [default: ./artifacts]
21-
-g, --interface Generate solidity interface for a Huff artifact
22-
-h, --help Print help information
23-
-i, --inputs <INPUTS>... The input constructor arguments
24-
-n, --interactive Interactively input the constructor args
25-
-o, --output <OUTPUT> The output file path
26-
-p, --print Prints out to the terminal
27-
-r, --bin-runtime Generate and log runtime bytecode
28-
-s, --source-path <SOURCE> The contracts source path [default: ./contracts]
29-
-v, --verbose Verbose output
30-
-V, --version Print version information
31-
-z, --optimize Optimize compilation [WIP]
18+
-a, --artifacts
19+
Whether to generate artifacts or not
20+
21+
-b, --bytecode
22+
Generate and log bytecode
23+
24+
-c, --constants <CONSTANTS>...
25+
Override / set constants for the compilation environment
26+
27+
-d, --output-directory <OUTPUTDIR>
28+
The output directory [default: ./artifacts]
29+
30+
-e, --evm-version <EVM_VERSION>
31+
Set the EVM version
32+
33+
-g, --interface [<INTERFACE>...]
34+
Generate solidity interface for a Huff artifact
35+
36+
-h, --help
37+
Print help information
38+
39+
-i, --inputs <INPUTS>...
40+
The input constructor arguments
41+
42+
-l, --label-indices
43+
Prints out the jump label PC indices for the specified contract
44+
45+
-m, --alt-main <ALTERNATIVE_MAIN>
46+
Compile a specific macro
47+
48+
-n, --interactive
49+
Interactively input the constructor args
50+
51+
-o, --output <OUTPUT>
52+
The output file path
53+
54+
-p, --print
55+
Prints out to the terminal
56+
57+
-r, --bin-runtime
58+
Generate and log runtime bytecode
59+
60+
-s, --source-path <SOURCE>
61+
The contracts source path [default: ./contracts]
62+
63+
-t, --alt-constructor <ALTERNATIVE_CONSTRUCTOR>
64+
Compile a specific constructor macro
65+
66+
-v, --verbose
67+
Verbose output
68+
69+
-V, --version
70+
Print version information
71+
72+
-z, --optimize
73+
Optimize compilation [WIP]
74+
3275
```
3376

3477
_NOTE: To generate the above output, run: `huffc --help`_
3578

36-
3779
## Usage
3880

3981
To run `huffc` from the command line, you can simply run:
82+
4083
```bash
4184
huffc --help
4285
```
4386

4487
By default, huffc will attempt to compile all contracts in the `contracts` directory. If there is no `contracts` directory present, the following will spit out an error like so:
88+
4589
```bash,color=red
4690
~ huffc
4791
@@ -90,18 +134,19 @@ huffc -o ./artifact.json ./huff-examples/erc20/contracts/ERC20.huff
90134
```
91135

92136
**NOTE**: The following will _not_ compile since multiple artifacts cannot be output to the same artifact json file.
137+
93138
```bash
94139
huffc -o ./artifact.json ./contracts/
95140
```
96141

97-
98142
#### Entering Constructor Arguments
99143

100144
`huffc` supports passing in constructor arguments to the contract. This is done by passing in the `--interactive` (shorthand: `-n`) flag or passing the `--inputs` (shorthand: `-i`) flag.
101145

102-
and passing in the arguments as a comma separated list.
146+
and passing in the arguments as a comma separated list.
103147

104148
For example, to compile a contract (let's call it `example.huff`) with the following constructor definition:
149+
105150
```huff
106151
#define macro CONSTRUCTOR(uint256, address) = takes(0) returns (0) {
107152
0x04 calldataload
@@ -119,14 +164,14 @@ $ huffc -b -n ./contracts/example.huff
119164
[INTERACTIVE] Enter a uint256 for constructor param: 100
120165
[INTERACTIVE] Enter a address for constructor param: 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef
121166

122-
33600.....f30000000000000000000000000000000000000000000000000000000000000064000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
167+
335f.....f30000000000000000000000000000000000000000000000000000000000000064000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
123168
```
124169

125170
Alternatively, you can enter the arguments as a comma separated list by using the `-i` or `--inputs` flag like so:
126171

127172
```bash
128173
$ huffc -b -i 100, 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef ./contracts/example.huff
129-
33600.....f30000000000000000000000000000000000000000000000000000000000000064000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
174+
335f0.....f30000000000000000000000000000000000000000000000000000000000000064000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
130175
```
131176

132177
#### Other Options
@@ -136,15 +181,16 @@ $ huffc -b -i 100, 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef ./contracts/exampl
136181
- `-z` or `--optimize`: Optimizes the contract compilation - a work in progress.
137182
- `-g` or `--interface`: Generates a solidity interface for the contract.
138183

139-
140184
## Building huffc from source
141185

142186
To run `huffc` from the command line, you can use the following command:
187+
143188
```bash
144189
cargo run --bin huffc
145190
```
146191

147192
To pass arguments into the `huffc` binary, simply pass them in after a `--` flag. For example, to get the `huffc` version (a `-V` flag), you can run:
193+
148194
```bash
149195
cargo run --bin huffc -- -V
150196
```

huff_cli/src/huffc.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use huff_utils::{
2020
file_provider::FileSystemFileProvider,
2121
prelude::{
2222
export_interfaces, gen_sol_interfaces, str_to_bytes32, unpack_files, AstSpan, BytecodeRes,
23-
CodegenError, CodegenErrorKind, CompilerError, FileSource, Literal, OutputLocation, Span,
23+
CodegenError, CodegenErrorKind, CompilerError, EVMVersion, FileSource, Literal,
24+
OutputLocation, Span,
2425
},
2526
};
2627
use isatty::stdout_isatty;
@@ -99,6 +100,10 @@ struct Huff {
99100
#[clap(short = 't', long = "alt-constructor")]
100101
alternative_constructor: Option<String>,
101102

103+
/// Set the EVM version
104+
#[clap(short = 'e', long = "evm-version")]
105+
evm_version: Option<String>,
106+
102107
/// Test subcommand
103108
#[clap(subcommand)]
104109
test: Option<TestCommands>,
@@ -185,6 +190,9 @@ fn main() {
185190
.collect()
186191
});
187192

193+
// Parse the EVM version
194+
let evm_version = EVMVersion::from(cli.evm_version);
195+
188196
let mut use_cache = true;
189197
if cli.interactive {
190198
// Don't accept configured inputs
@@ -204,6 +212,7 @@ fn main() {
204212
};
205213

206214
let compiler: Compiler = Compiler {
215+
evm_version: &evm_version,
207216
sources: Arc::clone(&sources),
208217
output,
209218
alternative_main: cli.alternative_main.clone(),
@@ -244,6 +253,7 @@ fn main() {
244253

245254
// Recurse through the macro and generate bytecode
246255
let bytecode_res: BytecodeRes = Codegen::macro_to_bytecode(
256+
&evm_version,
247257
macro_def,
248258
contract,
249259
&mut vec![macro_def],

huff_codegen/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "huff_codegen"
3-
version = "0.3.1"
3+
version = "0.3.2"
44
edition = "2021"
55
authors = ["refcell", "clabby", "exp.table", "maddiaa"]
66
readme = "README.md"

huff_codegen/README.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ assert!(cg.ast.is_none());
3636
assert!(cg.artifact.is_none());
3737

3838
// ERC20 Bytecode
39-
let main_bytecode = "60003560E01c8063a9059cbb1461004857806340c10f19146100de57806370a082311461014e57806318160ddd1461016b578063095ea7b314610177578063dd62ed3e1461018e575b600435336024358160016000526000602001526040600020548082116100d8578190038260016000526000602001526040600020558281906001600052600060200152604060002054018360016000526000602001526040600020556000527fDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF60206000a3600160005260206000f35b60006000fd5b60005433146100ed5760006000fd5b600435600060243582819060016000526000602001526040600020540183600160005260006020015260406000205580600254016002556000527fDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF60206000a35b600435600160005260006020015260406000205460005260206000f35b60025460005260206000f35b602435600435336000526000602001526040600020555b60243560043560005260006020015260406000205460005260206000f3";
40-
let constructor_bytecode = "33600055";
39+
let main_bytecode = "5f3560e01c8063a9059cbb1461004757806340c10f19146100d757806370a082311461014157806318160ddd1461015c578063095ea7b314610166578063dd62ed3e1461017d575b600435336024358160016000526000602001526040600020548082116100d3578190038260016000526000602001526040600020558281906001600052600060200152604060002054018360016000526000602001526040600020555f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa360015f5260205ff35b5f5ffd5b5f5433146100e3575f5ffd5b6004355f60243582819060016000526000602001526040600020540183600160005260006020015260406000205580600254016002555f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa35b60043560016000526000602001526040600020545f5260205ff35b6002545f5260205ff35b602435600435336000526000602001526040600020555b6024356004356000526000602001526040600020545f5260205ff3";
40+
let constructor_bytecode = "335f55";
4141
let inputs = vec![];
4242
let churn_res = cg.churn(Arc::new(FileSource::default()), inputs, main_bytecode, constructor_bytecode, false);
4343

4444
// Validate the output bytecode
45-
assert_eq!(churn_res.unwrap().bytecode, "336000556101ac80600e3d393df360003560e01c8063a9059cbb1461004857806340c10f19146100de57806370a082311461014e57806318160ddd1461016b578063095ea7b314610177578063dd62ed3e1461018e575b600435336024358160016000526000602001526040600020548082116100d8578190038260016000526000602001526040600020558281906001600052600060200152604060002054018360016000526000602001526040600020556000527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60206000a3600160005260206000f35b60006000fd5b60005433146100ed5760006000fd5b600435600060243582819060016000526000602001526040600020540183600160005260006020015260406000205580600254016002556000527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60206000a35b600435600160005260006020015260406000205460005260206000f35b60025460005260206000f35b602435600435336000526000602001526040600020555b60243560043560005260006020015260406000205460005260206000f3".to_lowercase());
45+
assert_eq!(churn_res.unwrap().bytecode, "335f5561019980600d3d393df35f3560e01c8063a9059cbb1461004757806340c10f19146100d757806370a082311461014157806318160ddd1461015c578063095ea7b314610166578063dd62ed3e1461017d575b600435336024358160016000526000602001526040600020548082116100d3578190038260016000526000602001526040600020558281906001600052600060200152604060002054018360016000526000602001526040600020555f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa360015f5260205ff35b5f5ffd5b5f5433146100e3575f5ffd5b6004355f60243582819060016000526000602001526040600020540183600160005260006020015260406000205580600254016002555f527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205fa35b60043560016000526000602001526040600020545f5260205ff35b6002545f5260205ff35b602435600435336000526000602001526040600020555b6024356004356000526000602001526040600020545f5260205ff3".to_lowercase());
4646

4747
// Write the compile artifact out to a file
4848
// cg.export("./output.json");
@@ -97,10 +97,10 @@ let contract = Contract {
9797
};
9898

9999
// Generate the main bytecode
100-
let main_bytecode: String = Codegen::generate_main_bytecode(&contract, None).unwrap();
100+
let main_bytecode: String = Codegen::generate_main_bytecode(&EVMVersion::default(), &contract, None).unwrap();
101101

102102
// Validate the output bytecode
103-
assert_eq!(main_bytecode, "60003560e01c");
103+
assert_eq!(main_bytecode, "5f3560e01c");
104104
```
105105

106106
Similarly, once you have a [Contract](../huff_utils/ast/struct.Contract.html) instance with a simple **CONSTRUCTOR** macro definition. You can generate the constructor/creation bytecode using the [generate_constructor_bytecode](struct.Codegen.html#method.generate_constructor_bytecode) function.
@@ -152,9 +152,9 @@ let contract = Contract {
152152
};
153153

154154
// Generate the constructor bytecode
155-
let (constructor_bytecode, has_custom_bootstrap): (String, bool) = Codegen::generate_constructor_bytecode(&contract, None).unwrap();
155+
let (constructor_bytecode, has_custom_bootstrap): (String, bool) = Codegen::generate_constructor_bytecode(&EVMVersion::default(), &contract, None).unwrap();
156156

157157
// Validate the output bytecode
158-
assert_eq!(constructor_bytecode, "60003560e01c");
158+
assert_eq!(constructor_bytecode, "5f3560e01c");
159159
assert_eq!(has_custom_bootstrap, false);
160160
```

0 commit comments

Comments
 (0)