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

Add Rust specific build info to metadata #680

Merged
merged 22 commits into from
Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8fd0b84
Write (slightly-hardcoded) build info to metadata
HCastano Aug 3, 2022
92ad530
Add `channel-date` formatted rustc version to metadata
HCastano Aug 4, 2022
42e22c4
Remove `features` from `BuildInfo`
HCastano Aug 4, 2022
beac37e
Add `wasm-opt` version to metadata
HCastano Aug 8, 2022
f6c3fa2
Move `BuildInfo` construction to `build` closure
HCastano Aug 8, 2022
ad19ec9
Add `build_info` field to tests
HCastano Aug 8, 2022
a12564c
Improve conversion between `BuildInfo` and `serde_json::Map`
HCastano Aug 10, 2022
b7a3d18
Merge branch 'master' into hc-add-build-info
HCastano Aug 18, 2022
6a2a1b3
Add `version` getter to `WasmOptHandler`
HCastano Aug 18, 2022
8d5f92d
Move code which indicates current toolchain to `utils`
HCastano Aug 18, 2022
5a2ad6a
Handle case where `cargo-contract` version can't be parsed
HCastano Aug 18, 2022
415ec3d
Merge branch 'master' into hc-add-build-info
HCastano Aug 29, 2022
7ec78dd
Use a stable `rustc` version
HCastano Aug 29, 2022
5c65ff9
Merge branch 'master' into hc-add-build-info
HCastano Sep 29, 2022
46ea782
Add `keep_debug_symbols` to metadata
HCastano Sep 29, 2022
276a7a4
Add `CHANGELOG` entry
HCastano Sep 29, 2022
8a6630c
Merge branch 'master' into hc-add-build-info
HCastano Oct 19, 2022
83aed6d
Remove `version` from `WasmOptSettings`
HCastano Oct 19, 2022
bae9094
Add target triple to `build_info`
HCastano Oct 19, 2022
00e8213
Move `CARGO_PKG_VERSION` into a const
HCastano Oct 19, 2022
a75b726
Appease Clippy
HCastano Oct 19, 2022
6eea64c
Rename field to more accurate `rust_toolchain`
HCastano Oct 20, 2022
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Add Rust specific build info to metadata - [#680](https://github.com/paritytech/cargo-contract/pull/680)

### Changed
- Removed requirement to install binaryen. The `wasm-opt` tool is now compiled into `cargo-contract`.

Expand Down
37 changes: 33 additions & 4 deletions crates/cargo-contract/src/cmd/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ use std::{
/// This is the maximum number of pages available for a contract to allocate.
const MAX_MEMORY_PAGES: u32 = 16;

/// Version of the currently executing `cargo-contract` binary.
const VERSION: &str = env!("CARGO_PKG_VERSION");

/// Arguments to use when executing `build` or `check` commands.
#[derive(Default)]
pub(crate) struct ExecuteArgs {
Expand Down Expand Up @@ -284,6 +287,7 @@ fn exec_cargo_for_wasm_target(
let cargo_build = |manifest_path: &ManifestPath| {
let target_dir = &crate_metadata.target_directory;
let target_dir = format!("--target-dir={}", target_dir.to_string_lossy());

let mut args = vec![
"--target=wasm32-unknown-unknown",
"-Zbuild-std",
Expand Down Expand Up @@ -576,6 +580,8 @@ pub fn assert_debug_mode_supported(ink_version: &Version) -> anyhow::Result<()>
///
/// It does so by invoking `cargo build` and then post processing the final binary.
pub(crate) fn execute(args: ExecuteArgs) -> Result<BuildResult> {
use crate::cmd::metadata::BuildInfo;

let ExecuteArgs {
manifest_path,
verbosity,
Expand All @@ -596,7 +602,9 @@ pub(crate) fn execute(args: ExecuteArgs) -> Result<BuildResult> {
assert_debug_mode_supported(&crate_metadata.ink_version)?;
}

let build = || -> Result<OptimizationResult> {
let build = || -> Result<(OptimizationResult, BuildInfo)> {
use crate::cmd::metadata::WasmOptSettings;

if skip_linting {
maybe_println!(
verbosity,
Expand Down Expand Up @@ -650,7 +658,26 @@ pub(crate) fn execute(args: ExecuteArgs) -> Result<BuildResult> {
&crate_metadata.contract_artifact_name,
)?;

Ok(optimization_result)
let cargo_contract_version = if let Ok(version) = Version::parse(VERSION) {
version
} else {
anyhow::bail!(
"Unable to parse version number for the currently running \
`cargo-contract` binary."
);
};

let build_info = BuildInfo {
rust_toolchain: crate::util::rust_toolchain()?,
cargo_contract_version,
build_mode,
wasm_opt_settings: WasmOptSettings {
optimization_passes,
keep_debug_symbols,
},
};

Ok((optimization_result, build_info))
};

let (opt_result, metadata_result) = match build_artifact {
Expand Down Expand Up @@ -689,11 +716,11 @@ pub(crate) fn execute(args: ExecuteArgs) -> Result<BuildResult> {
(None, None)
}
BuildArtifacts::CodeOnly => {
let optimization_result = build()?;
let (optimization_result, _build_info) = build()?;
(Some(optimization_result), None)
}
BuildArtifacts::All => {
let optimization_result = build()?;
let (optimization_result, build_info) = build()?;

let metadata_result = super::metadata::execute(
&crate_metadata,
Expand All @@ -702,7 +729,9 @@ pub(crate) fn execute(args: ExecuteArgs) -> Result<BuildResult> {
verbosity,
build_artifact.steps(),
&unstable_flags,
build_info,
)?;

(Some(optimization_result), Some(metadata_result))
}
};
Expand Down
48 changes: 46 additions & 2 deletions crates/cargo-contract/src/cmd/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use crate::{
ManifestPath,
Workspace,
},
BuildMode,
Network,
OptimizationPasses,
UnstableFlags,
Verbosity,
};
Expand Down Expand Up @@ -73,6 +75,40 @@ struct ExtendedMetadataResult {
user: Option<User>,
}

/// Information about the settings used to build a particular ink! contract.
///
/// Note that this should be an optional part of the metadata since it may not necessarily
/// translate to other languages (e.g ask!, Solidity).
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub struct BuildInfo {
/// The Rust toolchain used to build the contract.
pub rust_toolchain: String,
/// The version of `cargo-contract` used to build the contract.
pub cargo_contract_version: Version,
/// The type of build that was used when building the contract.
pub build_mode: BuildMode,
/// Information about the `wasm-opt` optimization settings.
pub wasm_opt_settings: WasmOptSettings,
}

impl TryFrom<BuildInfo> for serde_json::Map<String, serde_json::Value> {
type Error = serde_json::Error;

fn try_from(build_info: BuildInfo) -> Result<Self, Self::Error> {
let tmp = serde_json::to_string(&build_info)?;
serde_json::from_str(&tmp)
}
}

/// Settings used when optimizing the Wasm binary using Binaryen's `wasm-opt`.
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub struct WasmOptSettings {
/// The level of optimization used during the `wasm-opt` run.
pub optimization_passes: OptimizationPasses,
/// Whether or not the Wasm name section should be kept.
pub keep_debug_symbols: bool,
}

/// Generates a file with metadata describing the ABI of the smart contract.
///
/// It does so by generating and invoking a temporary workspace member.
Expand All @@ -83,6 +119,7 @@ pub(crate) fn execute(
verbosity: Verbosity,
total_steps: usize,
unstable_options: &UnstableFlags,
build_info: BuildInfo,
) -> Result<MetadataResult> {
let target_directory = crate_metadata.target_directory.clone();
let out_path_metadata = target_directory.join(METADATA_FILE);
Expand All @@ -95,7 +132,7 @@ pub(crate) fn execute(
source,
contract,
user,
} = extended_metadata(crate_metadata, final_contract_wasm)?;
} = extended_metadata(crate_metadata, final_contract_wasm, build_info)?;

let generate_metadata = |manifest_path: &ManifestPath| -> Result<()> {
let mut current_progress = 5;
Expand Down Expand Up @@ -171,6 +208,7 @@ pub(crate) fn execute(
fn extended_metadata(
crate_metadata: &CrateMetadata,
final_contract_wasm: &Path,
build_info: BuildInfo,
) -> Result<ExtendedMetadataResult> {
let contract_package = &crate_metadata.root_package;
let ink_version = &crate_metadata.ink_version;
Expand All @@ -193,7 +231,13 @@ fn extended_metadata(
let compiler = SourceCompiler::new(Compiler::RustC, rust_version);
let wasm = fs::read(final_contract_wasm)?;
let hash = blake2_hash(wasm.as_slice());
Source::new(Some(SourceWasm::new(wasm)), hash, lang, compiler)
Source::new(
Some(SourceWasm::new(wasm)),
hash,
lang,
compiler,
Some(build_info.try_into()?),
)
};

// Required contract fields
Expand Down
4 changes: 2 additions & 2 deletions crates/cargo-contract/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl FromStr for HexData {
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum OptimizationPasses {
Zero,
One,
Expand Down Expand Up @@ -298,7 +298,7 @@ impl Default for BuildArtifacts {
}

/// The mode to build the contract in.
#[derive(Eq, PartialEq, Copy, Clone, Debug, serde::Serialize)]
#[derive(Eq, PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum BuildMode {
/// Functionality to output debug messages is build into the contract.
Debug,
Expand Down
8 changes: 8 additions & 0 deletions crates/cargo-contract/src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ fn assert_channel() -> Result<()> {
}
}

// Returns the current Rust toolchain formatted by `<channel>-<target-triple>`.
pub(crate) fn rust_toolchain() -> Result<String> {
let meta = rustc_version::version_meta()?;
let toolchain = format!("{:?}-{}", meta.channel, meta.host,).to_lowercase();

Ok(toolchain)
}

/// Invokes `cargo` with the subcommand `command` and the supplied `args`.
///
/// In case `working_dir` is set, the command will be invoked with that folder
Expand Down
59 changes: 54 additions & 5 deletions crates/metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
//! let language = SourceLanguage::new(Language::Ink, Version::new(2, 1, 0));
//! let compiler = SourceCompiler::new(Compiler::RustC, Version::parse("1.46.0-nightly").unwrap());
//! let wasm = SourceWasm::new(vec![0u8]);
//! let source = Source::new(Some(wasm), CodeHash([0u8; 32]), language, compiler);
//! // Optional information about how the contract was build
//! let build_info: Map<String, Value> = Map::new();
//! let source = Source::new(Some(wasm), CodeHash([0u8; 32]), language, compiler, Some(build_info));
//! let contract = Contract::builder()
//! .name("incrementer".to_string())
//! .version(Version::new(2, 1, 0))
Expand Down Expand Up @@ -137,6 +139,11 @@ pub struct Source {
/// with the metadata.
#[serde(skip_serializing_if = "Option::is_none")]
pub wasm: Option<SourceWasm>,
/// Extra information about the environment in which the contract was built.
///
/// Useful for producing deterministic builds.
#[serde(skip_serializing_if = "Option::is_none")]
pub build_info: Option<Map<String, Value>>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why we convert to loosely typed json Map here? Is that for alt. compilers e.g. solang to provide arbitrary data here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, other compilers may want to include other info here. It's also useful for us if we decide that we need to add/remove info later on

}

impl Source {
Expand All @@ -146,12 +153,14 @@ impl Source {
hash: CodeHash,
language: SourceLanguage,
compiler: SourceCompiler,
build_info: Option<Map<String, Value>>,
) -> Self {
Source {
hash,
language,
compiler,
wasm,
build_info,
}
}
}
Expand Down Expand Up @@ -646,7 +655,25 @@ mod tests {
Version::parse("1.46.0-nightly").unwrap(),
);
let wasm = SourceWasm::new(vec![0u8, 1u8, 2u8]);
let source = Source::new(Some(wasm), CodeHash([0u8; 32]), language, compiler);
let build_info = json! {
{
"example_compiler_version": 42,
"example_settings": [],
"example_name": "increment"
}
}
.as_object()
.unwrap()
.clone();

let source = Source::new(
Some(wasm),
CodeHash([0u8; 32]),
language,
compiler,
Some(build_info),
);

let contract = Contract::builder()
.name("incrementer")
.version(Version::new(2, 1, 0))
Expand Down Expand Up @@ -690,7 +717,12 @@ mod tests {
"hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"language": "ink! 2.1.0",
"compiler": "rustc 1.46.0-nightly",
"wasm": "0x000102"
"wasm": "0x000102",
"build_info": {
"example_compiler_version": 42,
"example_settings": [],
"example_name": "increment"
}
},
"contract": {
"name": "incrementer",
Expand Down Expand Up @@ -729,7 +761,7 @@ mod tests {
Compiler::RustC,
Version::parse("1.46.0-nightly").unwrap(),
);
let source = Source::new(None, CodeHash([0u8; 32]), language, compiler);
let source = Source::new(None, CodeHash([0u8; 32]), language, compiler, None);
let contract = Contract::builder()
.name("incrementer")
.version(Version::new(2, 1, 0))
Expand Down Expand Up @@ -782,7 +814,24 @@ mod tests {
Version::parse("1.46.0-nightly").unwrap(),
);
let wasm = SourceWasm::new(vec![0u8, 1u8, 2u8]);
let source = Source::new(Some(wasm), CodeHash([0u8; 32]), language, compiler);
let build_info = json! {
{
"example_compiler_version": 42,
"example_settings": [],
"example_name": "increment",
}
}
.as_object()
.unwrap()
.clone();

let source = Source::new(
Some(wasm),
CodeHash([0u8; 32]),
language,
compiler,
Some(build_info),
);
let contract = Contract::builder()
.name("incrementer")
.version(Version::new(2, 1, 0))
Expand Down