Skip to content

Commit 31f7868

Browse files
authored
feat: compilation script + CREATE opcode (#43)
1 parent b6055d3 commit 31f7868

File tree

36 files changed

+1074
-163
lines changed

36 files changed

+1074
-163
lines changed

.cargo/config.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[alias]
2+
compile = "run --package r55-compile"
3+
test-r55 = "test --package r55"
4+
test-e2e = "test --package r55 --test e2e"
5+
test-erc20 = "test --package r55 --test erc20"
6+
test-erc721 = "test --package r55 --test erc721"
7+
8+

.github/workflows/ci.yml

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ jobs:
6565
# Only run tests on latest stable and above
6666
- name: build
6767
if: ${{ matrix.rust == '1.81' }} # MSRV
68-
run: cargo build --workspace ${{ matrix.flags }}
68+
run: cargo compile --workspace ${{ matrix.flags }}
6969
- name: test
7070
if: ${{ matrix.rust != '1.81' }} # MSRV
71-
run: cargo test --workspace ${{ matrix.flags }}
71+
run: cargo compile && cargo test --workspace ${{ matrix.flags }}
7272

7373
# TODO(fakedev9999): Add wasm tests if needed
7474

@@ -90,6 +90,14 @@ jobs:
9090
- uses: Swatinem/rust-cache@v2
9191
with:
9292
cache-on-failure: true
93+
- name: Install Dependencies
94+
run: |
95+
rustup install nightly-2025-01-07-x86_64-unknown-linux-gnu
96+
rustup component add rust-src --toolchain nightly-2025-01-07-x86_64-unknown-linux-gnu
97+
sudo apt-get update
98+
sudo apt-get install -y gcc-riscv64-unknown-elf make device-tree-compiler
99+
- name: Build
100+
run: cargo compile
93101
- name: cargo hack
94102
run: |
95103
args=(${{ matrix.flags }})
@@ -107,7 +115,16 @@ jobs:
107115
- uses: Swatinem/rust-cache@v2
108116
with:
109117
cache-on-failure: true
110-
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
118+
- name: Install Dependencies
119+
run: |
120+
rustup install nightly-2025-01-07-x86_64-unknown-linux-gnu
121+
rustup component add rust-src --toolchain nightly-2025-01-07-x86_64-unknown-linux-gnu
122+
sudo apt-get update
123+
sudo apt-get install -y gcc-riscv64-unknown-elf make device-tree-compiler
124+
- name: Compile
125+
run: cargo compile
126+
- name: Run Clippy
127+
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
111128
env:
112129
RUSTFLAGS: -D warnings
113130

@@ -120,7 +137,14 @@ jobs:
120137
- uses: Swatinem/rust-cache@v2
121138
with:
122139
cache-on-failure: true
123-
- run: cargo doc --workspace --all-features --no-deps --document-private-items
140+
- name: Install Dependencies
141+
run: |
142+
rustup install nightly-2025-01-07-x86_64-unknown-linux-gnu
143+
rustup component add rust-src --toolchain nightly-2025-01-07-x86_64-unknown-linux-gnu
144+
sudo apt-get update
145+
sudo apt-get install -y gcc-riscv64-unknown-elf make device-tree-compiler
146+
- name: Run Docs
147+
run: cargo compile && cargo doc --workspace --all-features --no-deps --document-private-items
124148
env:
125149
RUSTDOCFLAGS: "--cfg docsrs -D warnings"
126150

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@ Cargo.lock
1515

1616
# Ignore RISCV emulator files
1717
**/rvemu.*
18+
19+
# Ignore auto-generated files
20+
r55-output-bytecode/
21+
*/generated/
22+
23+
# Ignore .DS_Store
24+
.DS_Store

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
resolver = "2"
44

5-
members = ["eth-riscv-interpreter", "eth-riscv-syscalls", "r55"]
5+
members = ["eth-riscv-interpreter", "eth-riscv-syscalls", "r55", "r55-compile"]
66
default-members = ["eth-riscv-interpreter", "eth-riscv-syscalls", "r55"]
77

88
exclude = [

asm-runtime-example/runtime

4.48 KB
Binary file not shown.

asm-runtime-example/runtime.o

1.25 KB
Binary file not shown.

contract-derive/src/helpers.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ where
175175
}
176176
}
177177

178+
impl <C: CallCtx> #interface_name<C> {
179+
pub fn address(&self) -> Address {
180+
self.address
181+
}
182+
}
183+
178184
impl<C: StaticCtx> #interface_name<C> {
179185
#(#immut_method_impls)*
180186
}

contract-derive/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,8 @@ pub fn contract(_attr: TokenStream, item: TokenStream) -> TokenStream {
454454
// only when not in `interface-only` mode
455455
#[cfg(not(any(feature = "deploy", feature = "interface-only")))]
456456
#[allow(non_local_definitions)]
457+
#[allow(unused_imports)]
458+
#[allow(unreachable_code)]
457459
mod implementation {
458460
use super::*;
459461
use alloy_sol_types::SolValue;

eth-riscv-runtime/src/call.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![no_std]
2-
31
extern crate alloc;
42
use alloc::vec::Vec;
53
use alloy_core::primitives::{Address, Bytes, U256};

eth-riscv-runtime/src/create.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
extern crate alloc;
2+
use alloy_core::primitives::{Address, Bytes, U32};
3+
use alloy_sol_types::{SolType, SolValue};
4+
use ext_alloc::vec::Vec;
5+
use core::{arch::asm, marker::PhantomData, u64};
6+
use eth_riscv_syscalls::Syscall;
7+
8+
use crate::{FromBuilder, InitInterface, MethodCtx, ReadWrite};
9+
10+
pub trait Deployable {
11+
type Interface: InitInterface;
12+
13+
/// Returns the contract's runtime bytecode
14+
fn __runtime() -> &'static [u8];
15+
16+
/// Returns the contract's runtime bytecode
17+
fn bytecode() -> Bytes {
18+
Bytes::from(Self::__runtime())
19+
}
20+
21+
// Creates a deployment builder that captures the constructor args
22+
fn deploy<Args>(args: Args) -> DeploymentBuilder<Self, Args>
23+
where
24+
Self: Sized,
25+
Args: SolValue + core::convert::From<<<Args as SolValue>::SolType as SolType>::RustType>
26+
{
27+
DeploymentBuilder {
28+
args,
29+
_phantom: PhantomData,
30+
}
31+
}
32+
}
33+
34+
pub struct DeploymentBuilder<D: Deployable + ?Sized, Args>
35+
where
36+
Args: SolValue + core::convert::From<<<Args as SolValue>::SolType as SolType>::RustType>
37+
{
38+
args: Args,
39+
_phantom: PhantomData<D>,
40+
}
41+
42+
impl<D: Deployable, Args> DeploymentBuilder<D, Args>
43+
where
44+
Args: SolValue + core::convert::From<<<Args as SolValue>::SolType as SolType>::RustType>
45+
{
46+
47+
// Return the interface with the appropriate context
48+
pub fn with_ctx<M, T>(self, ctx: M) -> T
49+
where
50+
M: MethodCtx<Allowed = ReadWrite>, // Constrain to mutable contexts only
51+
D::Interface: InitInterface,
52+
T: FromBuilder<Context = M::Allowed>,
53+
D::Interface: crate::IntoInterface<T>
54+
{
55+
let bytecode = D::__runtime();
56+
let encoded_args = self.args.abi_encode();
57+
58+
// Craft R55 initcode: [0xFF][codesize][bytecode][constructor_args]
59+
let codesize = U32::from(bytecode.len());
60+
61+
let mut init_code = Vec::new();
62+
init_code.push(0xff);
63+
init_code.extend_from_slice(&Bytes::from(codesize.to_be_bytes_vec()));
64+
init_code.extend_from_slice(&bytecode);
65+
init_code.extend_from_slice(&encoded_args);
66+
67+
let offset = init_code.as_ptr() as u64;
68+
let size = init_code.len() as u64;
69+
70+
// TODO: think of an ergonomic API to handle deployments with values
71+
create(0, offset, size);
72+
73+
// Get deployment address
74+
let mut ret_data = Vec::with_capacity(20);
75+
ret_data.resize(20 as usize, 0);
76+
return_create_address(ret_data.as_ptr() as u64);
77+
78+
let address = Address::from_slice(&ret_data);
79+
80+
// Create the interface builder
81+
let builder = D::Interface::new(address);
82+
83+
// Convert to the actual interface with context
84+
builder.with_ctx(ctx)
85+
}
86+
}
87+
88+
fn create(value: u64, data_offset: u64, data_size: u64) {
89+
unsafe {
90+
asm!(
91+
"ecall",
92+
in("a0") value, in("a1") data_offset, in("a2") data_size,
93+
in("t0") u8::from(Syscall::Create)
94+
);
95+
}
96+
}
97+
98+
fn return_create_address(data_offset: u64) {
99+
unsafe {
100+
asm!(
101+
"ecall", in("a0") data_offset, in("t0") u8::from(Syscall::ReturnCreateAddress));
102+
}
103+
}

0 commit comments

Comments
 (0)