Skip to content

Commit

Permalink
Extrinsics: allow specifying contract artifact directly (#893)
Browse files Browse the repository at this point in the history
* WIP introduce ContractArtifacts

* WIP introduce ContractArtifacts

* Use ContractArtifacts in call and upload

* Extract function for constructing contract event data field

* WIP refactoring instantiate

* WIP fixing up CodeHas usage, fmt

* Complete instantiate refactoring to use code artifacts

* Attempt to use contract bundle artifact by default

* Fix test compilation

* CLIPPY

* Remove `wasm_path`, put file option first

* Fix conflicting

* Update docs

* Update docs/extrinsics.md

Co-authored-by: Michael Müller <[email protected]>

* Update crates/build/src/crate_metadata.rs

Co-authored-by: Michael Müller <[email protected]>

* Bump assert_cmd from 2.0.7 to 2.0.8

Bumps [assert_cmd](https://github.com/assert-rs/assert_cmd) from 2.0.7 to 2.0.8.
- [Release notes](https://github.com/assert-rs/assert_cmd/releases)
- [Changelog](https://github.com/assert-rs/assert_cmd/blob/master/CHANGELOG.md)
- [Commits](assert-rs/assert_cmd@v2.0.7...v2.0.8)

---
updated-dependencies:
- dependency-name: assert_cmd
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

* Bump regex from 1.7.0 to 1.7.1

Bumps [regex](https://github.com/rust-lang/regex) from 1.7.0 to 1.7.1.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](rust-lang/regex@1.7.0...1.7.1)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

* dependabot: ignore substrate deps (#902)

* dependabot: ignore substrate deps

* Move ignore section and use pattern

* Fix update-types

* Review suggestions

* Fix

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: Michael Müller <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 12, 2023
1 parent 2de0a02 commit 341c7a8
Show file tree
Hide file tree
Showing 12 changed files with 284 additions and 195 deletions.
7 changes: 7 additions & 0 deletions crates/build/src/crate_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ impl CrateMetadata {
pub fn metadata_path(&self) -> PathBuf {
self.target_directory.join(METADATA_FILE)
}

/// Get the path of the contract bundle, containing metadata + code.
pub fn contract_bundle_path(&self) -> PathBuf {
let target_directory = self.target_directory.clone();
let fname_bundle = format!("{}.contract", self.contract_artifact_name);
target_directory.join(fname_bundle)
}
}

/// Get the result of `cargo metadata`, together with the root package id.
Expand Down
12 changes: 12 additions & 0 deletions crates/build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,18 @@ pub fn execute(args: ExecuteArgs) -> Result<BuildResult> {
})
}

/// Returns the blake2 hash of the code slice.
pub fn code_hash(code: &[u8]) -> [u8; 32] {
use blake2::digest::{
consts::U32,
Digest as _,
};
let mut blake2 = blake2::Blake2b::<U32>::new();
blake2.update(code);
let result = blake2.finalize();
result.into()
}

/// Testing individual functions where the build itself is not actually invoked. See [`tests`] for
/// all tests which invoke the `build` command.
#[cfg(test)]
Expand Down
33 changes: 10 additions & 23 deletions crates/build/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// along with cargo-contract. If not, see <http://www.gnu.org/licenses/>.

use crate::{
code_hash,
crate_metadata::CrateMetadata,
maybe_println,
util,
Expand All @@ -31,13 +32,8 @@ use crate::{
};

use anyhow::Result;
use blake2::digest::{
consts::U32,
Digest as _,
};
use colored::Colorize;
use contract_metadata::{
CodeHash,
Compiler,
Contract,
ContractMetadata,
Expand All @@ -58,7 +54,7 @@ use std::{
};
use url::Url;

const METADATA_FILE: &str = "metadata.json";
pub const METADATA_FILE: &str = "metadata.json";

/// Metadata generation result.
#[derive(serde::Serialize)]
Expand Down Expand Up @@ -122,11 +118,8 @@ pub(crate) fn execute(
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);

let fname_bundle = format!("{}.contract", crate_metadata.contract_artifact_name);
let out_path_bundle = target_directory.join(fname_bundle);
let out_path_metadata = crate_metadata.metadata_path();
let out_path_bundle = crate_metadata.contract_bundle_path();

// build the extended contract project metadata
let ExtendedMetadataResult {
Expand All @@ -142,8 +135,10 @@ pub(crate) fn execute(
format!("{}", build_steps).bold(),
"Generating metadata".bright_green().bold()
);
let target_dir_arg =
format!("--target-dir={}", target_directory.to_string_lossy());
let target_dir_arg = format!(
"--target-dir={}",
crate_metadata.target_directory.to_string_lossy()
);
let stdout = util::invoke_cargo(
"run",
[
Expand Down Expand Up @@ -230,10 +225,10 @@ fn extended_metadata(
let lang = SourceLanguage::new(Language::Ink, ink_version.clone());
let compiler = SourceCompiler::new(Compiler::RustC, rust_version);
let wasm = fs::read(final_contract_wasm)?;
let hash = blake2_hash(wasm.as_slice());
let hash = code_hash(wasm.as_slice());
Source::new(
Some(SourceWasm::new(wasm)),
hash,
hash.into(),
lang,
compiler,
Some(build_info.try_into()?),
Expand Down Expand Up @@ -280,11 +275,3 @@ fn extended_metadata(
user,
})
}

/// Returns the blake2 hash of the submitted slice.
pub fn blake2_hash(code: &[u8]) -> CodeHash {
let mut blake2 = blake2::Blake2b::<U32>::new();
blake2.update(code);
let result = blake2.finalize();
CodeHash(result.into())
}
4 changes: 2 additions & 2 deletions crates/build/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ fn generates_metadata(manifest_path: &ManifestPath) -> Result<()> {

// calculate wasm hash
let fs_wasm = fs::read(&crate_metadata.dest_wasm)?;
let expected_hash = crate::metadata::blake2_hash(&fs_wasm[..]);
let expected_hash = crate::code_hash(&fs_wasm[..]);
let expected_wasm = build_byte_str(&fs_wasm);

let expected_language =
Expand All @@ -514,7 +514,7 @@ fn generates_metadata(manifest_path: &ManifestPath) -> Result<()> {
serde_json::Value::Array(vec!["and".into(), "their".into(), "values".into()]),
);

assert_eq!(build_byte_str(&expected_hash.0[..]), hash.as_str().unwrap());
assert_eq!(build_byte_str(&expected_hash[..]), hash.as_str().unwrap());
assert_eq!(expected_wasm, wasm.as_str().unwrap());
assert_eq!(expected_language, language.as_str().unwrap());
assert_eq!(expected_compiler, compiler.as_str().unwrap());
Expand Down
10 changes: 4 additions & 6 deletions crates/cargo-contract/src/cmd/extrinsics/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use super::{
BalanceVariant,
Client,
ContractMessageTranscoder,
CrateMetadata,
DefaultConfig,
ExtrinsicOpts,
PairSigner,
Expand Down Expand Up @@ -95,10 +94,9 @@ impl CallCommand {
}

pub fn run(&self) -> Result<(), ErrorVariant> {
let crate_metadata = CrateMetadata::from_manifest_path(
self.extrinsic_opts.manifest_path.as_ref(),
)?;
let transcoder = ContractMessageTranscoder::load(crate_metadata.metadata_path())?;
let artifacts = self.extrinsic_opts.contract_artifacts()?;
let transcoder = artifacts.contract_transcoder()?;

let call_data = transcoder.encode(&self.message, &self.args)?;
tracing::debug!("Message data: {:?}", hex::encode(&call_data));

Expand Down Expand Up @@ -218,7 +216,7 @@ impl CallCommand {
let result = submit_extrinsic(client, &call, signer).await?;

let display_events =
DisplayEvents::from_events(&result, transcoder, &client.metadata())?;
DisplayEvents::from_events(&result, Some(transcoder), &client.metadata())?;

let output = if self.output_json {
display_events.to_json()?
Expand Down
59 changes: 41 additions & 18 deletions crates/cargo-contract/src/cmd/extrinsics/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,21 @@ use colored::Colorize as _;
use contract_build::Verbosity;
use contract_transcode::{
ContractMessageTranscoder,
Hex,
TranscoderBuilder,
Value,
};

use anyhow::Result;
use std::fmt::Write;
use std::{
fmt::Write,
str::FromStr,
};
use subxt::{
self,
blocks::ExtrinsicEvents,
events::StaticEvent,
metadata::EventFieldMetadata,
};

/// Field that represent data of an event from invoking a contract extrinsic.
Expand Down Expand Up @@ -78,7 +83,7 @@ impl DisplayEvents {
/// Parses events and returns an object which can be serialised
pub fn from_events(
result: &ExtrinsicEvents<DefaultConfig>,
transcoder: &ContractMessageTranscoder,
transcoder: Option<&ContractMessageTranscoder>,
subxt_metadata: &subxt::Metadata,
) -> Result<DisplayEvents> {
let mut events: Vec<Event> = vec![];
Expand Down Expand Up @@ -111,22 +116,12 @@ impl DisplayEvents {
) && field_metadata.name() == Some("data")
{
tracing::debug!("event data: {:?}", hex::encode(&event_data));
match transcoder.decode_contract_event(event_data) {
Ok(contract_event) => {
let field = Field::new(
String::from("data"),
contract_event,
field_metadata.type_name().map(|s| s.to_string()),
);
event_entry.fields.push(field);
}
Err(err) => {
tracing::warn!(
"Decoding contract event failed: {:?}. It might have come from another contract.",
err
)
}
}
let field = contract_event_data_field(
transcoder,
field_metadata,
event_data,
)?;
event_entry.fields.push(field);
} else {
let field_name = field_metadata
.name()
Expand Down Expand Up @@ -208,3 +203,31 @@ impl DisplayEvents {
Ok(serde_json::to_string_pretty(self)?)
}
}

/// Construct the contract event data field, attempting to decode the event using the
/// [`ContractMessageTranscoder`] if available.
fn contract_event_data_field(
transcoder: Option<&ContractMessageTranscoder>,
field_metadata: &EventFieldMetadata,
event_data: &mut &[u8],
) -> Result<Field> {
let event_value = if let Some(transcoder) = transcoder {
match transcoder.decode_contract_event(event_data) {
Ok(contract_event) => contract_event,
Err(err) => {
tracing::warn!(
"Decoding contract event failed: {:?}. It might have come from another contract.",
err
);
Value::Hex(Hex::from_str(&hex::encode(&event_data))?)
}
}
} else {
Value::Hex(Hex::from_str(&hex::encode(event_data))?)
};
Ok(Field::new(
String::from("data"),
event_value,
field_metadata.type_name().map(|s| s.to_string()),
))
}
Loading

0 comments on commit 341c7a8

Please sign in to comment.