From c776588b61f1d20742da2c7575f8f6fe9593bf54 Mon Sep 17 00:00:00 2001 From: Alex Bean Date: Thu, 11 Jul 2024 12:47:30 +0200 Subject: [PATCH] test: integration tests, doc tests and improve coverage (#242) * test: fix tests in docs * chore: add docs tests in CI * test: skip_confirm flag for pop up parachain integration testing * test: remove useless tests * test: integration_tests whole process parachains and contracts * chore: add integration tests in CI for contract and parachains * fix: kill process contracts-node after tests * test: more unit tests in pop_contracts * test: unit test for call contracts * test: unit tests for call contract * fix: ci for running cargo test --doc * fix: doc tests --- .github/workflows/ci.yml | 57 ++++- Cargo.lock | 37 ++++ Cargo.toml | 1 + crates/pop-cli/src/commands/up/contract.rs | 13 +- crates/pop-cli/src/commands/up/parachain.rs | 37 ++-- crates/pop-cli/tests/contract.rs | 191 ++++++++++------ crates/pop-cli/tests/parachain.rs | 95 ++++++-- crates/pop-contracts/Cargo.toml | 2 +- crates/pop-contracts/README.md | 206 ++++++++++-------- crates/pop-contracts/src/call.rs | 85 +++++++- crates/pop-contracts/src/errors.rs | 2 + crates/pop-contracts/src/up.rs | 12 +- .../pop-contracts/src/utils/contracts_node.rs | 12 +- crates/pop-contracts/src/utils/helpers.rs | 29 +++ crates/pop-contracts/src/utils/signer.rs | 36 +++ crates/pop-contracts/tests/contract.rs | 119 ---------- .../tests/files/testing.contract | 2 +- crates/pop-parachains/Cargo.toml | 1 + crates/pop-parachains/README.md | 119 +++++----- 19 files changed, 674 insertions(+), 382 deletions(-) delete mode 100644 crates/pop-contracts/tests/contract.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 068d6131..d18ff599 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,7 +88,7 @@ jobs: files: codecov.json fail_ci_if_error: true - contract-integration-tests: + documentation-tests: needs: lint runs-on: ubuntu-latest steps: @@ -98,18 +98,67 @@ jobs: with: git-user: ${{ env.GITHUB_ACTOR }} + - name: Run doc tests + run: cargo test --doc + + contract-integration-tests: + needs: lint + strategy: + matrix: + os: ["ubuntu-latest", "macos-latest"] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + default: true + target: wasm32-unknown-unknown + components: rust-src, clippy + + - name: Cache + uses: Swatinem/rust-cache@v2 + - name: Run integration tests run: cargo test --no-default-features --features contract --test contract parachain-integration-tests: needs: lint - runs-on: ubuntu-latest + strategy: + matrix: + os: ["ubuntu-latest", "macos-latest"] + runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 - - uses: "./.github/actions/init" + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + default: true + target: wasm32-unknown-unknown + components: rust-src, clippy + + - name: Cache + uses: Swatinem/rust-cache@v2 + + - name: Install packages (Linux) + if: matrix.os == 'ubuntu-latest' + uses: "./.github/actions/init" with: git-user: ${{ env.GITHUB_ACTOR }} + - name: Install packages (macOS) + if: matrix.os == 'macos-latest' + run: | + brew install protobuf + protoc --version + - name: Run integration tests run: cargo test --no-default-features --features parachain --test parachain diff --git a/Cargo.lock b/Cargo.lock index 45450f11..47185a8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -504,6 +504,28 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "async-task" version = "4.7.1" @@ -4519,6 +4541,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-test", "url", ] @@ -4543,6 +4566,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-test", "toml_edit 0.22.14", "url", "walkdir", @@ -6935,6 +6959,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + [[package]] name = "tokio-tungstenite" version = "0.20.1" diff --git a/Cargo.toml b/Cargo.toml index 6183fbe5..044374fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ predicates = "3.1.0" tar = "0.4.40" tempfile = "3.10" thiserror = "1.0.58" +tokio-test = "0.4.4" # networking reqwest = { version = "0.12", features = ["json"] } diff --git a/crates/pop-cli/src/commands/up/contract.rs b/crates/pop-cli/src/commands/up/contract.rs index 239e36a3..bfcb3a57 100644 --- a/crates/pop-cli/src/commands/up/contract.rs +++ b/crates/pop-cli/src/commands/up/contract.rs @@ -15,8 +15,11 @@ use pop_contracts::{ }; use sp_core::Bytes; use sp_weights::Weight; -use std::path::{Path, PathBuf}; use std::process::Child; +use std::{ + path::{Path, PathBuf}, + process::Command, +}; use tempfile::NamedTempFile; use url::Url; @@ -259,14 +262,18 @@ impl UpContractCommand { /// Handles the optional termination of a local running node. fn terminate_node(process: Option<(Child, NamedTempFile)>) -> anyhow::Result<()> { // Prompt to close any launched node - let Some((mut process, log)) = process else { + let Some((process, log)) = process else { return Ok(()); }; if confirm("Would you like to terminate the local node?") .initial_value(true) .interact()? { - process.kill()? + // Stop the process contracts-node + Command::new("kill") + .args(["-s", "TERM", &process.id().to_string()]) + .spawn()? + .wait()?; } else { log.keep()?; log::warning(format!("NOTE: The node is running in the background with process ID {}. Please terminate it manually when done.", process.id()))?; diff --git a/crates/pop-cli/src/commands/up/parachain.rs b/crates/pop-cli/src/commands/up/parachain.rs index 0766e570..c91ae0db 100644 --- a/crates/pop-cli/src/commands/up/parachain.rs +++ b/crates/pop-cli/src/commands/up/parachain.rs @@ -44,6 +44,9 @@ pub(crate) struct ZombienetCommand { /// Whether the output should be verbose. #[arg(short, long, action)] verbose: bool, + /// Automatically source all needed binaries required without prompting for confirmation. + #[clap(short('y'), long)] + skip_confirm: bool, } impl ZombienetCommand { @@ -83,7 +86,7 @@ impl ZombienetCommand { }; // Source any missing/stale binaries - if Self::source_binaries(&mut zombienet, &cache, self.verbose).await? { + if Self::source_binaries(&mut zombienet, &cache, self.verbose, self.skip_confirm).await? { return Ok(()); } @@ -159,6 +162,7 @@ impl ZombienetCommand { zombienet: &mut Zombienet, cache: &PathBuf, verbose: bool, + skip_confirm: bool, ) -> anyhow::Result { // Check for any missing or stale binaries let binaries: Vec<_> = zombienet.binaries().filter(|b| !b.exists() || b.stale()).collect(); @@ -197,15 +201,17 @@ impl ZombienetCommand { )) .dim() .to_string(); - if !confirm(format!( + if !skip_confirm { + if !confirm(format!( "📦 Would you like to source them automatically now? It may take some time...\n {list}")) - .initial_value(true) - .interact()? - { - outro_cancel( + .initial_value(true) + .interact()? + { + outro_cancel( "🚫 Cannot launch the specified network until all required binaries are available.", )?; - return Ok(true); + return Ok(true); + } } } @@ -235,13 +241,16 @@ impl ZombienetCommand { log::warning(format!( "ℹ️ The following binaries have newer versions available:\n {list}" ))?; - - latest = confirm( - "📦 Would you like to source them automatically now? It may take some time..." - .to_string(), - ) - .initial_value(true) - .interact()?; + if !skip_confirm { + latest = confirm( + "📦 Would you like to source them automatically now? It may take some time..." + .to_string(), + ) + .initial_value(true) + .interact()?; + } else { + latest = true; + } } let binaries: Vec<_> = binaries diff --git a/crates/pop-cli/tests/contract.rs b/crates/pop-cli/tests/contract.rs index bf263a34..1f7231ff 100644 --- a/crates/pop-cli/tests/contract.rs +++ b/crates/pop-cli/tests/contract.rs @@ -1,93 +1,156 @@ // SPDX-License-Identifier: GPL-3.0 -use anyhow::{Error, Result}; +use anyhow::Result; use assert_cmd::Command; -use predicates::prelude::*; +use pop_common::templates::Template; +use pop_contracts::{ + dry_run_gas_estimate_instantiate, instantiate_smart_contract, run_contracts_node, + set_up_deployment, Contract, UpOpts, +}; +use std::{path::Path, process::Command as Cmd}; +use strum::VariantArray; +use url::Url; -fn setup_test_environment() -> Result { - let temp_contract_dir = tempfile::tempdir().unwrap(); - // pop new contract test_contract +/// Test the contract lifecycle: new, build, up, call +#[tokio::test] +async fn contract_lifecycle() -> Result<()> { + let temp = tempfile::tempdir().unwrap(); + let temp_dir = temp.path(); + //let temp_dir = Path::new("./"); //For testing locally + // Test that all templates are generated correctly + generate_all_the_templates(&temp_dir)?; + // pop new contract test_contract (default) Command::cargo_bin("pop") .unwrap() - .current_dir(&temp_contract_dir) + .current_dir(&temp_dir) .args(&["new", "contract", "test_contract"]) .assert() .success(); + assert!(temp_dir.join("test_contract").exists()); - Ok(temp_contract_dir) -} - -#[test] -fn test_contract_build_success() -> Result<(), Error> { - let temp_contract_dir = setup_test_environment()?; - - // pop build contract + // pop build --path ./test_contract --release Command::cargo_bin("pop") .unwrap() - .current_dir(&temp_contract_dir.path().join("test_contract")) - .args(&["build", "contract"]) + .current_dir(&temp_dir) + .args(&["build", "--path", "./test_contract", "--release"]) .assert() .success(); - // Verify that the folder target has been created - assert!(temp_contract_dir.path().join("test_contract/target").exists()); + assert!(temp_dir.join("test_contract/target").exists()); // Verify that all the artifacts has been generated - assert!(temp_contract_dir - .path() - .join("test_contract/target/ink/test_contract.contract") - .exists()); - assert!(temp_contract_dir - .path() - .join("test_contract/target/ink/test_contract.wasm") - .exists()); - assert!(temp_contract_dir - .path() - .join("test_contract/target/ink/test_contract.json") - .exists()); - - Ok(()) -} + assert!(temp_dir.join("test_contract/target/ink/test_contract.contract").exists()); + assert!(temp_dir.join("test_contract/target/ink/test_contract.wasm").exists()); + assert!(temp_dir.join("test_contract/target/ink/test_contract.json").exists()); -#[test] -fn test_contract_build_specify_path() -> Result<(), Error> { - let temp_contract_dir = setup_test_environment()?; + // Run the contracts node + let cache = temp_dir.join("cache"); + let process = run_contracts_node(cache, None).await?; + // Only upload the contract + // pop up contract --upload-only + Command::cargo_bin("pop") + .unwrap() + .current_dir(&temp_dir.join("test_contract")) + .args(&["up", "contract", "--upload-only"]) + .assert() + .success(); + // Instantiate contract, only dry-run + Command::cargo_bin("pop") + .unwrap() + .current_dir(&temp_dir.join("test_contract")) + .args(&[ + "up", + "contract", + "--constructor", + "new", + "--args", + "false", + "--suri", + "//Alice", + "--dry-run", + ]) + .assert() + .success(); + // Using methods from the pop_contracts crate to instantiate it to get the Contract Address for the call + let instantiate_exec = set_up_deployment(UpOpts { + path: Some(temp_dir.join("test_contract")), + constructor: "new".to_string(), + args: ["false".to_string()].to_vec(), + value: "0".to_string(), + gas_limit: None, + proof_size: None, + salt: None, + url: Url::parse("ws://127.0.0.1:9944")?, + suri: "//Alice".to_string(), + }) + .await?; + let weight_limit = dry_run_gas_estimate_instantiate(&instantiate_exec).await?; + let contract_address = instantiate_smart_contract(instantiate_exec, weight_limit).await?; + // Call contract (only query) + // pop call contract --contract $INSTANTIATED_CONTRACT_ADDRESS --message get --suri //Alice + Command::cargo_bin("pop") + .unwrap() + .current_dir(&temp_dir.join("test_contract")) + .args(&[ + "call", + "contract", + "--contract", + &contract_address, + "--message", + "get", + "--suri", + "//Alice", + ]) + .assert() + .success(); - // pop build contract --path ./test_contract + // Call contract (execute extrinsic) + // pop call contract --contract $INSTANTIATED_CONTRACT_ADDRESS --message flip --suri //Alice -x Command::cargo_bin("pop") .unwrap() - .current_dir(&temp_contract_dir.path()) - .args(&["build", "contract", "--path", "./test_contract"]) + .current_dir(&temp_dir.join("test_contract")) + .args(&[ + "call", + "contract", + "--contract", + &contract_address, + "--message", + "flip", + "--suri", + "//Alice", + "-x", + ]) .assert() .success(); - // Verify that the folder target has been created - assert!(temp_contract_dir.path().join("test_contract/target").exists()); - // Verify that all the artifacts has been generated - assert!(temp_contract_dir - .path() - .join("test_contract/target/ink/test_contract.contract") - .exists()); - assert!(temp_contract_dir - .path() - .join("test_contract/target/ink/test_contract.wasm") - .exists()); - assert!(temp_contract_dir - .path() - .join("test_contract/target/ink/test_contract.json") - .exists()); + // Stop the process contracts-node + Cmd::new("kill") + .args(["-s", "TERM", &process.id().to_string()]) + .spawn()? + .wait()?; Ok(()) } -#[test] -fn test_contract_build_fails_if_no_contract_exists() -> Result<(), Error> { - // pop build contract - Command::cargo_bin("pop") - .unwrap() - .args(&["build", "contract"]) - .assert() - .failure() - .stderr(predicate::str::contains("Error: No 'ink' dependency found")); - +fn generate_all_the_templates(temp_dir: &Path) -> Result<()> { + for template in Contract::VARIANTS { + let contract_name = format!("test_contract_{}", template); + let contract_type = template.template_type()?.to_lowercase(); + // pop new parachain test_parachain + Command::cargo_bin("pop") + .unwrap() + .current_dir(&temp_dir) + .args(&[ + "new", + "contract", + &contract_name, + "--contract-type", + &contract_type, + "--template", + &template.to_string(), + ]) + .assert() + .success(); + assert!(temp_dir.join(contract_name).exists()); + } Ok(()) } diff --git a/crates/pop-cli/tests/parachain.rs b/crates/pop-cli/tests/parachain.rs index 8cfeef11..2d5ab2df 100644 --- a/crates/pop-cli/tests/parachain.rs +++ b/crates/pop-cli/tests/parachain.rs @@ -1,33 +1,96 @@ // SPDX-License-Identifier: GPL-3.0 -use anyhow::{Error, Result}; -use assert_cmd::Command; +use anyhow::Result; +use assert_cmd::{cargo::cargo_bin, Command}; +use pop_common::templates::Template; +use pop_parachains::Parachain; +use std::{fs, path::Path, process::Command as Cmd}; +use strum::VariantArray; +use tokio::time::{sleep, Duration}; -fn setup_test_environment() -> Result { - let temp_dir = tempfile::tempdir().unwrap(); - // pop new parachain test_parachain +/// Test the parachain lifecycle: new, build, up +#[tokio::test] +async fn parachain_lifecycle() -> Result<()> { + let temp = tempfile::tempdir().unwrap(); + let temp_dir = temp.path(); + // let temp_dir = Path::new("./"); //For testing locally + // Test that all templates are generated correctly + generate_all_the_templates(&temp_dir)?; + // pop new parachain test_parachain (default) Command::cargo_bin("pop") .unwrap() .current_dir(&temp_dir) - .args(&["new", "parachain", "test_parachain"]) + .args(&[ + "new", + "parachain", + "test_parachain", + "--symbol", + "POP", + "--decimals", + "6", + "--endowment", + "1u64 << 60", + ]) .assert() .success(); + assert!(temp_dir.join("test_parachain").exists()); - Ok(temp_dir) -} - -#[test] -fn test_parachain_build_after_instantiating_template() -> Result<()> { - let temp_dir = setup_test_environment()?; - - // pop build contract -p "./test_parachain" + // pop build --path "./test_parachain" Command::cargo_bin("pop") .unwrap() .current_dir(&temp_dir) - .args(&["build", "parachain", "--path", "./test_parachain"]) + .args(&["build", "--path", "./test_parachain", "--id", "2000"]) .assert() .success(); - assert!(temp_dir.path().join("test_parachain/target").exists()); + assert!(temp_dir.join("test_parachain/target").exists()); + // Assert build files has been generated + assert!(temp_dir.join("test_parachain/raw-parachain-chainspec.json").exists()); + assert!(temp_dir.join("test_parachain/para-2000-wasm.wasm").exists()); + assert!(temp_dir.join("test_parachain/para-2000-genesis-state").exists()); + + let content = fs::read_to_string(temp_dir.join("test_parachain/raw-parachain-chainspec.json")) + .expect("Could not read file"); + // Assert custom values has been set propertly + assert!(content.contains("\"para_id\": 2000")); + assert!(content.contains("\"tokenDecimals\": 6")); + assert!(content.contains("\"tokenSymbol\": \"POP\"")); + + // pop up contract -p "./test_parachain" + let mut cmd = Cmd::new(cargo_bin("pop")) + .current_dir(&temp_dir.join("test_parachain")) + .args(&["up", "parachain", "-f", "./network.toml", "--skip-confirm"]) + .spawn() + .unwrap(); + // If after 20 secs is still running probably execution is ok, or waiting for user response + sleep(Duration::from_secs(20)).await; + + assert!(cmd.try_wait().unwrap().is_none(), "the process should still be running"); + // Stop the process + Cmd::new("kill").args(["-s", "TERM", &cmd.id().to_string()]).spawn()?; + + Ok(()) +} + +fn generate_all_the_templates(temp_dir: &Path) -> Result<()> { + for template in Parachain::VARIANTS { + let parachain_name = format!("test_parachain_{}", template); + let provider = template.template_type()?.to_lowercase(); + // pop new parachain test_parachain + Command::cargo_bin("pop") + .unwrap() + .current_dir(&temp_dir) + .args(&[ + "new", + "parachain", + ¶chain_name, + &provider, + "--template", + &template.to_string(), + ]) + .assert() + .success(); + assert!(temp_dir.join(parachain_name).exists()); + } Ok(()) } diff --git a/crates/pop-contracts/Cargo.toml b/crates/pop-contracts/Cargo.toml index b4c4894d..91f85dfc 100644 --- a/crates/pop-contracts/Cargo.toml +++ b/crates/pop-contracts/Cargo.toml @@ -39,4 +39,4 @@ pop-common = { path = "../pop-common", version = "0.2.0" } [dev-dependencies] mockito.workspace = true - +tokio-test.workspace = true diff --git a/crates/pop-contracts/README.md b/crates/pop-contracts/README.md index 5800df0f..17870a5d 100644 --- a/crates/pop-contracts/README.md +++ b/crates/pop-contracts/README.md @@ -5,122 +5,144 @@ A crate for generating, building, deploying, and calling [`ink!`](https://github ## Usage Generate a new Smart Contract: -```rust -use pop_contracts::{create_smart_contract, Template}; +```rust,no_run +use pop_contracts::{create_smart_contract, Contract}; +use std::path::Path; -let template = Template::Standard; - -let name = '...'; -let contract_path = ...; -create_smart_contract(name, &contract_path, &template)?; +let contract_path = Path::new("./"); +create_smart_contract("my_contract", &contract_path, &Contract::Standard); ``` Build an existing Smart Contract: -```rust +```rust,no_run use pop_contracts::build_smart_contract; +use std::path::Path; +pub use contract_build::Verbosity; -let contract_path = ...; +let contract_path = Path::new("./"); let build_release = true; // `true` for release mode, `false` for debug mode. -build_smart_contract(&contract_path, build_release)?; +let result = build_smart_contract(Some(&contract_path), build_release, Verbosity::Default); ``` Test an existing Smart Contract: -```rust +```rust,no_run use pop_contracts::{test_e2e_smart_contract, test_smart_contract}; +use std::path::Path; -let contract_path = ...; -let contracts_node_path = ...; +let contract_path = Path::new("./"); +let contracts_node_path = Path::new("./path-to-contracts-node-binary"); //unit testing -test_smart_contract(&contract_path)?; +test_smart_contract(Some(contract_path)); //e2e testing -test_e2e_smart_contract(&contract_path, contracts_node_path)?; +test_e2e_smart_contract(Some(contract_path), Some(contracts_node_path)); ``` Deploy and instantiate an existing Smart Contract: -```rust -use pop_contracts::{ instantiate_smart_contract, set_up_deployment, UpOpts}; - -// prepare extrinsic for deployment -let up_opts = UpOpts {..} -let instantiate_exec = set_up_deployment(up_opts); - - -let contract_address = instantiate_smart_contract(instantiate_exec, Weight::from_parts(gas_limit, proof_size)) - .await - .map_err(|err| anyhow!("{} {}", "ERROR:", format!("{err:?}")))?; -``` - -If you don't know the `gas_limit` and `proof_size`, you can perform a dry run to estimate the gas amount before instatianting the Smart Contract: -```rust -use pop_contracts::{ instantiate_smart_contract, dry_run_gas_estimate_instantiate}; - -let weight_limit = match dry_run_gas_estimate_instantiate(&instantiate_exec).await?; -let contract_address = instantiate_smart_contract(instantiate_exec, weight_limit) - .await - .map_err(|err| anyhow!("{} {}", "ERROR:", format!("{err:?}")))?; +```rust,no_run +use pop_contracts::{ dry_run_gas_estimate_instantiate, instantiate_smart_contract, set_up_deployment, UpOpts}; +use std::path::PathBuf; +use tokio_test; +use url::Url; + +tokio_test::block_on(async { + let contract_path = PathBuf::from("./"); + // prepare extrinsic for deployment + let up_opts = UpOpts { + path: Some(contract_path), + constructor: "new".to_string(), + args: ["false".to_string()].to_vec(), + value: "1000".to_string(), + gas_limit: None, + proof_size: None, + url: Url::parse("ws://localhost:9944").unwrap(), + suri: "//Alice".to_string(), + salt: None, + }; + let instantiate_exec = set_up_deployment(up_opts).await.unwrap(); + + // If you don't know the `gas_limit` and `proof_size`, you can perform a dry run to estimate the gas amount before instatianting the Smart Contract. + let weight = dry_run_gas_estimate_instantiate(&instantiate_exec).await.unwrap(); + + let contract_address = instantiate_smart_contract(instantiate_exec, weight).await.unwrap(); +}); ``` Upload a Smart Contract only: -```rust -use pop_contracts::{ upload_smart_contract, set_up_upload, UpOpts}; - -// prepare extrinsic for deployment -let up_opts = UpOpts {..} -let upload_exec = set_up_upload(up_opts); - -// to perform only a dry-run -let hash_code = dry_run_upload(&upload_exec)?; - -// to upload the smart contract -let contract_address = upload_smart_contract(&upload_exec) - .await - .map_err(|err| anyhow!("{} {}", "ERROR:", format!("{err:?}")))?; +```rust,no_run +use pop_contracts::{ dry_run_upload, set_up_upload, upload_smart_contract, UpOpts}; +use std::path::PathBuf; +use tokio_test; +use url::Url; + +tokio_test::block_on(async { + // prepare extrinsic for deployment + let contract_path = PathBuf::from("./"); + let up_opts = UpOpts { + path: Some(contract_path), + constructor: "new".to_string(), + args: ["false".to_string()].to_vec(), + value: "1000".to_string(), + gas_limit: None, + proof_size: None, + url: Url::parse("ws://localhost:9944").unwrap(), + suri: "//Alice".to_string(), + salt: None, + }; + let upload_exec = set_up_upload(up_opts).await.unwrap(); + // to perform only a dry-run + let hash_code = dry_run_upload(&upload_exec).await.unwrap(); + // to upload the smart contract + let code_hash = upload_smart_contract(&upload_exec).await.unwrap(); +}); ``` Call a deployed (and instantiated) Smart Contract: -```rust -use pop_contracts::{set_up_call, CallOpts}; - -// prepare extrinsic for call -let call_opts = CallOpts { - path: ..., - contract: ..., - message: ..., - args: ..., - value: ..., - gas_limit: ..., - proof_size: ..., - url: ..., - suri: ..., - execute: ..., -} -let call_exec = set_up_call(call_opts).await?; -``` -For operations that only require reading from the blockchain state, it does not require to submit an extrinsic: -```rust -use pop_contracts::dry_run_call; - -let call_dry_run_result = dry_run_call(&call_exec).await?; -``` -For operations that change a storage value, thus altering the blockchain state, requires to submit an extrinsic: -```rust -use pop_contracts::call_smart_contract; - -let url = ....; -let call_result = call_smart_contract(call_exec, Weight::from_parts(gas_limit, proof_size), url) - .await - .map_err(|err| anyhow!("{} {}", "ERROR:", format!("{err:?}")))?; -``` -Same as above, if you don't know the `gas_limit` and `proof_size`, you can perform a dry run to estimate the gas amount before calling the Smart Contract: -```rust -use pop_contracts::{ call_smart_contract, dry_run_gas_estimate_call}; - -let url = ....; -let weight_limit = match dry_run_gas_estimate_call(&call_exec).await?; -let contract_address = call_smart_contract(call_exec, weight_limit, url) - .await - .map_err(|err| anyhow!("{} {}", "ERROR:", format!("{err:?}")))?; +```rust,no_run +use pop_contracts::{call_smart_contract, dry_run_call, dry_run_gas_estimate_call, set_up_call,CallOpts}; +use std::path::PathBuf; +use tokio_test; +use url::Url; + +tokio_test::block_on(async { + // prepare extrinsic for call + let contract_path = PathBuf::from("./"); + let get_call_opts = CallOpts { + path: Some(contract_path.clone()), + contract: "5CLPm1CeUvJhZ8GCDZCR7nWZ2m3XXe4X5MtAQK69zEjut36A".to_string(), + message: "get".to_string(), + args: [].to_vec(), + value: "1000".to_string(), + gas_limit: None, + proof_size: None, + url: Url::parse("ws://localhost:9944").unwrap(), + suri: "//Alice".to_string(), + execute: false + }; + let get_call_exec = set_up_call(get_call_opts).await.unwrap(); + // For operations that only require reading from the blockchain state, it does not require to submit an extrinsic. + let call_dry_run_result = dry_run_call(&get_call_exec).await.unwrap(); + + // For operations that change a storage value, thus altering the blockchain state, requires to submit an extrinsic. + let flip_call_opts = CallOpts { + path: Some(contract_path), + contract: "5CLPm1CeUvJhZ8GCDZCR7nWZ2m3XXe4X5MtAQK69zEjut36A".to_string(), + message: "flip".to_string(), + args: [].to_vec(), + value: "1000".to_string(), + gas_limit: None, + proof_size: None, + url: Url::parse("ws://localhost:9944").unwrap(), + suri: "//Alice".to_string(), + execute: true + }; + let flip_call_exec = set_up_call(flip_call_opts).await.unwrap(); + let url = Url::parse("ws://localhost:9944").unwrap(); + // If you don't know the `gas_limit` and `proof_size`, you can perform a dry run to estimate the gas amount before calling the Smart Contract. + let weight_limit = dry_run_gas_estimate_call(&flip_call_exec).await.unwrap(); + // Use this weight to execute the call. + let call_result = call_smart_contract(flip_call_exec, weight_limit, &url).await.unwrap(); +}); ``` ## Acknowledgements diff --git a/crates/pop-contracts/src/call.rs b/crates/pop-contracts/src/call.rs index c9f96974..4a9f566a 100644 --- a/crates/pop-contracts/src/call.rs +++ b/crates/pop-contracts/src/call.rs @@ -143,10 +143,13 @@ pub async fn call_smart_contract( call_exec: CallExec, gas_limit: Weight, url: &Url, -) -> anyhow::Result { +) -> anyhow::Result { let token_metadata = TokenMetadata::query::(url).await?; let metadata = call_exec.client().metadata(); - let events = call_exec.call(Some(gas_limit)).await?; + let events = call_exec + .call(Some(gas_limit)) + .await + .map_err(|error_variant| Error::CallContractError(format!("{:?}", error_variant)))?; let display_events = DisplayEvents::from_events::(&events, None, &metadata)?; @@ -158,11 +161,15 @@ pub async fn call_smart_contract( #[cfg(test)] mod tests { use super::*; - use crate::{create_smart_contract, errors::Error, templates::Contract}; + use crate::{ + create_smart_contract, dry_run_gas_estimate_instantiate, errors::Error, + instantiate_smart_contract, run_contracts_node, set_up_deployment, Contract, UpOpts, + }; use anyhow::Result; - use std::{env, fs}; + use sp_core::Bytes; + use std::{env, fs, process::Command}; - const CONTRACTS_NETWORK_URL: &str = "wss://rococo-contracts-rpc.polkadot.io"; + const CONTRACTS_NETWORK_URL: &str = "wss://rpc2.paseo.popnetwork.xyz"; fn generate_smart_contract_test_environment() -> Result { let temp_dir = tempfile::tempdir().expect("Could not create temp dir"); @@ -296,4 +303,72 @@ mod tests { )); Ok(()) } + + #[tokio::test] + async fn call_works() -> Result<()> { + const LOCALHOST_URL: &str = "ws://127.0.0.1:9944"; + let temp_dir = generate_smart_contract_test_environment()?; + mock_build_process(temp_dir.path().join("testing"))?; + // Run the contracts-node. + let cache = temp_dir.path().join("cache"); + let process = run_contracts_node(cache, None).await?; + // Instantiate a Smart Contract. + let instantiate_exec = set_up_deployment(UpOpts { + path: Some(temp_dir.path().join("testing")), + constructor: "new".to_string(), + args: ["false".to_string()].to_vec(), + value: "0".to_string(), + gas_limit: None, + proof_size: None, + salt: Some(Bytes::from(vec![0x00])), + url: Url::parse(LOCALHOST_URL)?, + suri: "//Alice".to_string(), + }) + .await?; + let weight = dry_run_gas_estimate_instantiate(&instantiate_exec).await?; + let address = instantiate_smart_contract(instantiate_exec, weight).await?; + // Test querying a value. + let query_exec = set_up_call(CallOpts { + path: Some(temp_dir.path().join("testing")), + contract: address.clone(), + message: "get".to_string(), + args: [].to_vec(), + value: "0".to_string(), + gas_limit: None, + proof_size: None, + url: Url::parse(LOCALHOST_URL)?, + suri: "//Alice".to_string(), + execute: false, + }) + .await?; + let mut query = dry_run_call(&query_exec).await?; + assert_eq!(query, "Ok(false)"); + // Test extrinsic execution by flipping the value. + let call_exec = set_up_call(CallOpts { + path: Some(temp_dir.path().join("testing")), + contract: address, + message: "flip".to_string(), + args: [].to_vec(), + value: "0".to_string(), + gas_limit: None, + proof_size: None, + url: Url::parse(LOCALHOST_URL)?, + suri: "//Alice".to_string(), + execute: false, + }) + .await?; + let weight = dry_run_gas_estimate_call(&call_exec).await?; + assert!(weight.ref_time() > 0); + assert!(weight.proof_size() > 0); + call_smart_contract(call_exec, weight, &Url::parse(LOCALHOST_URL)?).await?; + // Assert that the value has been flipped. + query = dry_run_call(&query_exec).await?; + assert_eq!(query, "Ok(true)"); + // Stop the process contracts-node + Command::new("kill") + .args(["-s", "TERM", &process.id().to_string()]) + .spawn()? + .wait()?; + Ok(()) + } } diff --git a/crates/pop-contracts/src/errors.rs b/crates/pop-contracts/src/errors.rs index 2736386f..137e0f4c 100644 --- a/crates/pop-contracts/src/errors.rs +++ b/crates/pop-contracts/src/errors.rs @@ -11,6 +11,8 @@ pub enum Error { #[error("Failed to parse balance: {0}")] BalanceParsing(String), #[error("{0}")] + CallContractError(String), + #[error("{0}")] CommonError(#[from] pop_common::Error), #[error("Pre-submission dry-run failed: {0}")] DryRunUploadContractError(String), diff --git a/crates/pop-contracts/src/up.rs b/crates/pop-contracts/src/up.rs index 1478dea2..ac7f7f48 100644 --- a/crates/pop-contracts/src/up.rs +++ b/crates/pop-contracts/src/up.rs @@ -201,10 +201,10 @@ mod tests { use super::*; use crate::{create_smart_contract, errors::Error, run_contracts_node, templates::Contract}; use anyhow::Result; - use std::{env, fs}; + use std::{env, fs, process::Command}; use url::Url; - const CONTRACTS_NETWORK_URL: &str = "wss://rococo-contracts-rpc.polkadot.io"; + const CONTRACTS_NETWORK_URL: &str = "wss://rpc2.paseo.popnetwork.xyz"; fn generate_smart_contract_test_environment() -> Result { let temp_dir = tempfile::tempdir().expect("Could not create temp dir"); @@ -337,7 +337,7 @@ mod tests { mock_build_process(temp_dir.path().join("testing"))?; // Run contracts-node let cache = temp_dir.path().join("cache"); - let mut process = run_contracts_node(cache, None).await?; + let process = run_contracts_node(cache, None).await?; let upload_exec = set_up_upload(UpOpts { path: Some(temp_dir.path().join("testing")), @@ -381,7 +381,11 @@ mod tests { // Instantiate smart contract let address = instantiate_smart_contract(instantiate_exec, weight).await?; assert!(address.starts_with("5")); - process.kill()?; + // Stop the process contracts-node + Command::new("kill") + .args(["-s", "TERM", &process.id().to_string()]) + .spawn()? + .wait()?; Ok(()) } } diff --git a/crates/pop-contracts/src/utils/contracts_node.rs b/crates/pop-contracts/src/utils/contracts_node.rs index 3b8d4982..5b83b421 100644 --- a/crates/pop-contracts/src/utils/contracts_node.rs +++ b/crates/pop-contracts/src/utils/contracts_node.rs @@ -118,6 +118,7 @@ fn release_folder_by_target() -> Result<&'static str, Error> { mod tests { use super::*; use anyhow::{Error, Result}; + use std::process::Command; #[tokio::test] async fn test_latest_polkadot_release() -> Result<()> { @@ -153,7 +154,7 @@ mod tests { #[tokio::test] async fn is_chain_alive_works() -> Result<(), Error> { - let local_url = url::Url::parse("ws://localhost:9944")?; + let local_url = url::Url::parse("ws://wrong")?; assert!(!is_chain_alive(local_url).await?); let polkadot_url = url::Url::parse("wss://polkadot-rpc.dwellir.com")?; assert!(is_chain_alive(polkadot_url).await?); @@ -163,16 +164,19 @@ mod tests { #[tokio::test] async fn run_contracts_node_works() -> Result<(), Error> { let local_url = url::Url::parse("ws://localhost:9944")?; - assert!(!is_chain_alive(local_url.clone()).await?); // Run the contracts node let temp_dir = tempfile::tempdir().expect("Could not create temp dir"); let cache = temp_dir.path().join("cache"); - let mut process = run_contracts_node(cache.clone(), None).await?; + let process = run_contracts_node(cache.clone(), None).await?; // Check if the node is alive assert!(is_chain_alive(local_url).await?); assert!(cache.join("substrate-contracts-node").exists()); assert!(!cache.join("artifacts").exists()); - process.kill()?; + // Stop the process contracts-node + Command::new("kill") + .args(["-s", "TERM", &process.id().to_string()]) + .spawn()? + .wait()?; Ok(()) } } diff --git a/crates/pop-contracts/src/utils/helpers.rs b/crates/pop-contracts/src/utils/helpers.rs index 775b8655..ca94aa34 100644 --- a/crates/pop-contracts/src/utils/helpers.rs +++ b/crates/pop-contracts/src/utils/helpers.rs @@ -81,4 +81,33 @@ mod tests { canonicalized_path(temp_dir.path())?; Ok(()) } + + #[test] + fn parse_balance_works() -> Result<(), Error> { + let balance = parse_balance("100000")?; + assert_eq!(balance, BalanceVariant::Default(100000)); + Ok(()) + } + + #[test] + fn parse_balance_fails_wrong_balance() -> Result<(), Error> { + assert!(matches!(parse_balance("wrongbalance"), Err(super::Error::BalanceParsing(..)))); + Ok(()) + } + + #[test] + fn parse_account_works() -> Result<(), Error> { + let account = parse_account("5CLPm1CeUvJhZ8GCDZCR7nWZ2m3XXe4X5MtAQK69zEjut36A")?; + assert_eq!(account.to_string(), "5CLPm1CeUvJhZ8GCDZCR7nWZ2m3XXe4X5MtAQK69zEjut36A"); + Ok(()) + } + + #[test] + fn parse_account_fails_wrong_value() -> Result<(), Error> { + assert!(matches!( + parse_account("wrongaccount"), + Err(super::Error::AccountAddressParsing(..)) + )); + Ok(()) + } } diff --git a/crates/pop-contracts/src/utils/signer.rs b/crates/pop-contracts/src/utils/signer.rs index 62e6d16b..51fc44b0 100644 --- a/crates/pop-contracts/src/utils/signer.rs +++ b/crates/pop-contracts/src/utils/signer.rs @@ -18,3 +18,39 @@ pub fn parse_hex_bytes(input: &str) -> Result { let bytes = decode_hex(input).map_err(|e| Error::HexParsing(format!("{}", e)))?; Ok(bytes.into()) } + +#[cfg(test)] +mod tests { + use super::*; + use anyhow::Result; + + #[test] + fn create_signer_works() -> Result<(), Error> { + let keypair = create_signer("//Alice")?; + assert_eq!( + keypair.public_key().to_account_id().to_string(), + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" //Alice account + ); + Ok(()) + } + + #[test] + fn create_signer_fails_wrong_key() -> Result<(), Error> { + assert!(matches!(create_signer("11111"), Err(Error::KeyPairCreation(..)))); + Ok(()) + } + + #[test] + fn parse_hex_bytes_works() -> Result<(), Error> { + let input_in_hex = "48656c6c6f"; + let result = parse_hex_bytes(input_in_hex)?; + assert_eq!(result, Bytes(vec![72, 101, 108, 108, 111])); + Ok(()) + } + + #[test] + fn parse_hex_bytes_fails_wrong_input() -> Result<(), Error> { + assert!(matches!(parse_hex_bytes("wronghexvalue"), Err(Error::HexParsing(..)))); + Ok(()) + } +} diff --git a/crates/pop-contracts/tests/contract.rs b/crates/pop-contracts/tests/contract.rs deleted file mode 100644 index a4919240..00000000 --- a/crates/pop-contracts/tests/contract.rs +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use anyhow::{Error, Result}; -use contract_build::{BuildMode, Verbosity}; -use pop_contracts::{ - build_smart_contract, create_smart_contract, dry_run_gas_estimate_instantiate, - set_up_deployment, Contract, UpOpts, -}; -use std::fs; -use tempfile::TempDir; -use url::Url; - -fn setup_test_environment() -> std::result::Result { - let temp_dir = tempfile::tempdir().expect("Could not create temp dir"); - let temp_contract_dir = temp_dir.path().join("test_contract"); - fs::create_dir(&temp_contract_dir)?; - create_smart_contract("test_contract", temp_contract_dir.as_path(), &Contract::Standard)?; - Ok(temp_dir) -} - -fn verify_build_files(temp_contract_dir: TempDir) -> Result<()> { - // Verify that the folder target has been created - assert!(temp_contract_dir.path().join("test_contract/target").exists()); - // Verify that all the artifacts has been generated - assert!(temp_contract_dir - .path() - .join("test_contract/target/ink/test_contract.contract") - .exists()); - assert!(temp_contract_dir - .path() - .join("test_contract/target/ink/test_contract.wasm") - .exists()); - assert!(temp_contract_dir - .path() - .join("test_contract/target/ink/test_contract.json") - .exists()); - Ok(()) -} - -#[test] -fn test_contract_build() -> std::result::Result<(), Error> { - // Test building in release mode - let temp_contract_dir = setup_test_environment()?; - - let build_result = build_smart_contract( - Some(&temp_contract_dir.path().join("test_contract")), - true, - Verbosity::Default, - )?; - assert_eq!(build_result.build_mode, BuildMode::Release); - - verify_build_files(temp_contract_dir)?; - - let temp_debug_contract_dir = setup_test_environment()?; - // Test building in debug mode - let build_result = build_smart_contract( - Some(&temp_debug_contract_dir.path().join("test_contract")), - false, - Verbosity::Default, - )?; - assert_eq!(build_result.build_mode, BuildMode::Debug); - - verify_build_files(temp_debug_contract_dir)?; - - Ok(()) -} - -const CONTRACTS_NETWORK_URL: &str = "wss://rococo-contracts-rpc.polkadot.io"; - -fn build_smart_contract_test_environment(temp_dir: &TempDir) -> Result<(), Error> { - build_smart_contract(Some(&temp_dir.path().join("test_contract")), true, Verbosity::Default)?; - Ok(()) -} - -#[tokio::test] -async fn test_set_up_deployment() -> std::result::Result<(), Error> { - let temp_dir = setup_test_environment()?; - build_smart_contract_test_environment(&temp_dir)?; - - let call_opts = UpOpts { - path: Some(temp_dir.path().join("test_contract")), - constructor: "new".to_string(), - args: ["false".to_string()].to_vec(), - value: "1000".to_string(), - gas_limit: None, - proof_size: None, - url: Url::parse(CONTRACTS_NETWORK_URL)?, - suri: "//Alice".to_string(), - salt: None, - }; - let result = set_up_deployment(call_opts).await?; - assert_eq!(result.opts().url(), "wss://rococo-contracts-rpc.polkadot.io:443/"); - Ok(()) -} - -#[tokio::test] -async fn test_dry_run_gas_estimate_instantiate() -> std::result::Result<(), Error> { - let temp_dir = setup_test_environment()?; - build_smart_contract_test_environment(&temp_dir)?; - - let call_opts = UpOpts { - path: Some(temp_dir.path().join("test_contract")), - constructor: "new".to_string(), - args: ["false".to_string()].to_vec(), - value: "0".to_string(), - gas_limit: None, - proof_size: None, - url: Url::parse(CONTRACTS_NETWORK_URL)?, - suri: "//Alice".to_string(), - salt: None, - }; - let instantiate_exec = set_up_deployment(call_opts).await; - - let weight = dry_run_gas_estimate_instantiate(&instantiate_exec.unwrap()).await?; - assert!(weight.clone().ref_time() > 0); - assert!(weight.proof_size() > 0); - - Ok(()) -} diff --git a/crates/pop-contracts/tests/files/testing.contract b/crates/pop-contracts/tests/files/testing.contract index 77006686..8701e656 100644 --- a/crates/pop-contracts/tests/files/testing.contract +++ b/crates/pop-contracts/tests/files/testing.contract @@ -1 +1 @@ -{"source":{"hash":"0xca7b0d5a7425ba48720ad9314e9fac4aaf141d0edd54ca257c12f0e706b24f4c","language":"ink! 5.0.0","compiler":"rustc 1.78.0","wasm":"0x0061736d01000000012b0860027f7f0060037f7f7f017f60000060047f7f7f7f017f60037f7f7f0060017f006000017f60017f017f027406057365616c310b6765745f73746f726167650003057365616c3005696e7075740000057365616c320b7365745f73746f726167650003057365616c300b7365616c5f72657475726e0004057365616c301176616c75655f7472616e73666572726564000003656e76066d656d6f72790201021003100f0101010105040006070002050002020616037f01418080040b7f00418080050b7f00418080050b0711020463616c6c0012066465706c6f7900130aab0b0f2b01017f037f2002200346047f200005200020036a200120036a2d00003a0000200341016a21030c010b0b0b6f01017f0240200020014d04402000210303402002450d02200320012d00003a0000200341016a2103200141016a2101200241016b21020c000b000b200041016b2103200141016b210103402002450d01200220036a200120026a2d00003a0000200241016b21020c000b000b20000b2501017f037f2002200346047f200005200020036a20013a0000200341016a21030c010b0b0b3f01027f0340200245044041000f0b200241016b210220012d0000210320002d00002104200141016a2101200041016a210020032004460d000b200420036b0b2601017f230041106b220124002001410036020c20002001410c6a4104100a200141106a24000b4801027f024002402000280208220320026a22042003490d00200420002802044b0d00200420036b2002470d01200028020020036a2001200210051a200020043602080f0b000b000b2601017f230041106b22022400200220003a000f20012002410f6a4101100a200241106a24000b6102027f027e230041206b22002400200041106a22014200370300200042003703082000411036021c200041086a2000411c6a1004200028021c41114f0440000b2001290300210220002903082103200041206a2400410541042002200384501b0b3f01017f2000280204220145044041020f0b2000200141016b36020420002000280200220041016a3602004101410220002d000022004101461b410020001b0b3c01027f027f200145044041808004210141010c010b410121024180800441013a000041818004210141020b2103200120023a0000200020031011000b12004180800441003b0100410041021011000b8a0101057f230041106b22012400200142808001370208200141808004360204200141046a22041009024020012802082205200128020c2202490d00200128020421032001410036020c2001200520026b3602082001200220036a36020420002004100b200128020c220020012802084b0d00200320022001280204200010021a200141106a24000f0b000b0d0020004180800420011003000b990301067f230041106b22002400024002400240100c41ff01714105470d0020004180800136020441808004200041046a100120002802042201418180014f0d0020014104490d02418380042d00002101418280042d00002103418180042d000021020240418080042d00002204412f470440200441e300470d04410121052002413a47200341a5014772200141d1004772450d010c040b200241860147200341db004772200141d90147720d030b200042808001370208200041808004360204200041046a2203100920002802082204200028020c2201490d00200028020421022000200420016b220436020420022001200120026a2201200310002000280204220220044b720d0020002002360208200020013602042003100d220141ff01714102460d0020002802080d0020050d01230041106b220024002000418080043602044180800441003a00002000428080818010370208200141ff0171410047200041046a100b200028020c2200418180014f0440000b410020001011000b000b200141ff017145101041004100100e000b41014101100e000be80101057f230041106b2200240002400240100c41ff01714105470d0020004180800136020c418080042000410c6a1001200028020c2201418180014f0d0020014104490d012000418480043602042000200141046b360208418380042d00002101418280042d00002102418180042d000021030240418080042d0000220441ed014704402004419b0147200341ae0147722002419d0147200141de004772720d03200041046a100d220041ff01714102470d010c030b200341cb00462002419d0146712001411b4671450d0241011010100f000b20004101731010100f000b000b41014101100e000b","build_info":{"build_mode":"Release","cargo_contract_version":"4.1.1","rust_toolchain":"stable-aarch64-apple-darwin","wasm_opt_settings":{"keep_debug_symbols":false,"optimization_passes":"Z"}}},"contract":{"name":"testing","version":"0.1.0","authors":["[your_name] <[your_email]>"]},"image":null,"spec":{"constructors":[{"args":[{"label":"init_value","type":{"displayName":["bool"],"type":0}}],"default":false,"docs":["Constructor that initializes the `bool` value to the given `init_value`."],"label":"new","payable":false,"returnType":{"displayName":["ink_primitives","ConstructorResult"],"type":2},"selector":"0x9bae9d5e"},{"args":[],"default":false,"docs":["Constructor that initializes the `bool` value to `false`.","","Constructors can delegate to other constructors."],"label":"default","payable":false,"returnType":{"displayName":["ink_primitives","ConstructorResult"],"type":2},"selector":"0xed4b9d1b"}],"docs":[],"environment":{"accountId":{"displayName":["AccountId"],"type":6},"balance":{"displayName":["Balance"],"type":9},"blockNumber":{"displayName":["BlockNumber"],"type":12},"chainExtension":{"displayName":["ChainExtension"],"type":13},"hash":{"displayName":["Hash"],"type":10},"maxEventTopics":4,"staticBufferSize":16384,"timestamp":{"displayName":["Timestamp"],"type":11}},"events":[],"lang_error":{"displayName":["ink","LangError"],"type":4},"messages":[{"args":[],"default":false,"docs":[" A message that can be called on instantiated contracts."," This one flips the value of the stored `bool` from `true`"," to `false` and vice versa."],"label":"flip","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":2},"selector":"0x633aa551"},{"args":[],"default":false,"docs":[" Simply returns the current value of our `bool`."],"label":"get","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":5},"selector":"0x2f865bd9"}]},"storage":{"root":{"layout":{"struct":{"fields":[{"layout":{"leaf":{"key":"0x00000000","ty":0}},"name":"value"}],"name":"Testing2"}},"root_key":"0x00000000","ty":1}},"types":[{"id":0,"type":{"def":{"primitive":"bool"}}},{"id":1,"type":{"def":{"composite":{"fields":[{"name":"value","type":0,"typeName":",>>::Type"}]}},"path":["testing","testing","Testing2"]}},{"id":2,"type":{"def":{"variant":{"variants":[{"fields":[{"type":3}],"index":0,"name":"Ok"},{"fields":[{"type":4}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":3},{"name":"E","type":4}],"path":["Result"]}},{"id":3,"type":{"def":{"tuple":[]}}},{"id":4,"type":{"def":{"variant":{"variants":[{"index":1,"name":"CouldNotReadInput"}]}},"path":["ink_primitives","LangError"]}},{"id":5,"type":{"def":{"variant":{"variants":[{"fields":[{"type":0}],"index":0,"name":"Ok"},{"fields":[{"type":4}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":0},{"name":"E","type":4}],"path":["Result"]}},{"id":6,"type":{"def":{"composite":{"fields":[{"type":7,"typeName":"[u8; 32]"}]}},"path":["ink_primitives","types","AccountId"]}},{"id":7,"type":{"def":{"array":{"len":32,"type":8}}}},{"id":8,"type":{"def":{"primitive":"u8"}}},{"id":9,"type":{"def":{"primitive":"u128"}}},{"id":10,"type":{"def":{"composite":{"fields":[{"type":7,"typeName":"[u8; 32]"}]}},"path":["ink_primitives","types","Hash"]}},{"id":11,"type":{"def":{"primitive":"u64"}}},{"id":12,"type":{"def":{"primitive":"u32"}}},{"id":13,"type":{"def":{"variant":{}},"path":["ink_env","types","NoChainExtension"]}}],"version":5} \ No newline at end of file +{"source":{"hash":"0xb15348075722f8ac92352b8fcfd6fa3506e2a3f430adadcc79fa73cf23bfe9e7","language":"ink! 5.0.0","compiler":"rustc 1.78.0","wasm":"0x0061736d0100000001400b60037f7f7f017f60027f7f017f60027f7f0060037f7f7f0060017f0060047f7f7f7f017f60047f7f7f7f0060000060057f7f7f7f7f006000017f60017f017f028a0107057365616c310b6765745f73746f726167650005057365616c3005696e7075740002057365616c320b7365745f73746f726167650005057365616c300d64656275675f6d6573736167650001057365616c300b7365616c5f72657475726e0003057365616c301176616c75655f7472616e73666572726564000203656e76066d656d6f7279020102100335340000000006030403020901020a00010702040302020704070306020301010004000101010104020101080506050802010103000104050170010e0e0616037f01418080040b7f0041c092050b7f0041ba92050b0711020463616c6c001b066465706c6f79001d0913010041010b0d103528392a362529252627232c0ae63b342b01017f037f2002200346047f200005200020036a200120036a2d00003a0000200341016a21030c010b0b0b6f01017f0240200020014d04402000210303402002450d02200320012d00003a0000200341016a2103200141016a2101200241016b21020c000b000b200041016b2103200141016b210103402002450d01200220036a200120026a2d00003a0000200241016b21020c000b000b20000b2501017f037f2002200346047f200005200020036a20013a0000200341016a21030c010b0b0b3f01027f0340200245044041000f0b200241016b210220012d0000210320002d00002104200141016a2101200041016a210020032004460d000b200420036b0b2300200120034b04402001200341f49004100b000b20002001360204200020023602000b6801017f230041306b2203240020032001360204200320003602002003412c6a41033602002003410236020c200341a88a0436020820034202370214200341033602242003200341206a3602102003200341046a36022820032003360220200341086a20021011000b2601017f230041106b220124002001410036020c20002001410c6a4104100d200141106a24000b920101037f02402000280208220420026a220320044f04402003200028020422054b0d01200028020020046a200320046b2001200241d08f041033200020033602080f0b230041206b22002400200041013602042000420037020c200041988e043602082000412b36021c200041f286043602182000200041186a360200200041b08f041011000b2003200541c08f04100b000b2601017f230041106b22022400200220003a000f20012002410f6a4101100d200241106a24000b6d02037f027e230041206b22002400200041106a22014200370300200042003703082000411036021c200041086a2000411c6a1005200028021c220241114f04402002411041f49004100b000b2001290300210320002903082104200041206a2400410541042003200484501b0b810101017f230041306b220224002002410136020c200241988d043602082002420137021420024102360224200220002d00004102742200418092046a28020036022c20022000419492046a2802003602282002200241206a3602102002200241286a36022020012802142001280218200241086a10242100200241306a240020000b3c01017f230041206b22022400200241013b011c2002200136021820022000360214200241b88704360210200241988e0436020c2002410c6a102b000b4901017f230041106b22012400200141003a000f027f20002001410f6a410110134504404101410220012d000f22004101461b410020001b0c010b41020b2100200141106a240020000b3d01027f2000280204220320024922044504402001200220002802002201200241f0910410332000200320026b3602042000200120026a3602000b20040b11002001410036000020002001410410130b5301027f230041106b22002400200042808001370208200041ba9204360204200041046a220141001019200141001019200028020c2200418180014f044020004180800141f08004100b000b41002000101a000b5b01027f230041106b22022400200242808001370208200241ba9204360204200241046a22032001047f20034101101941010541000b1019200228020c2201418180014f044020014180800141f08004100b000b20002001101a000ba70102057f017e230041306b2201240020014100360220200142808001370228200141ba9204360224200141246a2202100c20012001290224370218200141106a200141186a2203200128022c10182001280214210420012802102105200129021821062001410036022c2001200637022420002002100e20012001290224370218200141086a2003200128022c1018200520042001280208200128020c10021a200141306a24000b7401027f230041206b220324002002200128020422044b04402003410136020c200341a48e0436020820034200370214200341988e04360210200341086a41f08f041011000b2001200420026b36020420012001280200220120026a3602002000200236020420002001360200200341206a24000b940101027f20002802082202200028020422034904402000200241016a360208200028020020026a20013a00000f0b230041306b2200240020002003360204200020023602002000412c6a41033602002000410236020c20004188880436020820004202370214200041033602242000200041206a360210200020003602282000200041046a360220200041086a41e08f041011000b0d00200041ba920420011004000bef0401077f230041406a220024000240024002400240100f41ff0171410546044020004180800136022841ba9204200041286a22011001200041106a200028022841ba920441808001100a2000200029031037022820012000411c6a10140d0320002d001f210120002d001e210220002d001d2103024020002d001c2204412f470440200441e300470d05410121042003413a47200241a5014772200141d1004772450d010c050b41002104200341860147200241db004772200141d90147720d040b2000410036022420004280800137022c200041ba9204360228200041286a2202100c2000200029022837021c200041086a2000411c6a20002802301018200028020c210320002802082105200028021c21012000200028022022063602282005200320012002100021022000200028022820012006100a02400240024020020e0400040401040b200028020021012000200028020436022c20002001360228200041286a1012220141ff01714102470440200028022c450d020b2000410136022c200041bc82043602280c060b2000410136022c2000418c82043602280c050b20040d02230041106b22002400200042808001370208200041ba9204360204200041046a220241001019200141ff01714100472002100e200028020c2200418180014f044020004180800141f08004100b000b41002000101a000b200041043a0028200041286a101c000b2000410136022c2000419c810436022820004200370234200041988e04360230200041286a41a481041011000b200141ff0171451017410041001016000b410141011016000b20004200370234200041988e04360230200041286a41e481041011000b4501017f230041206b2201240020014101360204200141988d043602002001420137020c2001410136021c200120003602182001200141186a360208200141e481041011000be90101057f230041206b220024000240100f220141ff0171410546044020004180800136021441ba9204200041146a22011001200041086a200028021441ba920441808001100a2000200029030837021420012000411c6a10140d0120002d001f210120002d001e210220002d001d210320002d001c2204419b01470440200341cb00462002419d0146712001411b467145200441ed0147720d02410010171015000b200341ae01472002419d014772200141de0047720d01200041146a1012220041ff01714102460d01200010171015000b200020013a0014200041146a101c000b410141011016000b6001027f230041106b2203240020022000280200200028020822046b4b0440200341086a200020042002101f2003280208200328020c1020200028020821040b200028020420046a2001200210061a2000200220046a360208200341106a24000b9a0301077f230041206b220624000240200220036a22032002490d00410121044108200128020022024101742205200320032005491b2203200341084d1b2203417f73411f76210502402002450440410021040c010b2006200236021c200620012802043602140b20062004360218200641086a210820032102200641146a2104230041106b22072400027f027f024020050440200241004e0d01410121054100210241040c030b2008410036020441010c010b027f2004280204044020042802082209450440200741086a20052002102120072802082104200728020c0c020b2004280200210a02402005200210222204450440410021040c010b2004200a200910061a0b20020c010b20072005200210212007280200210420072802040b210920082004200520041b3602042009200220041b21022004450b210541080b20086a200236020020082005360200200741106a2400200628020c21042006280208450440200120033602002001200436020441818080807821040c010b200628021021030b2000200336020420002004360200200641206a24000bcb0100024020004181808080784704402000450d01230041306b220024002000200136020c20004102360214200041a085043602102000420137021c2000410336022c2000200041286a36021820002000410c6a360228230041206b22012400200141003b011c200141b085043602182001200041106a360214200141b88704360210200141988e0436020c2001410c6a102b000b0f0b230041206b220024002000410136020c20004188830436020820004200370214200041988e04360210200041086a418084041011000b200041a892042d00001a200120021022210120002002360204200020013602000bc50101017f027f41ac92042d0000044041b092042802000c010b3f00210241b0920441c0920536020041ac920441013a000041b49204200241107436020041c092050b21020240027f4100200020026a41016b410020006b71220020016a22022000490d001a41b492042802002002490440200141ffff036a220241107640002200417f460d022000411074220020024180807c716a22022000490d0241b4920420023602004100200020016a22022000490d011a0b41b09204200236020020000b0f0b41000b0c00200041dc8204200110240b850401077f230041406a22032400200341033a003c2003412036022c200341003602382003200136023420032000360230200341003602242003410036021c027f0240024020022802102201450440200228020c22004103742105200041ffffffff01712106200228020421082002280200210720022802082101034020042005460d02200420076a220041046a28020022020440200328023020002802002002200328023428020c1100000d040b200441086a21042001280200210020012802042102200141086a210120002003411c6a2002110100450d000b0c020b200228021422044105742100200441ffffff3f712106200228020c2109200228020821052002280204210820022802002207210403402000450d01200441046a28020022020440200328023020042802002002200328023428020c1100000d030b2003200128021036022c200320012d001c3a003c20032001280218360238200341106a2005200141086a10372003200329031037021c200341086a20052001103720032003290308370224200441086a2104200041206b210020012802142102200141206a2101200520024103746a22022802002003411c6a2002280204110100450d000b0c010b200620084904402003280230200720064103746a22002802002000280204200328023428020c1100000d010b41000c010b41010b2101200341406b240020010b0300010b0c00200020012002101e41000bb20201047f230041106b220224000240027f0240024020014180014f04402002410036020c2001418010490d012001418080044f0d0220022001410c7641e001723a000c20022001410676413f71418001723a000d4102210341030c030b200028020822032000280200460440230041106b22042400200441086a200020034101101f2004280208200428020c1020200441106a2400200028020821030b2000200341016a360208200028020420036a20013a00000c030b2002200141067641c001723a000c4101210341020c010b20022001410676413f71418001723a000e20022001410c76413f71418001723a000d2002200141127641077141f001723a000c4103210341040b210420032002410c6a2205722001413f71418001723a0000200020052004101e0b200241106a240041000bdb05020b7f027e230041406a220324004127210202402000350200220d4290ce00540440200d210e0c010b0340200341196a20026a220041046b200d4290ce0080220e42f0b1037e200d7ca7220441ffff037141e4006e220641017441ac88046a2f00003b0000200041026b2006419c7f6c20046a41ffff037141017441ac88046a2f00003b0000200241046b2102200d42ffc1d72f562100200e210d20000d000b0b200ea7220041e3004b0440200241026b2202200341196a6a200ea7220441ffff037141e4006e2200419c7f6c20046a41ffff037141017441ac88046a2f00003b00000b02402000410a4f0440200241026b2202200341196a6a200041017441ac88046a2f00003b00000c010b200241016b2202200341196a6a20004130723a00000b200128021c22054101712207412720026b22066a2100410021042005410471044041988e04210441988e0441988e04102d20006a21000b412b418080c40020071b2107200341196a20026a2108024020012802004504404101210220012802142200200128021822012007200410300d01200020082006200128020c11000021020c010b2000200128020422094f04404101210220012802142200200128021822012007200410300d01200020082006200128020c11000021020c010b200541087104402001280210210b2001413036021020012d0020210c41012102200141013a0020200128021422052001280218220a2007200410300d01200341106a2001200920006b4101103120032802102200418080c400460d0120032802142104200520082006200a28020c1100000d01200020042005200a10320d012001200c3a00202001200b360210410021020c010b41012102200341086a2001200920006b4101103120032802082205418080c400460d00200328020c210920012802142200200128021822012007200410300d00200020082006200128020c1100000d002005200920002001103221020b200341406b240020020b1800200128021441d482044105200128021828020c1100000b0e0020002802001a03400c000b000baa0201017f230041406a220124002001200036020c20014102360214200141b08e043602102001420137021c2001410436022c2001200141286a36021820012001410c6a360228200141003602382001428080808010370230200141306a200141106a10234504402001280234210020012802382101024041b892042d000045044041b992042d00000d010b200020011003410947044041b8920441013a00000b41b9920441013a00000b000b230041406a220024002000413336020c200041c08504360208200041c4820436021420002001413f6a3602102000413c6a41063602002000410236021c2000419c880436021820004202370224200041023602342000200041306a3602202000200041106a3602382000200041086a360230200041186a41e086041011000b2200200042eeb4d39ded9bae93907f370308200042d4ce8f88d3c5f6dba47f3703000ba10301067f230041106b220224000240200120006b220141104f04402000200041036a417c71220520006b2200102e2005200120006b2200417c716a2000410371102e6a21042000410276210303402003450d0220022005200341c0012003200341c0014f1b41ac8b04102f200228020c21032002280208210520022002280200200228020422002000417c7141888d04102f024020022802042200450440410021010c010b2002280200220620004102746a21074100210103404100210003402001200020066a2802002201417f734107762001410676724181828408716a2101200041046a22004110470d000b200641106a22062007470d000b0b200141087641ff81fc0771200141ff81fc07716a418180046c41107620046a2104200228020c2201450d000b2002280208210020014102742103410021010340200120002802002201417f734107762001410676724181828408716a2101200041046a2100200341046b22030d000b200141087641ff81fc0771200141ff81fc07716a418180046c41107620046a21040c010b20002001102e21040b200241106a240020040b2c01017f200104400340200220002c000041bf7f4a6a2102200041016a2100200141016b22010d000b0b20020b6b01017f230041206b22052400200220034904402005410136020c200541a48e0436020820054200370214200541988e04360210200541086a20041011000b20002003360204200020013602002000200220036b36020c2000200120034102746a360208200541206a24000b39000240027f2002418080c40047044041012000200220012802101101000d011a0b20030d0141000b0f0b200020034100200128020c1100000b990101027f024002400240024020012d0020220441016b0e03010200030b200341ff01710d00410021040c020b20022104410021020c010b20024101762104200241016a41017621020b200441016a210420012802102103200128021821052001280214210102400340200441016b2204450d01200120032005280210110100450d000b418080c40021030b20002002360204200020033602000b3201017f027f0340200120012004460d011a200441016a2104200220002003280210110100450d000b200441016b0b2001490b78002001200346044020002002200110061a0f0b230041306b2200240020002003360204200020013602002000412c6a41033602002000410336020c200041fc8b0436020820004202370214200041033602242000200041206a360210200020003602282000200041046a360220200041086a20041011000bf60101067f2000027f418080c400200128020022022001280204460d001a2001200241016a2205360200024020022d0000220341187441187541004e0d002001200241026a220536020020022d0001413f7121042003411f712106200341df014d0440200641067420047221030c010b2001200241036a220536020020022d0002413f712004410674722104200341f00149044020042006410c747221030c010b2001200241046a2205360200418080c4002006411274418080f0007120022d0003413f71200441067472722203418080c400460d011a0b200120012802082207200520026b6a36020820030b360204200020073602000baa0301067f230041306b22022400200028020421042000280200210302400240200128020022062001280208220072044002402000450d00200128020c21002002410036022c200220033602242002200320046a360228200041016a21000340200041016b22000440200241186a200241246a1034200228021c418080c400470d010c020b0b200241106a200241246a10342002280214418080c400460d000240024020022802102205450d00200420054d04404100210020042005460d010c020b41002100200320056a2c00004140480d010b200321000b2005200420001b21042000200320001b21030b2006450440200128021420032004200128021828020c11000021000c030b200128020422002003200320046a102d22054d0d01200241086a2001200020056b410010314101210020022802082205418080c400460d02200228020c210620012802142207200320042001280218220128020c1100000d022005200620072001103221000c020b200128021420032004200128021828020c11000021000c010b200128021420032004200128021828020c11000021000b200241306a240020000b140020002802002001200028020428020c1101000b5501027f0240027f02400240200228020041016b0e020103000b200241046a0c010b200120022802044103746a22012802044105470d0120012802000b2802002104410121030b20002004360204200020033602000b0a0020002001200210240be00201067f230041406a22022400200028020021054101210002402001280214220441c88704410c2001280218220628020c22011100000d00200528020c21032002413c6a4103360200200241346a410336020020024103360214200241a087043602102002420337021c20022003410c6a3602382002200341086a3602302002410236022c200220033602282002200241286a220736021820042006200241106a10380d00200528020822030440200441d48704410220011100000d01200241386a200341106a290200370300200241306a200341086a29020037030020022003290200370328200420062007103821000c010b200220052802002203200528020428020c11020041002100200229030042e4dec78590d085de7d520d00200229030842c1f7f9e8cc93b2d141520d0041012100200441d48704410220011100000d00200420032802002003280204200111000021000b200241406b240020000b0bb0120100418080040ba7122f55736572732f616c65786265616e2f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f696e6b5f656e762d352e302e302f7372632f656e67696e652f6f6e5f636861696e2f696d706c732e727300000001006f0000001a01000032000000656e636f756e746572656420756e6578706563746564206572726f72800001001c000000000001006f000000e3000000170000002f55736572732f616c65786265616e2f446f63756d656e74732f726f6775652f74657374696e672f6c69622e72730000b40001002e000000060000000500000073746f7261676520656e7472792077617320656d70747900f400010017000000636f756c64206e6f742070726f7065726c79206465636f64652073746f7261676520656e747279001401010027000000070000000000000001000000080000004572726f72000000090000000c000000040000000a0000000b0000000c0000006361706163697479206f766572666c6f7700000074010100110000002f55736572732f616c65786265616e2f2e7275737475702f746f6f6c636861696e732f737461626c652d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7261775f7665632e7273900101007000000019000000050000002f55736572732f616c65786265616e2f2e7275737475702f746f6f6c636861696e732f737461626c652d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f616c6c6f632e72736d656d6f727920616c6c6f636174696f6e206f6620206279746573206661696c65647e02010015000000930201000d000000100201006e000000a50100000d0000006120666f726d617474696e6720747261697420696d706c656d656e746174696f6e2072657475726e656420616e206572726f722f55736572732f616c65786265616e2f2e7275737475702f746f6f6c636861696e732f737461626c652d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f666d742e727300f30201006c0000007902000020000000293a63616c6c656420604f7074696f6e3a3a756e77726170282960206f6e206120604e6f6e65602076616c75650000001807010000000000710301000100000071030100010000000700000000000000010000000d00000070616e69636b6564206174203a0a696e646578206f7574206f6620626f756e64733a20746865206c656e20697320206275742074686520696e64657820697320d603010020000000f6030100120000003a200000180701000000000018040100020000003030303130323033303430353036303730383039313031313132313331343135313631373138313932303231323232333234323532363237323832393330333133323333333433353336333733383339343034313432343334343435343634373438343935303531353235333534353535363537353835393630363136323633363436353636363736383639373037313732373337343735373637373738373938303831383238333834383538363837383838393930393139323933393439353936393739383939206f7574206f662072616e676520666f7220736c696365206f66206c656e6774682072616e676520656e6420696e6465782000001605010010000000f4040100220000002f55736572732f616c65786265616e2f2e7275737475702f746f6f6c636861696e732f737461626c652d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f697465722e727300003805010072000000ce05000025000000736f7572636520736c696365206c656e67746820282920646f6573206e6f74206d617463682064657374696e6174696f6e20736c696365206c656e6774682028bc05010015000000d10501002b00000070030100010000002f55736572732f616c65786265616e2f2e7275737475702f746f6f6c636861696e732f737461626c652d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f636f756e742e727300000014060100710000004f000000320000001807010000000000756e61626c6520746f206465636f64652073656c6563746f72656e636f756e746572656420756e6b6e6f776e2073656c6563746f72756e61626c6520746f206465636f646520696e707574636f756c64206e6f74207265616420696e7075747061696420616e20756e70617961626c65206d6573736167656d6964203e206c656e00000018070100090000000a00000018070100000000002c070100010000002f55736572732f616c65786265616e2f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f696e6b5f656e762d352e302e302f7372632f656e67696e652f6f6e5f636861696e2f6275666665722e727340070100700000005c0000003b00000040070100700000005c0000001400000040070100700000005d0000000e00000040070100700000006800000009000000400701007000000090000000210000002f55736572732f616c65786265616e2f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f70616c6c65742d636f6e7472616374732d756170692d6e6578742d362e302e332f7372632f686f73742e727300000000080100710000002d000000170000002f55736572732f616c65786265616e2f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7061726974792d7363616c652d636f6465632d332e362e31322f7372632f636f6465632e727300840801006b000000770000000e000000190000001c000000160000001400000019000000a0060100b9060100d5060100eb060100ff0601","build_info":{"build_mode":"Debug","cargo_contract_version":"4.1.1","rust_toolchain":"stable-aarch64-apple-darwin","wasm_opt_settings":{"keep_debug_symbols":false,"optimization_passes":"Z"}}},"contract":{"name":"testing","version":"0.1.0","authors":["[your_name] <[your_email]>"]},"image":null,"spec":{"constructors":[{"args":[{"label":"init_value","type":{"displayName":["bool"],"type":0}}],"default":false,"docs":["Constructor that initializes the `bool` value to the given `init_value`."],"label":"new","payable":false,"returnType":{"displayName":["ink_primitives","ConstructorResult"],"type":2},"selector":"0x9bae9d5e"},{"args":[],"default":false,"docs":["Constructor that initializes the `bool` value to `false`.","","Constructors can delegate to other constructors."],"label":"default","payable":false,"returnType":{"displayName":["ink_primitives","ConstructorResult"],"type":2},"selector":"0xed4b9d1b"}],"docs":[],"environment":{"accountId":{"displayName":["AccountId"],"type":6},"balance":{"displayName":["Balance"],"type":9},"blockNumber":{"displayName":["BlockNumber"],"type":12},"chainExtension":{"displayName":["ChainExtension"],"type":13},"hash":{"displayName":["Hash"],"type":10},"maxEventTopics":4,"staticBufferSize":16384,"timestamp":{"displayName":["Timestamp"],"type":11}},"events":[],"lang_error":{"displayName":["ink","LangError"],"type":4},"messages":[{"args":[],"default":false,"docs":[" A message that can be called on instantiated contracts."," This one flips the value of the stored `bool` from `true`"," to `false` and vice versa."],"label":"flip","mutates":true,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":2},"selector":"0x633aa551"},{"args":[],"default":false,"docs":[" Simply returns the current value of our `bool`."],"label":"get","mutates":false,"payable":false,"returnType":{"displayName":["ink","MessageResult"],"type":5},"selector":"0x2f865bd9"}]},"storage":{"root":{"layout":{"struct":{"fields":[{"layout":{"leaf":{"key":"0x00000000","ty":0}},"name":"value"}],"name":"Testing"}},"root_key":"0x00000000","ty":1}},"types":[{"id":0,"type":{"def":{"primitive":"bool"}}},{"id":1,"type":{"def":{"composite":{"fields":[{"name":"value","type":0,"typeName":",>>::Type"}]}},"path":["testing","testing","Testing"]}},{"id":2,"type":{"def":{"variant":{"variants":[{"fields":[{"type":3}],"index":0,"name":"Ok"},{"fields":[{"type":4}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":3},{"name":"E","type":4}],"path":["Result"]}},{"id":3,"type":{"def":{"tuple":[]}}},{"id":4,"type":{"def":{"variant":{"variants":[{"index":1,"name":"CouldNotReadInput"}]}},"path":["ink_primitives","LangError"]}},{"id":5,"type":{"def":{"variant":{"variants":[{"fields":[{"type":0}],"index":0,"name":"Ok"},{"fields":[{"type":4}],"index":1,"name":"Err"}]}},"params":[{"name":"T","type":0},{"name":"E","type":4}],"path":["Result"]}},{"id":6,"type":{"def":{"composite":{"fields":[{"type":7,"typeName":"[u8; 32]"}]}},"path":["ink_primitives","types","AccountId"]}},{"id":7,"type":{"def":{"array":{"len":32,"type":8}}}},{"id":8,"type":{"def":{"primitive":"u8"}}},{"id":9,"type":{"def":{"primitive":"u128"}}},{"id":10,"type":{"def":{"composite":{"fields":[{"type":7,"typeName":"[u8; 32]"}]}},"path":["ink_primitives","types","Hash"]}},{"id":11,"type":{"def":{"primitive":"u64"}}},{"id":12,"type":{"def":{"primitive":"u32"}}},{"id":13,"type":{"def":{"variant":{}},"path":["ink_env","types","NoChainExtension"]}}],"version":5} \ No newline at end of file diff --git a/crates/pop-parachains/Cargo.toml b/crates/pop-parachains/Cargo.toml index f84c1849..0b53a87a 100644 --- a/crates/pop-parachains/Cargo.toml +++ b/crates/pop-parachains/Cargo.toml @@ -37,3 +37,4 @@ pop-common = { path = "../pop-common", version = "0.2.0" } [dev-dependencies] mockito.workspace = true +tokio-test.workspace = true diff --git a/crates/pop-parachains/README.md b/crates/pop-parachains/README.md index f248f0d1..23169bf1 100644 --- a/crates/pop-parachains/README.md +++ b/crates/pop-parachains/README.md @@ -6,94 +6,103 @@ A crate for generating, building and running parachains and pallets. Used by ## Usage Generate a new parachain: -```rust -use pop_parachains::{instantiate_template_dir, Config, Git, Template}; +```rust,no_run +use pop_parachains::{instantiate_template_dir, Config, Parachain}; +use std::path::Path; -let template = Template::Standard; -let destination_path = ...; +let destination_path = Path::new("./"); +let tag_version = None; // Latest let config = Config { - symbol: ..., - decimals: ..., - initial_endowment: .., -} -instantiate_template_dir(template,destination_path,config)?; + symbol: "UNIT".to_string(), + decimals: 12, + initial_endowment: "1u64 << 60".to_string() +}; +let tag = instantiate_template_dir(&Parachain::Standard, &destination_path, tag_version, config); ``` Build a Parachain: -```rust +```rust,no_run use pop_common::Profile; use pop_parachains::build_parachain; +use std::path::Path; -let path = ...; +let path = Path::new("./"); let package = None; // The optional package to be built. -build_parachain(&path, package, &Profile::Release, None)?; +let binary_path = build_parachain(&path, package, &Profile::Release, None).unwrap(); ``` Generate a raw chain specification file and export the WASM and genesis state files: -```rust -use pop_parachains::{generate_plain_chain_spec, generate_raw_chain_spec, export_wasm_file, generate_genesis_state_file}; +```rust,no_run +use pop_common::Profile; +use pop_parachains::{build_parachain, export_wasm_file, generate_plain_chain_spec, generate_raw_chain_spec, generate_genesis_state_file}; +use std::path::Path; -let path = ...; // Location of the parachain project. +let path = Path::new("./"); // Location of the parachain project. +let package = None; // The optional package to be built. let para_id = 2000; // The path to the node binary executable. -let binary_path = ..; +let binary_path = build_parachain(&path, package, &Profile::Release, None).unwrap();; // Generate a plain chain specification file of a parachain let plain_chain_spec_path = path.join("plain-parachain-chainspec.json"); -let plain_chain_spec = generate_plain_chain_spec(&binary_path, plain_chain_spec_path, para_id)?; +generate_plain_chain_spec(&binary_path, &plain_chain_spec_path, para_id); // Generate a raw chain specification file of a parachain -let chain_spec = generate_raw_chain_spec(&binary_path, &plain_chain_spec, "raw-parachain-chainspec.json")?; +let chain_spec = generate_raw_chain_spec(&binary_path, &plain_chain_spec_path, "raw-parachain-chainspec.json").unwrap(); // Export the WebAssembly runtime for the parachain. -let wasm_file = export_wasm_file(&binary_path, &chain_spec, "para-2000-wasm")?; +let wasm_file = export_wasm_file(&binary_path, &chain_spec, "para-2000-wasm").unwrap(); // Generate the parachain genesis state. -let genesis_state_file = generate_genesis_state_file(&binary_path, &chain_spec, "para-2000-genesis-state")?; +let genesis_state_file = generate_genesis_state_file(&binary_path, &chain_spec, "para-2000-genesis-state").unwrap(); ``` Run a Parachain: -```rust +```rust,no_run use pop_parachains::Zombienet; - - -let cache = ... // The cache location, used for caching binaries. -let config_file = ... // The Zombienet config to be used to launch a network. -let relay_chain_version = ... // relay_chain version if applies -let system_chain_version = ... // system_chain version if applies -let parachains_binaries = ... // The binaries required to launch parachains - -let mut zombienet = Zombienet::new( - cache, - config_file, - relay_chain_version, - system_chain_version, - parachains_binaries, -) -.await?; - -zombienet.spawn().await? -``` - -To download the missing binaries before starting the network: -```rust -// Check if any binaries need to be sourced -let missing = zombienet.missing_binaries(); -if missing.len() > 0 { +use std::path::Path; +use tokio_test; + +tokio_test::block_on(async { + let cache = Path::new("./cache"); // The cache location, used for caching binaries. + let network_config = "network.toml"; // The configuration file to be used to launch a network. + let relay_chain_version = None; // Latest + let relay_chain_runtime_version = None; // Latest + let system_parachain_version = None; // Latest + let system_parachain_runtime_version = None; // Latest + let parachains = None; // The parachain(s) specified. + + let mut zombienet = Zombienet::new( + &cache, + &network_config, + relay_chain_version, + relay_chain_runtime_version, + system_parachain_version, + system_parachain_runtime_version, + parachains, + ).await.unwrap(); + + zombienet.spawn().await; + + //To download the missing binaries before starting the network: + let release = true; // Whether the binary should be built using the release profile. + let status = {}; // Mechanism to observe status updates + let verbose = false; // Whether verbose output is required + let missing = zombienet.binaries(); for binary in missing { - binary.source(&cache).await?; + binary.source(release, &status, verbose).await; } -} +}) ``` Generate a new Pallet: -```rust +```rust,no_run use pop_parachains::{create_pallet_template, TemplatePalletConfig}; -let path = ...; +let path = "./".to_string(); let pallet_config = TemplatePalletConfig { - name: ..., - authors: ..., - description: ..., -} + name: "MyPallet".to_string(), + authors: "R0GUE".to_string(), + description: "Template pallet".to_string() +}; -create_pallet_template(path,pallet_config)?; +create_pallet_template(Some(path),pallet_config); ``` ## Acknowledgements