Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Major Changes to Reproducible Builds #53

Merged
merged 13 commits into from
Jul 16, 2024
95 changes: 87 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions check/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ tokio.workspace = true
wasmer = "3.1.0"
glob = "0.3.1"
tempfile = "3.10.1"
wasmparser = "0.213.0"
wasm-encoder = "0.213.0"
wasm-gen = "0.1.4"
49 changes: 19 additions & 30 deletions check/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,22 @@ pub async fn check(cfg: &CheckConfig) -> Result<ProgramCheck> {
greyln!("reading wasm file at {}", wasm.to_string_lossy().lavender());
}

let (wasm, code) = project::compress_wasm(&wasm).wrap_err("failed to compress WASM")?;
// Next, we include the project's hash as a custom section
// in the user's WASM so it can be verified by Cargo stylus'
// reproducible verification. This hash is added as a section that is
// ignored by WASM runtimes, so it will only exist in the file
// for metadata purposes.
// add_project_hash_to_wasm_file(wasm, project_hash)
let (wasm_file_bytes, code) =
project::compress_wasm(&wasm, project_hash).wrap_err("failed to compress WASM")?;

greyln!("contract size: {}", format_file_size(code.len(), 16, 24));

if verbose {
greyln!("wasm size: {}", format_file_size(wasm.len(), 96, 128));
greyln!(
"wasm size: {}",
format_file_size(wasm_file_bytes.len(), 96, 128)
);
greyln!("connecting to RPC: {}", &cfg.common_cfg.endpoint.lavender());
}

Expand All @@ -73,34 +83,23 @@ pub async fn check(cfg: &CheckConfig) -> Result<ProgramCheck> {
let codehash = alloy_primitives::keccak256(&code);

if program_exists(codehash, &provider).await? {
return Ok(ProgramCheck::Active { code, project_hash });
return Ok(ProgramCheck::Active { code });
}

let address = cfg.program_address.unwrap_or(H160::random());
let fee = check_activate(code.clone().into(), address, &provider).await?;
let visual_fee = format_data_fee(fee).unwrap_or("???".red());
greyln!("wasm data fee: {visual_fee}");
Ok(ProgramCheck::Ready {
code,
fee,
project_hash,
})
Ok(ProgramCheck::Ready { code, fee })
}

/// Whether a program is active, or needs activation.
#[derive(PartialEq)]
pub enum ProgramCheck {
/// Program already exists onchain.
Active {
code: Vec<u8>,
project_hash: [u8; 32],
},
Active { code: Vec<u8> },
/// Program can be activated with the given data fee.
Ready {
code: Vec<u8>,
fee: U256,
project_hash: [u8; 32],
},
Ready { code: Vec<u8>, fee: U256 },
}

impl ProgramCheck {
Expand All @@ -110,14 +109,6 @@ impl ProgramCheck {
Self::Ready { code, .. } => code,
}
}

pub fn project_hash(&self) -> &[u8; 32] {
match self {
Self::Active { project_hash, .. } => project_hash,
Self::Ready { project_hash, .. } => project_hash,
}
}

pub fn suggest_fee(&self) -> U256 {
match self {
Self::Active { .. } => U256::default(),
Expand All @@ -132,11 +123,9 @@ impl CheckConfig {
return Ok((wasm, [0u8; 32]));
}
let cfg = BuildConfig::new(self.common_cfg.rust_stable);
let project_hash = project::hash_files(
self.common_cfg.source_files_for_project_hash.clone(),
cfg.clone(),
)?;
let wasm = project::build_dylib(cfg)?;
let wasm = project::build_dylib(cfg.clone())?;
let project_hash =
project::hash_files(self.common_cfg.source_files_for_project_hash.clone(), cfg)?;
Ok((wasm, project_hash))
}
}
Expand Down
4 changes: 4 additions & 0 deletions check/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,7 @@ pub const GITHUB_TEMPLATE_REPO_MINIMAL: &str =

/// One ether in wei.
pub const ONE_ETH: U256 = U256([1000000000000000000, 0, 0, 0]);

/// Name of the custom wasm section that is added to contracts deployed with cargo stylus
/// to include a hash of the Rust project's source files for reproducible verification of builds.
pub const PROJECT_HASH_SECTION_NAME: &str = "project_hash";
12 changes: 4 additions & 8 deletions check/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,7 @@ pub async fn deploy(cfg: DeployConfig) -> Result<()> {
}
}

let contract = cfg
.deploy_contract(program.code(), program.project_hash(), sender, &client)
.await?;
let contract = cfg.deploy_contract(program.code(), sender, &client).await?;

match program {
ProgramCheck::Ready { .. } => cfg.activate(sender, contract, data_fee, &client).await?,
Expand All @@ -98,11 +96,10 @@ impl DeployConfig {
async fn deploy_contract(
&self,
code: &[u8],
project_hash: &[u8; 32],
sender: H160,
client: &SignerClient,
) -> Result<H160> {
let init_code = program_deployment_calldata(code, project_hash);
let init_code = program_deployment_calldata(code);

let tx = Eip1559TransactionRequest::new()
.from(sender)
Expand Down Expand Up @@ -231,23 +228,22 @@ pub async fn run_tx(
}

/// Prepares an EVM bytecode prelude for contract creation.
pub fn program_deployment_calldata(code: &[u8], hash: &[u8; 32]) -> Vec<u8> {
pub fn program_deployment_calldata(code: &[u8]) -> Vec<u8> {
let mut code_len = [0u8; 32];
U256::from(code.len()).to_big_endian(&mut code_len);
let mut deploy: Vec<u8> = vec![];
deploy.push(0x7f); // PUSH32
deploy.extend(code_len);
deploy.push(0x80); // DUP1
deploy.push(0x60); // PUSH1
deploy.push(42 + 1 + 32); // prelude + version + hash
deploy.push(42 + 1); // prelude + version + hash
rauljordan marked this conversation as resolved.
Show resolved Hide resolved
deploy.push(0x60); // PUSH1
deploy.push(0x00);
deploy.push(0x39); // CODECOPY
deploy.push(0x60); // PUSH1
deploy.push(0x00);
deploy.push(0xf3); // RETURN
deploy.push(0x00); // version
deploy.extend(hash);
deploy.extend(code);
deploy
}
Expand Down
4 changes: 4 additions & 0 deletions check/src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ fn create_image(version: &str) -> Result<()> {
RUN rustup target add wasm32-unknown-unknown
RUN rustup target add wasm32-wasi
RUN rustup target add aarch64-unknown-linux-gnu
RUN rustup toolchain install nightly
RUN rustup toolchain install nightly-aarch64-apple-darwin
RUN rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
RUN rustup component add rust-src --toolchain nightly-aarch64-apple-darwin
RUN cargo install cargo-stylus
RUN cargo install --force cargo-stylus-check
RUN cargo install --force cargo-stylus-replay
Expand Down
Loading
Loading