-
Notifications
You must be signed in to change notification settings - Fork 40
feat: Build verifiable contracts #800
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
Changes from 6 commits
ea47304
faae645
233422e
cd8601e
74fde11
9f2ad37
6fdeafa
062fd13
044881f
3b9250b
23daed5
25e97d6
ca08e8d
d765c04
e099c9c
661a65f
8b5ca42
0bf0202
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,17 +1,21 @@ | ||||||||||||
| // SPDX-License-Identifier: GPL-3.0 | ||||||||||||
|
|
||||||||||||
| use super::{BuildArgs, Profile}; | ||||||||||||
| use crate::cli; | ||||||||||||
| use pop_contracts::{MetadataSpec, Verbosity, build_smart_contract}; | ||||||||||||
| use pop_contracts::{BuildMode, ImageVariant, MetadataSpec, Verbosity, build_smart_contract}; | ||||||||||||
| use std::path::PathBuf; | ||||||||||||
|
|
||||||||||||
| /// Configuration for building a smart contract. | ||||||||||||
| pub struct BuildContract { | ||||||||||||
| /// Path of the contract project. | ||||||||||||
| pub(crate) path: PathBuf, | ||||||||||||
| /// Build profile: `true` for release mode, `false` for debug mode. | ||||||||||||
| pub(crate) release: bool, | ||||||||||||
| /// Build profile: `true` for release mode, `false` for debug mode, `verifiable` for | ||||||||||||
| /// deterministic, release mode. | ||||||||||||
tsenovilla marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||
| pub(crate) build_mode: BuildMode, | ||||||||||||
| /// Which specification to use for contract metadata. | ||||||||||||
| pub(crate) metadata: Option<MetadataSpec>, | ||||||||||||
| /// A custom image for a verifiable build | ||||||||||||
| pub(crate) image: Option<ImageVariant>, | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| impl BuildContract { | ||||||||||||
|
|
@@ -27,10 +31,107 @@ impl BuildContract { | |||||||||||
| fn build(self, cli: &mut impl cli::traits::Cli) -> anyhow::Result<&'static str> { | ||||||||||||
| cli.intro("Building your contract")?; | ||||||||||||
| // Build contract. | ||||||||||||
| let build_result = | ||||||||||||
| build_smart_contract(&self.path, self.release, Verbosity::Default, self.metadata)?; | ||||||||||||
| let build_result = build_smart_contract( | ||||||||||||
| &self.path, | ||||||||||||
| self.build_mode, | ||||||||||||
| Verbosity::Default, | ||||||||||||
| self.metadata, | ||||||||||||
| self.image, | ||||||||||||
| )?; | ||||||||||||
| cli.success(build_result.display())?; | ||||||||||||
| cli.outro("Build completed successfully!")?; | ||||||||||||
| Ok("contract") | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /// Resolve the `BuildMode` to use in a contract build depending on the specified args | ||||||||||||
| /// | ||||||||||||
| /// # Arguments | ||||||||||||
| /// * `args` - The `BuildArgs` needed to resolve the `BuildMode` | ||||||||||||
| pub(super) fn resolve_build_mode(args: &BuildArgs) -> BuildMode { | ||||||||||||
| match (&args.profile, args.verifiable) { | ||||||||||||
| (Some(Profile::Release), false) | (Some(Profile::Production), false) => BuildMode::Release, | ||||||||||||
| (None, true) => BuildMode::Verifiable, | ||||||||||||
| (None, false) if args.release => BuildMode::Release, | ||||||||||||
|
||||||||||||
| (None, false) if args.release => BuildMode::Release, | |
| (None, false) if args.release => BuildMode::Release, | |
| // This case is unreachable due to CLI `conflicts_with_all` validation, | |
| // but is included for clarity in case the function is called programmatically. | |
| (Some(_), true) => BuildMode::Debug, // Unreachable due to CLI conflicts_with_all |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the review is right, the fallback is there to reduce the casuistry and just default to the simplest mode instead of failing if an invalid combination of args is used. As the review says, clap will handle this conflict, so I wouldn't add a specific case just for tests
AlexD10S marked this conversation as resolved.
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,7 +47,7 @@ pub(crate) struct BuildArgs { | |
| #[cfg(feature = "chain")] | ||
| pub command: Option<Command>, | ||
| /// Directory path with flag for your project [default: current directory] | ||
| #[arg(long)] | ||
| #[arg(long, visible_alias = "manifest-path")] | ||
tsenovilla marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| pub(crate) path: Option<PathBuf>, | ||
| /// Directory path without flag for your project [default: current directory] | ||
| #[arg(value_name = "PATH", index = 1, conflicts_with = "path")] | ||
|
|
@@ -84,10 +84,15 @@ pub(crate) struct BuildArgs { | |
| #[clap(long, help_heading = CONTRACT_HELP_HEADER)] | ||
| #[cfg(feature = "contract")] | ||
| pub(crate) metadata: Option<MetadataSpec>, | ||
| /// Whether to build in a way that the contract is verifiable | ||
| ///#[clap(long, help_heading = CONTRACT_HELP_HEADER)] | ||
| ///#[cfg(feature = "contract")] | ||
| ///pub(crate) verifiable: bool | ||
| /// Whether to build in a way that the contract is verifiable. For verifiable contracts, use | ||
| /// --manifest-path instead of --path to directly point to your contracts Cargo.toml | ||
tsenovilla marked this conversation as resolved.
Show resolved
Hide resolved
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the I was thinking on simply disabling
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I see. The cargo-contract is a very confusing implementation no?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah it's not the best for third party integration, but normal anyway as it's designed to call The line you mentioned is actually useless for verifiable contracts, as if the user specifies So yeah it's not optimal but Idk if we have something better |
||
| #[clap(long, conflicts_with_all = ["release", "profile"], help_heading = CONTRACT_HELP_HEADER)] | ||
| #[cfg(feature = "contract")] | ||
| pub(crate) verifiable: bool, | ||
| /// Custom image for verifiable builds | ||
| #[clap(long, help_heading = CONTRACT_HELP_HEADER)] | ||
|
||
| #[cfg(feature = "contract")] | ||
| pub(crate) image: Option<String>, | ||
| } | ||
|
|
||
| /// Subcommand for building chain artifacts. | ||
|
|
@@ -120,12 +125,10 @@ impl Command { | |
|
|
||
| #[cfg(feature = "contract")] | ||
| if pop_contracts::is_supported(&project_path)? { | ||
| // All commands originating from root command are valid | ||
| let release = match &args.profile { | ||
| Some(profile) => (*profile).into(), | ||
| None => args.release, | ||
| }; | ||
| BuildContract { path: project_path, release, metadata: args.metadata }.execute()?; | ||
| let build_mode = contract::resolve_build_mode(&args); | ||
| let image = contract::resolve_image(&args)?; | ||
| BuildContract { path: project_path, build_mode, metadata: args.metadata, image } | ||
| .execute()?; | ||
| return Ok(()); | ||
| } | ||
|
|
||
|
|
@@ -361,6 +364,10 @@ mod tests { | |
| only_runtime: false, | ||
| #[cfg(feature = "contract")] | ||
| metadata: None, | ||
| #[cfg(feature = "contract")] | ||
| verifiable: false, | ||
| #[cfg(feature = "contract")] | ||
| image: None, | ||
| }, | ||
| project_path, | ||
| &mut cli, | ||
|
|
@@ -429,6 +436,10 @@ mod tests { | |
| only_runtime: false, | ||
| #[cfg(feature = "contract")] | ||
| metadata: None, | ||
| #[cfg(feature = "contract")] | ||
| verifiable: false, | ||
| #[cfg(feature = "contract")] | ||
| image: None, | ||
| })?; | ||
|
|
||
| Ok(()) | ||
|
|
@@ -474,6 +485,10 @@ mod tests { | |
| only_runtime: false, | ||
| #[cfg(feature = "contract")] | ||
| metadata: None, | ||
| #[cfg(feature = "contract")] | ||
| verifiable: false, | ||
| #[cfg(feature = "contract")] | ||
| image: None, | ||
| })?; | ||
|
|
||
| // Test 2: Execute with production profile | ||
|
|
@@ -496,6 +511,10 @@ mod tests { | |
| only_runtime: false, | ||
| #[cfg(feature = "contract")] | ||
| metadata: None, | ||
| #[cfg(feature = "contract")] | ||
| verifiable: false, | ||
| #[cfg(feature = "contract")] | ||
| image: None, | ||
| })?; | ||
|
|
||
| // Test 3: Execute with custom features | ||
|
|
@@ -515,6 +534,10 @@ mod tests { | |
| only_runtime: false, | ||
| #[cfg(feature = "contract")] | ||
| metadata: None, | ||
| #[cfg(feature = "contract")] | ||
| verifiable: false, | ||
| #[cfg(feature = "contract")] | ||
| image: None, | ||
| })?; | ||
| } | ||
|
|
||
|
|
@@ -538,6 +561,10 @@ mod tests { | |
| only_runtime: false, | ||
| #[cfg(feature = "contract")] | ||
| metadata: None, | ||
| #[cfg(feature = "contract")] | ||
| verifiable: false, | ||
| #[cfg(feature = "contract")] | ||
| image: None, | ||
| })?; | ||
|
|
||
| // Test 5: Execute with path_pos instead of path | ||
|
|
@@ -560,6 +587,10 @@ mod tests { | |
| only_runtime: false, | ||
| #[cfg(feature = "contract")] | ||
| metadata: None, | ||
| #[cfg(feature = "contract")] | ||
| verifiable: false, | ||
| #[cfg(feature = "contract")] | ||
| image: None, | ||
| })?; | ||
|
|
||
| // Test 6: Execute with benchmark and try_runtime flags | ||
|
|
@@ -579,6 +610,10 @@ mod tests { | |
| only_runtime: false, | ||
| #[cfg(feature = "contract")] | ||
| metadata: None, | ||
| #[cfg(feature = "contract")] | ||
| verifiable: false, | ||
| #[cfg(feature = "contract")] | ||
| image: None, | ||
| })?; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Temporarily needed til these changes are released. Please note that the base branch for this PR isn't main but
feat/contract-verificationso we can merge as soon as the review is done