Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Exclude all Rust build output directories.
# This prevents Docker from sending gigabytes of compiled artifacts
# as part of the build context when building Dockerfile.local.
**/target/

# Not needed to build sc-meta from source.
.github/
.vscode/
tools/
contracts/
template-test/
install-debugger-test/
4 changes: 2 additions & 2 deletions Cargo.lock

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

68 changes: 62 additions & 6 deletions framework/meta-lib/src/cargo_toml/cargo_toml_contents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,78 @@ impl CargoTomlContents {
pub fn package_name(&self) -> String {
self.toml_value
.get(PACKAGE)
.expect("missing package in Cargo.toml")
.unwrap_or_else(|| {
panic!(
"missing [package] section in Cargo.toml: {}",
self.path.display()
)
})
.get("name")
.expect("missing package name in Cargo.toml")
.unwrap_or_else(|| {
panic!(
"missing package name in Cargo.toml: {}",
self.path.display()
)
})
.as_str()
.expect("package name not a string value")
.unwrap_or_else(|| {
panic!(
"package name is not a string in Cargo.toml: {}",
self.path.display()
)
})
.to_string()
}

pub fn package_version(&self) -> String {
self.toml_value
.get(PACKAGE)
.unwrap_or_else(|| {
panic!(
"missing [package] section in Cargo.toml: {}",
self.path.display()
)
})
.get("version")
.unwrap_or_else(|| {
panic!(
"missing package version in Cargo.toml: {}",
self.path.display()
)
})
.as_str()
.unwrap_or_else(|| {
panic!(
"package version is not a string in Cargo.toml: {}",
self.path.display()
)
})
.to_string()
}

pub fn package_edition(&self) -> String {
self.toml_value
.get(PACKAGE)
.expect("missing package in Cargo.toml")
.unwrap_or_else(|| {
panic!(
"missing [package] section in Cargo.toml: {}",
self.path.display()
)
})
.get("edition")
.expect("missing package name in Cargo.toml")
.unwrap_or_else(|| {
panic!(
"missing package edition in Cargo.toml: {}",
self.path.display()
)
})
.as_str()
.expect("package name not a string value")
.unwrap_or_else(|| {
panic!(
"package edition is not a string in Cargo.toml: {}",
self.path.display()
)
})
.to_string()
}

Expand Down
5 changes: 1 addition & 4 deletions framework/meta-lib/src/contract/sc_config/wasm_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,7 @@ impl ContractVariant {

print_generate_codehash(&output_codehash_path.to_string_lossy());

let wasm_bytes = fs::read(&output_wasm_path).expect("failed to read compiled contract");
let hash = multiversx_sc::chain_core::std::code_hash(&wasm_bytes);
let hex_hash = hex::encode(hash);
fs::write(&output_codehash_path, hex_hash).expect("failed to write codehash file");
tools::generate_codehash(&output_wasm_path, &output_codehash_path);
}
}

Expand Down
2 changes: 2 additions & 0 deletions framework/meta-lib/src/tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub(crate) mod panic_report;
mod rustc_version;
mod rustc_version_warning;
pub mod twiggy;
mod wasm_codehash;
mod wasm_extractor;
pub mod wasm_opt;
mod wasm_to_wat;
Expand All @@ -13,6 +14,7 @@ pub use find_workspace::{find_current_workspace, find_workspace};
pub use git_describe::git_describe;
pub use rustc_version::RustcVersion;
pub use rustc_version_warning::rustc_version_warning;
pub use wasm_codehash::{CODEHASH_FILE_SUFFIX, generate_codehash, generate_codehashes_in_output};
pub use wasm_extractor::OpcodeVersion;
pub use wasm_extractor::code_report::CodeReport;
pub use wasm_extractor::extractor::WasmInfo;
Expand Down
39 changes: 39 additions & 0 deletions framework/meta-lib/src/tools/wasm_codehash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::{fs, path::Path};

pub const CODEHASH_FILE_SUFFIX: &str = ".codehash.txt";

/// Computes the Blake2b-256 code hash of the `.wasm` file at `wasm_path`,
/// and writes the lowercase hex string to `codehash_path`.
pub fn generate_codehash(wasm_path: &Path, codehash_path: &Path) {
let wasm_bytes = fs::read(wasm_path)
.unwrap_or_else(|err| panic!("failed to read wasm file {}: {err}", wasm_path.display()));
let hash = multiversx_sc::chain_core::std::code_hash(&wasm_bytes);
let hex_hash = hex::encode(hash);
fs::write(codehash_path, hex_hash).unwrap_or_else(|err| {
panic!(
"failed to write codehash file {}: {err}",
codehash_path.display()
)
});
}

/// Scans `output_dir` for `.wasm` files and generates a codehash file for each one.
///
/// For every `<name>.wasm` found, writes the Blake2b-256 hash (lowercase hex) to
/// `<name>.codehash.txt` in the same directory.
pub fn generate_codehashes_in_output(output_dir: &Path) {
let Ok(read_dir) = fs::read_dir(output_dir) else {
return;
};
for entry in read_dir.flatten() {
let path = entry.path();
if path.extension().map(|e| e == "wasm").unwrap_or(false) {
let codehash_path = path.with_file_name(format!(
"{}{}",
path.file_stem().unwrap().to_string_lossy(),
CODEHASH_FILE_SUFFIX
));
generate_codehash(&path, &codehash_path);
}
}
}
2 changes: 2 additions & 0 deletions framework/meta/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ common-path = "1.0.0"
bip39 = { version = "2.0", features = ["rand"] }
anyhow = "1.0"
hex = "0.4.3"
base64 = "0.22"
indexmap = { version = "2", features = ["serde"] }
# warning: newer versions require Rust 1.88, hence we are not upgrading yet
zip = { version = "7.2", features = ["deflate"], default-features = false }

Expand Down
69 changes: 69 additions & 0 deletions framework/meta/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
FROM ubuntu:22.04

# Toolchain versions — bump these together when upgrading.
ARG VERSION_RUST="1.93.0"
ARG VERSION_SC_META="0.65.1"
ARG VERSION_WASM_OPT="0.116.1"
ARG TARGETPLATFORM

# Install system dependencies
RUN apt-get update --fix-missing && apt-get install -y \
wget \
build-essential \
git \
pkg-config \
libssl-dev

# Install Rust
RUN wget -O rustup.sh https://sh.rustup.rs && \
chmod +x rustup.sh && \
CARGO_HOME=/rust RUSTUP_HOME=/rust ./rustup.sh \
--verbose \
--default-toolchain ${VERSION_RUST} \
--profile minimal \
-y && \
rm rustup.sh && \
chmod -R 777 /rust && \
rm -rf /rust/registry

# Install sc-meta from crates.io
RUN PATH="/rust/bin:${PATH}" CARGO_HOME=/rust RUSTUP_HOME=/rust \
cargo install multiversx-sc-meta --version ${VERSION_SC_META} --locked && \
rm -rf /rust/registry

# Install wasm32 target
RUN PATH="/rust/bin:${PATH}" CARGO_HOME=/rust RUSTUP_HOME=/rust \
sc-meta install wasm32

# Install wasm-opt
RUN PATH="/rust/bin:${PATH}" CARGO_HOME=/rust RUSTUP_HOME=/rust \
cargo install wasm-opt --version ${VERSION_WASM_OPT} --locked && \
rm -rf /rust/registry

ENV PATH="/rust/bin:${PATH}"
ENV CARGO_HOME="/rust"
ENV RUSTUP_HOME="/rust"

# Exposed to sc-meta at runtime for embedding into .source.json build metadata.
ENV BUILD_METADATA_VERSION_RUST=${VERSION_RUST}
ENV BUILD_METADATA_VERSION_SC_META=${VERSION_SC_META}
ENV BUILD_METADATA_VERSION_WASM_OPT=${VERSION_WASM_OPT}
ENV BUILD_METADATA_TARGETPLATFORM=${TARGETPLATFORM}

# /project — mounted read-only by the caller (the contract source tree)
# /output — mounted read-write by the caller (build artifacts land here)
# /rust/cargo-target-dir — optionally mounted for caching between runs

# Additional arguments forwarded at "docker run" time:
# --project /project (required; set automatically by docker-build)
# --contract <name> (optional)
# --no-wasm-opt (optional)
# --build-root <path> (optional; defaults to /tmp/sc-build inside the container)
ENTRYPOINT ["sc-meta", "reproducible-build", "local-build", \
"--output", "/output", \
"--target-dir", "/rust/cargo-target-dir"]

LABEL frozen="yes"
LABEL rust=${VERSION_RUST}
LABEL sc_meta=${VERSION_SC_META}
LABEL wasm_opt=${VERSION_WASM_OPT}
73 changes: 73 additions & 0 deletions framework/meta/Dockerfile.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
FROM ubuntu:22.04

# Toolchain versions — bump these together when upgrading.
ARG VERSION_RUST="1.93.0"
ARG VERSION_SC_META="local"
ARG VERSION_WASM_OPT="0.116.1"
ARG TARGETPLATFORM

# Install system dependencies
RUN apt-get update --fix-missing && apt-get install -y \
wget \
build-essential \
git \
pkg-config \
libssl-dev

# Install Rust
RUN wget -O rustup.sh https://sh.rustup.rs && \
chmod +x rustup.sh && \
CARGO_HOME=/rust RUSTUP_HOME=/rust ./rustup.sh \
--verbose \
--default-toolchain ${VERSION_RUST} \
--profile minimal \
-y && \
rm rustup.sh && \
chmod -R 777 /rust && \
rm -rf /rust/registry

# Install sc-meta from the local source tree.
# Build context must be the workspace root:
# docker build -f framework/meta/Dockerfile.local <workspace-root>
COPY . /mx-sdk-rs
RUN PATH="/rust/bin:${PATH}" CARGO_HOME=/rust RUSTUP_HOME=/rust \
cargo install --path /mx-sdk-rs/framework/meta --locked && \
rm -rf /rust/registry && \
rm -rf /mx-sdk-rs

# Install wasm32 target
RUN PATH="/rust/bin:${PATH}" CARGO_HOME=/rust RUSTUP_HOME=/rust \
sc-meta install wasm32

# Install wasm-opt
RUN PATH="/rust/bin:${PATH}" CARGO_HOME=/rust RUSTUP_HOME=/rust \
cargo install wasm-opt --version ${VERSION_WASM_OPT} --locked && \
rm -rf /rust/registry

ENV PATH="/rust/bin:${PATH}"
ENV CARGO_HOME="/rust"
ENV RUSTUP_HOME="/rust"

# Exposed to sc-meta at runtime for embedding into .source.json build metadata.
ENV BUILD_METADATA_VERSION_RUST=${VERSION_RUST}
ENV BUILD_METADATA_VERSION_SC_META=${VERSION_SC_META}
ENV BUILD_METADATA_VERSION_WASM_OPT=${VERSION_WASM_OPT}
ENV BUILD_METADATA_TARGETPLATFORM=${TARGETPLATFORM}

# /project — mounted read-only by the caller (the contract source tree)
# /output — mounted read-write by the caller (build artifacts land here)
# /rust/cargo-target-dir — optionally mounted for caching between runs

# Additional arguments forwarded at "docker run" time:
# --project /project (required; set automatically by docker-build)
# --contract <name> (optional)
# --no-wasm-opt (optional)
# --build-root <path> (optional; defaults to /tmp/sc-build inside the container)
ENTRYPOINT ["sc-meta", "reproducible-build", "local-build", \
"--output", "/output", \
"--target-dir", "/rust/cargo-target-dir"]

LABEL frozen="no"
LABEL rust=${VERSION_RUST}
LABEL sc_meta=${VERSION_SC_META}
LABEL wasm_opt=${VERSION_WASM_OPT}
12 changes: 12 additions & 0 deletions framework/meta/docker-build-released.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

# Builds the Docker image using the published sc-meta from crates.io.
# For a local source build, use docker-build.sh.

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

docker build \
--platform linux/amd64 \
-f "$SCRIPT_DIR/Dockerfile" \
-t multiversx/sc-meta-reproducible-build:0.65.1 \
"$SCRIPT_DIR"
16 changes: 16 additions & 0 deletions framework/meta/docker-build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

# Builds the Docker image using the local workspace source tree.
# For the released (crates.io) image, use docker-build-released.sh.

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

echo "$SCRIPT_DIR"

WORKSPACE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"

docker build \
--platform linux/amd64 \
-f "$SCRIPT_DIR/Dockerfile.local" \
-t multiversx/sc-meta-reproducible-build:local \
"$WORKSPACE_ROOT"
Loading
Loading