From 32537a4d08e5c9715828a17b4e35b33090563aec Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 28 May 2024 11:15:28 +0200 Subject: [PATCH 01/18] Scaffolding for wasm test --- .github/workflows/ci.yml | 11 +++++++++ Cargo.lock | 4 ++++ Cargo.toml | 1 + examples/wasm/Cargo.toml | 8 +++++++ examples/wasm/examples/wasm_example.rs | 32 ++++++++++++++++++++++++++ 5 files changed, 56 insertions(+) create mode 100644 examples/wasm/Cargo.toml create mode 100644 examples/wasm/examples/wasm_example.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd6f6fe07..e203276dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,16 @@ jobs: with: access_token: ${{ secrets.GITHUB_TOKEN }} + setup_wasmtime: + name: Setup wasmtime + runs-on: ${{ matrix.os }} + steps: + - name: Setup `wasmtime` + uses: bytecodealliance/actions/wasmtime/setup@v1 + + - name: Run `wasmtime version` + run: "wasmtime --version" + build: name: ${{ matrix.check }} runs-on: ${{ matrix.os }} @@ -54,6 +64,7 @@ jobs: # Test for 32 bit and wasm32-unknown-unknown compatibility cargo build --target wasm32-unknown-unknown --no-default-features --features sync-api, + cargo build --example wasm_example --target wasm32-unknown-unknown, # Test for 32 bit and wasm32-wasip1 compatibility cargo build --target wasm32-wasip1 --no-default-features --features std --features staking-xt --features contracts-xt --features sync-api, diff --git a/Cargo.lock b/Cargo.lock index 915dd2861..aa004e84d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,6 +61,10 @@ dependencies = [ "substrate-api-client", ] +[[package]] +name = "ac-examples-wasm" +version = "0.5.0" + [[package]] name = "ac-keystore" version = "0.10.0" diff --git a/Cargo.toml b/Cargo.toml index 9ffeacb61..6078ee20c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ members = [ "compose-macros", "examples/async", "examples/sync", + "examples/wasm", "node-api", "test-no-std", "testing/async", diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml new file mode 100644 index 000000000..754eea3d8 --- /dev/null +++ b/examples/wasm/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "ac-examples-wasm" +version = "0.5.0" +license = "Apache-2.0" +edition = "2021" + +[dev-dependencies] + diff --git a/examples/wasm/examples/wasm_example.rs b/examples/wasm/examples/wasm_example.rs new file mode 100644 index 000000000..f7b878ba7 --- /dev/null +++ b/examples/wasm/examples/wasm_example.rs @@ -0,0 +1,32 @@ +/* + Copyright 2023 Supercomputing Systems AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +//! Example that shows how to detect a runtime update and afterwards update the metadata. + +use std::process::ExitCode; + +#[no_mangle] +pub extern "C" fn add(lhs: i32, rhs: i32) -> i32 { + if lhs % 2 == 0 { + lhs + rhs + } else { + lhs - rhs + } +} + +fn main() -> Result { + assert!(5 == 5, "x wasn't true!"); + //panic!("x wasn't true!"); + //Err(5) + Ok(ExitCode::from(0)) +} From 5eb956353c91d86a8471e4cfef1a1359bc5105b6 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 28 May 2024 11:28:52 +0200 Subject: [PATCH 02/18] Fix command to build wasm example --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e203276dd..26cc2840b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,7 @@ jobs: # Test for 32 bit and wasm32-unknown-unknown compatibility cargo build --target wasm32-unknown-unknown --no-default-features --features sync-api, - cargo build --example wasm_example --target wasm32-unknown-unknown, + cargo build --release -p ac-examples-wasm --examples --target wasm32-unknown-unknown, # Test for 32 bit and wasm32-wasip1 compatibility cargo build --target wasm32-wasip1 --no-default-features --features std --features staking-xt --features contracts-xt --features sync-api, From d8b7ad919433ba7d2fbb55b0f5611b2d882b5a92 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 28 May 2024 12:53:59 +0200 Subject: [PATCH 03/18] State os for running job statically --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26cc2840b..864aebec1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: setup_wasmtime: name: Setup wasmtime - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest steps: - name: Setup `wasmtime` uses: bytecodealliance/actions/wasmtime/setup@v1 From aee1ef7dcac4c39e7ec1637835ab6fac60abfb27 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 28 May 2024 13:25:41 +0200 Subject: [PATCH 04/18] Run example with wasmtime --- .github/workflows/ci.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 864aebec1..51007be3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,15 +21,18 @@ jobs: with: access_token: ${{ secrets.GITHUB_TOKEN }} - setup_wasmtime: - name: Setup wasmtime + wasmtime_test: + name: wasmtime test runs-on: ubuntu-latest steps: - name: Setup `wasmtime` uses: bytecodealliance/actions/wasmtime/setup@v1 - - name: Run `wasmtime version` - run: "wasmtime --version" + - name: Compile wasm example + run: cargo build --release -p ac-examples-wasm --examples --target wasm32-unknown-unknown + + - name: Run wasm example + run: wasmtime --invoke main ../../target/wasm32-unknown-unknown/debug/examples/wasm_example.wasm 0 0 build: name: ${{ matrix.check }} @@ -64,7 +67,6 @@ jobs: # Test for 32 bit and wasm32-unknown-unknown compatibility cargo build --target wasm32-unknown-unknown --no-default-features --features sync-api, - cargo build --release -p ac-examples-wasm --examples --target wasm32-unknown-unknown, # Test for 32 bit and wasm32-wasip1 compatibility cargo build --target wasm32-wasip1 --no-default-features --features std --features staking-xt --features contracts-xt --features sync-api, From 5212a9f1537327ecdd54ce66c3aa193727641fba Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 29 May 2024 11:18:33 +0200 Subject: [PATCH 05/18] Try different approach for a build with a wasm test --- .github/workflows/ci.yml | 47 +++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51007be3c..15f59257f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,19 +21,6 @@ jobs: with: access_token: ${{ secrets.GITHUB_TOKEN }} - wasmtime_test: - name: wasmtime test - runs-on: ubuntu-latest - steps: - - name: Setup `wasmtime` - uses: bytecodealliance/actions/wasmtime/setup@v1 - - - name: Compile wasm example - run: cargo build --release -p ac-examples-wasm --examples --target wasm32-unknown-unknown - - - name: Run wasm example - run: wasmtime --invoke main ../../target/wasm32-unknown-unknown/debug/examples/wasm_example.wasm 0 0 - build: name: ${{ matrix.check }} runs-on: ${{ matrix.os }} @@ -67,6 +54,7 @@ jobs: # Test for 32 bit and wasm32-unknown-unknown compatibility cargo build --target wasm32-unknown-unknown --no-default-features --features sync-api, + cargo build --release -p ac-examples-wasm --examples --target wasm32-unknown-unknown # Test for 32 bit and wasm32-wasip1 compatibility cargo build --target wasm32-wasip1 --no-default-features --features std --features staking-xt --features contracts-xt --features sync-api, @@ -133,6 +121,14 @@ jobs: !target/release/examples/*.d !target/release/examples/*-* + - name: Upload wasm examples + uses: actions/upload-artifact@v4 + if: contains(matrix.check, 'examples-wasm') + with: + name: examples-wasm + path: | + target/wasm32-unknown-unknown/release/examples/*.wasm + - name: Upload async testing examples uses: actions/upload-artifact@v4 if: contains(matrix.check, 'testing-async') @@ -248,6 +244,31 @@ jobs: nc -z -v 127.0.0.1 9944 chmod +x ${{ matrix.example }} ./${{ matrix.example }} + wasm_examples: + runs-on: ${{ matrix.os }} + needs: build + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest ] + example: [ + wasm_example, + ] + steps: + - uses: actions/checkout@v4 + + - name: Download examples from previous run + uses: actions/download-artifact@v4 + with: + pattern: examples-wasm + merge-multiple: true + + - name: Setup `wasmtime` + uses: bytecodealliance/actions/wasmtime/setup@v1 + + - name: Run wasm example + run: wasmtime --invoke main ../../target/wasm32-unknown-unknown/debug/examples/${{ matrix.example }}.wasm 0 0 + merge: runs-on: ubuntu-latest needs: examples From 4788746405caf1bac23831822d41d8f1cb9f943c Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 29 May 2024 11:31:17 +0200 Subject: [PATCH 06/18] Add missing comma --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15f59257f..89c4e3a83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,7 @@ jobs: # Test for 32 bit and wasm32-unknown-unknown compatibility cargo build --target wasm32-unknown-unknown --no-default-features --features sync-api, - cargo build --release -p ac-examples-wasm --examples --target wasm32-unknown-unknown + cargo build --release -p ac-examples-wasm --examples --target wasm32-unknown-unknown, # Test for 32 bit and wasm32-wasip1 compatibility cargo build --target wasm32-wasip1 --no-default-features --features std --features staking-xt --features contracts-xt --features sync-api, From b9a423a698c25addc809d3d67248dae1bdaa6dc1 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 29 May 2024 11:51:01 +0200 Subject: [PATCH 07/18] Fix toml formatting --- examples/wasm/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 754eea3d8..1b1320c77 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -5,4 +5,3 @@ license = "Apache-2.0" edition = "2021" [dev-dependencies] - From 61aa86718d6f1085f7492fd353ad000df73b66dc Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Thu, 30 May 2024 09:13:19 +0200 Subject: [PATCH 08/18] Adjust path --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89c4e3a83..b1cd8b331 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -267,7 +267,7 @@ jobs: uses: bytecodealliance/actions/wasmtime/setup@v1 - name: Run wasm example - run: wasmtime --invoke main ../../target/wasm32-unknown-unknown/debug/examples/${{ matrix.example }}.wasm 0 0 + run: wasmtime --invoke main ${{ matrix.example }}.wasm 0 0 merge: runs-on: ubuntu-latest From 6f225b571fb4ea8c0fa68201bc86e76557aa0f32 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 5 Jun 2024 09:04:34 +0200 Subject: [PATCH 09/18] Test a failing example --- examples/wasm/examples/wasm_example.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/wasm/examples/wasm_example.rs b/examples/wasm/examples/wasm_example.rs index f7b878ba7..9d54c10f9 100644 --- a/examples/wasm/examples/wasm_example.rs +++ b/examples/wasm/examples/wasm_example.rs @@ -28,5 +28,5 @@ fn main() -> Result { assert!(5 == 5, "x wasn't true!"); //panic!("x wasn't true!"); //Err(5) - Ok(ExitCode::from(0)) + Ok(ExitCode::from(1)) } From 0e629b5b55124e0ff8731142c04a76558b9e8232 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 5 Jun 2024 15:56:36 +0200 Subject: [PATCH 10/18] Return an Err --- examples/wasm/examples/wasm_example.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/wasm/examples/wasm_example.rs b/examples/wasm/examples/wasm_example.rs index 9d54c10f9..09c32a9f2 100644 --- a/examples/wasm/examples/wasm_example.rs +++ b/examples/wasm/examples/wasm_example.rs @@ -27,6 +27,6 @@ pub extern "C" fn add(lhs: i32, rhs: i32) -> i32 { fn main() -> Result { assert!(5 == 5, "x wasn't true!"); //panic!("x wasn't true!"); - //Err(5) - Ok(ExitCode::from(1)) + Err(5) + //Ok(ExitCode::from(1)) } From ae0e25a8cf3aebe39233556fd6f0cbc8b5d2c28d Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Thu, 6 Jun 2024 16:02:42 +0200 Subject: [PATCH 11/18] Improve wasm example --- Cargo.lock | 9 +++ examples/wasm/Cargo.toml | 9 +++ examples/wasm/examples/wasm_example.rs | 86 +++++++++++++++++++++----- 3 files changed, 90 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa004e84d..0c0447f11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,15 @@ dependencies = [ [[package]] name = "ac-examples-wasm" version = "0.5.0" +dependencies = [ + "frame-metadata 16.0.0", + "kitchensink-runtime", + "pallet-balances", + "parity-scale-codec", + "sp-core", + "sp-runtime", + "substrate-api-client", +] [[package]] name = "ac-keystore" diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 1b1320c77..58a7c3d03 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -5,3 +5,12 @@ license = "Apache-2.0" edition = "2021" [dev-dependencies] +frame-metadata = { version = "16.0", default-features = false, features = ["current", "serde_full", "decode"] } +sp-core = { default-features = false, features = ["full_crypto", "serde"], git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" } + +substrate-api-client = { default-features = false, path = "../..", version = "0.17" } + +pallet-balances = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" } +kitchensink-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ['derive'] } diff --git a/examples/wasm/examples/wasm_example.rs b/examples/wasm/examples/wasm_example.rs index 09c32a9f2..c9ed99407 100644 --- a/examples/wasm/examples/wasm_example.rs +++ b/examples/wasm/examples/wasm_example.rs @@ -12,21 +12,79 @@ */ //! Example that shows how to detect a runtime update and afterwards update the metadata. - +use kitchensink_runtime::{RuntimeCall, UncheckedExtrinsic}; +pub use pallet_balances::Call as BalancesCall; +use sp_core::{ + crypto::{AccountId32, Ss58Codec}, + sr25519, Bytes, Encode, Pair, +}; +use sp_runtime::MultiAddress; use std::process::ExitCode; +use substrate_api_client::ac_primitives::{AssetRuntimeConfig, ExtrinsicSigner}; +fn main() -> Result { + let alice: sr25519::Pair = Pair::from_string( + "0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a", + None, + ) + .unwrap(); -#[no_mangle] -pub extern "C" fn add(lhs: i32, rhs: i32) -> i32 { - if lhs % 2 == 0 { - lhs + rhs - } else { - lhs - rhs - } -} + let bob_account: AccountId32 = + sr25519::Public::from_ss58check("5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty") + .unwrap() + .into(); + let bob = MultiAddress::Id(bob_account); + let es_converted: ExtrinsicSigner = alice.clone().into(); + let es_new = ExtrinsicSigner::::new(alice.clone()); + assert_eq!(es_converted.signer().public(), es_new.signer().public()); -fn main() -> Result { - assert!(5 == 5, "x wasn't true!"); - //panic!("x wasn't true!"); - Err(5) - //Ok(ExitCode::from(1)) + let call1 = RuntimeCall::Balances(BalancesCall::force_transfer { + source: bob.clone(), + dest: bob.clone(), + value: 10, + }); + let call2 = RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: bob.clone(), + value: 2000, + }); + let call3 = + RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: bob, value: 1000 }); + + let _xt1: Bytes = UncheckedExtrinsic::new_unsigned(call1).encode().into(); + let _xt2: Bytes = UncheckedExtrinsic::new_unsigned(call2).encode().into(); + let _xt3: Bytes = UncheckedExtrinsic::new_unsigned(call3).encode().into(); + /* + let recipients_extrinsic_address: ExtrinsicAddressOf = + bob_account.clone().into(); + + //let recipient = AccountKeyring::Bob.to_account_id(); + //assert!(4 == 5, "x wasn't true!"); + let spec_version = 1; + let transaction_version = 2; + let genesis_hash = H256::zero(); + //let metadata = Metadata::new(); + let signer_nonce = 3; + println!("[+] Alice's Account Nonce is {}", signer_nonce); + + // Construct an extrinsic using only functionality available in no_std + let xt = { + let extrinsic_params = ::ExtrinsicParams::new( + spec_version, + transaction_version, + signer_nonce, + genesis_hash, + additional_extrinsic_params, + ); + + let call = compose_call!( + metadata, + "Balances", + "transfer_allow_death", + recipients_extrinsic_address, + Compact(4u32) + ) + .unwrap(); + compose_extrinsic_offline!(extrinsic_signer, call, extrinsic_params) + }; + */ + Ok(ExitCode::from(0)) } From 341727e13ebc6045096d687e45a13985837062ad Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 11 Jun 2024 07:51:54 +0200 Subject: [PATCH 12/18] Working on example --- examples/wasm/examples/wasm_example.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/wasm/examples/wasm_example.rs b/examples/wasm/examples/wasm_example.rs index c9ed99407..2ad49f383 100644 --- a/examples/wasm/examples/wasm_example.rs +++ b/examples/wasm/examples/wasm_example.rs @@ -12,13 +12,15 @@ */ //! Example that shows how to detect a runtime update and afterwards update the metadata. -use kitchensink_runtime::{RuntimeCall, UncheckedExtrinsic}; +//use kitchensink_runtime::RuntimeCall; +//use kitchensink_runtime::constants::currency::DOLLARS; pub use pallet_balances::Call as BalancesCall; use sp_core::{ crypto::{AccountId32, Ss58Codec}, sr25519, Bytes, Encode, Pair, }; use sp_runtime::MultiAddress; +pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; use std::process::ExitCode; use substrate_api_client::ac_primitives::{AssetRuntimeConfig, ExtrinsicSigner}; fn main() -> Result { @@ -32,12 +34,12 @@ fn main() -> Result { sr25519::Public::from_ss58check("5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty") .unwrap() .into(); - let bob = MultiAddress::Id(bob_account); + let bob: MultiAddress = MultiAddress::Id(bob_account); let es_converted: ExtrinsicSigner = alice.clone().into(); let es_new = ExtrinsicSigner::::new(alice.clone()); assert_eq!(es_converted.signer().public(), es_new.signer().public()); - let call1 = RuntimeCall::Balances(BalancesCall::force_transfer { + /*let call1 = RuntimeCall::Balances(BalancesCall::force_transfer { source: bob.clone(), dest: bob.clone(), value: 10, @@ -51,7 +53,7 @@ fn main() -> Result { let _xt1: Bytes = UncheckedExtrinsic::new_unsigned(call1).encode().into(); let _xt2: Bytes = UncheckedExtrinsic::new_unsigned(call2).encode().into(); - let _xt3: Bytes = UncheckedExtrinsic::new_unsigned(call3).encode().into(); + let _xt3: Bytes = UncheckedExtrinsic::new_unsigned(call3).encode().into();*/ /* let recipients_extrinsic_address: ExtrinsicAddressOf = bob_account.clone().into(); From 50ea0c2c2b5e7764b55a38c6cd389c6e93389f26 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 11 Jun 2024 11:21:30 +0200 Subject: [PATCH 13/18] Implement functionality --- src/extrinsic/balances.rs | 21 ++++++++++ .../async/examples/dispatch_errors_tests.rs | 10 +++-- .../async/examples/pallet_balances_tests.rs | 41 ++++++++++++++++++- 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/extrinsic/balances.rs b/src/extrinsic/balances.rs index 709a9d816..ebb4a2c57 100644 --- a/src/extrinsic/balances.rs +++ b/src/extrinsic/balances.rs @@ -30,11 +30,15 @@ use codec::{Compact, Encode}; pub const BALANCES_MODULE: &str = "Balances"; pub const TRANSFER_ALLOW_DEATH: &str = "transfer_allow_death"; +pub const TRANSFER_KEEP_ALIVE: &str = "transfer_keep_alive"; pub const FORCE_SET_BALANCE: &str = "force_set_balance"; /// Call for a balance transfer. pub type TransferAllowDeathCall = (CallIndex, Address, Compact); +/// Call for a balance transfer. +pub type TransferKeepAliveCall = (CallIndex, Address, Compact); + /// Call to the balance of an account. pub type ForceSetBalanceCall = (CallIndex, Address, Compact); @@ -52,6 +56,14 @@ pub trait BalancesExtrinsics { amount: Self::Balance, ) -> Option>>; + /// Transfer some liquid free balance to another account. + #[allow(clippy::type_complexity)] + async fn balance_transfer_keep_alive( + &self, + to: Self::Address, + amount: Self::Balance, + ) -> Option>>; + /// Set the balances of a given account. #[allow(clippy::type_complexity)] async fn balance_force_set_balance( @@ -85,6 +97,15 @@ where compose_extrinsic!(self, BALANCES_MODULE, TRANSFER_ALLOW_DEATH, to, Compact(amount)) } + #[allow(clippy::type_complexity)] + async fn balance_transfer_keep_alive( + &self, + to: Self::Address, + amount: Self::Balance, + ) -> Option>> { + compose_extrinsic!(self, BALANCES_MODULE, TRANSFER_KEEP_ALIVE, to, Compact(amount)) + } + async fn balance_force_set_balance( &self, who: Self::Address, diff --git a/testing/async/examples/dispatch_errors_tests.rs b/testing/async/examples/dispatch_errors_tests.rs index 0ebc516b7..c1ab12e88 100644 --- a/testing/async/examples/dispatch_errors_tests.rs +++ b/testing/async/examples/dispatch_errors_tests.rs @@ -20,7 +20,7 @@ use sp_keyring::AccountKeyring; use sp_runtime::MultiAddress; use substrate_api_client::{ ac_primitives::AssetRuntimeConfig, extrinsic::BalancesExtrinsics, rpc::JsonrpseeClient, Api, - Error, GetAccountInformation, SubmitAndWatch, XtStatus, + Error, GetAccountInformation, GetBalance, SubmitAndWatch, XtStatus, }; #[tokio::main] @@ -59,10 +59,10 @@ async fn main() { assert!(report.block_hash.is_some()); assert!(report.events.is_some()); assert!(format!("{dispatch_error:?}").contains("BadOrigin")); + println!("[+] BadOrigin error: Bob can't force set balance"); }, _ => panic!("Expected Failed Extrinisc Error"), } - println!("[+] BadOrigin error: Bob can't force set balance"); //BelowMinimum api.set_signer(alice_signer.into()); @@ -80,5 +80,9 @@ async fn main() { }, _ => panic!("Expected Failed Extrinisc Error"), } - println!("[+] BelowMinimum error: balance (999999) is below the existential deposit"); + let existential_deposit = api.get_existential_deposit().await.unwrap(); + println!( + "[+] BelowMinimum error: balance (999999) is below the existential deposit ({})", + &existential_deposit + ); } diff --git a/testing/async/examples/pallet_balances_tests.rs b/testing/async/examples/pallet_balances_tests.rs index 0eae6abca..cfb6b1039 100644 --- a/testing/async/examples/pallet_balances_tests.rs +++ b/testing/async/examples/pallet_balances_tests.rs @@ -15,15 +15,52 @@ //! Tests for the pallet balances interface functions. +use sp_core::H256; +use sp_keyring::AccountKeyring; +use sp_runtime::MultiAddress; use substrate_api_client::{ - ac_primitives::AssetRuntimeConfig, rpc::JsonrpseeClient, Api, GetBalance, + ac_primitives::AssetRuntimeConfig, extrinsic::BalancesExtrinsics, rpc::JsonrpseeClient, Api, + Error, GetAccountInformation, GetBalance, SubmitAndWatch, XtStatus, }; #[tokio::main] async fn main() { // Setup let client = JsonrpseeClient::with_default_url().await.unwrap(); - let api = Api::::new(client).await.unwrap(); + let mut api = Api::::new(client).await.unwrap(); let _ed = api.get_existential_deposit().await.unwrap(); + + let alice_signer = AccountKeyring::Alice.pair(); + + let alice = AccountKeyring::Alice.to_account_id(); + let balance_of_alice = api.get_account_data(&alice).await.unwrap().unwrap().free; + println!("[+] Alice's Free Balance is is {}\n", balance_of_alice); + + let one = AccountKeyring::One.to_account_id(); + + //BadOrigin + api.set_signer(alice_signer.into()); + //Can only be called by root + let xt = api + .balance_force_set_balance(MultiAddress::Id(alice.clone()), 100000000000000000) + .await + .unwrap(); + + let result = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await; + match result { + Err(Error::FailedExtrinsic(extrinsic_error)) => { + let dispatch_error = extrinsic_error.dispatch_error(); + let report = extrinsic_error.get_report::().unwrap(); + assert!(report.block_hash.is_some()); + assert!(report.events.is_some()); + assert!(format!("{dispatch_error:?}").contains("BadOrigin")); + println!("{dispatch_error:?}"); + println!("[+] BadOrigin error: Bob can't force set balance"); + }, + _ => panic!("Expected Failed Extrinisc Error"), + } + + let balance_of_one = api.get_account_data(&one).await.unwrap().unwrap_or_default().free; + println!("[+] One's Free Balance is {}\n", balance_of_one); } From 8955962eb96db9d2545ee1971df1a85775ef9208 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 11 Jun 2024 11:59:13 +0200 Subject: [PATCH 14/18] Improve example --- examples/wasm/examples/wasm_example.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/examples/wasm/examples/wasm_example.rs b/examples/wasm/examples/wasm_example.rs index 2ad49f383..b026cfeaf 100644 --- a/examples/wasm/examples/wasm_example.rs +++ b/examples/wasm/examples/wasm_example.rs @@ -34,32 +34,34 @@ fn main() -> Result { sr25519::Public::from_ss58check("5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty") .unwrap() .into(); - let bob: MultiAddress = MultiAddress::Id(bob_account); + let _bob: MultiAddress = MultiAddress::Id(bob_account); let es_converted: ExtrinsicSigner = alice.clone().into(); let es_new = ExtrinsicSigner::::new(alice.clone()); assert_eq!(es_converted.signer().public(), es_new.signer().public()); + let extrinsic = UncheckedExtrinsic::from_bytes(&[]); + match extrinsic { + Ok(_) => panic!("Extrinsic should be invalid"), + Err(_) => (), + } + //let _xt1: Bytes = extrinsic.unwrap().encode().into(); + + //assert_eq!(4, 5); + /*let call1 = RuntimeCall::Balances(BalancesCall::force_transfer { source: bob.clone(), dest: bob.clone(), value: 10, }); - let call2 = RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: bob.clone(), - value: 2000, - }); - let call3 = - RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: bob, value: 1000 }); - let _xt1: Bytes = UncheckedExtrinsic::new_unsigned(call1).encode().into(); - let _xt2: Bytes = UncheckedExtrinsic::new_unsigned(call2).encode().into(); - let _xt3: Bytes = UncheckedExtrinsic::new_unsigned(call3).encode().into();*/ + */ + /* let recipients_extrinsic_address: ExtrinsicAddressOf = bob_account.clone().into(); //let recipient = AccountKeyring::Bob.to_account_id(); - //assert!(4 == 5, "x wasn't true!"); + let spec_version = 1; let transaction_version = 2; let genesis_hash = H256::zero(); From b203ac8a4e1cd75ebba4726a7479bac822165f0d Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 11 Jun 2024 13:01:57 +0200 Subject: [PATCH 15/18] Cleanup example --- Cargo.lock | 3 -- examples/wasm/Cargo.toml | 5 --- examples/wasm/examples/wasm_example.rs | 56 +++----------------------- 3 files changed, 5 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c0447f11..53936dc01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,10 +65,7 @@ dependencies = [ name = "ac-examples-wasm" version = "0.5.0" dependencies = [ - "frame-metadata 16.0.0", - "kitchensink-runtime", "pallet-balances", - "parity-scale-codec", "sp-core", "sp-runtime", "substrate-api-client", diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 58a7c3d03..e620f1e94 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -5,12 +5,7 @@ license = "Apache-2.0" edition = "2021" [dev-dependencies] -frame-metadata = { version = "16.0", default-features = false, features = ["current", "serde_full", "decode"] } sp-core = { default-features = false, features = ["full_crypto", "serde"], git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" } sp-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" } - substrate-api-client = { default-features = false, path = "../..", version = "0.17" } - pallet-balances = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" } -kitchensink-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "master" } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ['derive'] } diff --git a/examples/wasm/examples/wasm_example.rs b/examples/wasm/examples/wasm_example.rs index b026cfeaf..57a6a7cc1 100644 --- a/examples/wasm/examples/wasm_example.rs +++ b/examples/wasm/examples/wasm_example.rs @@ -1,5 +1,5 @@ /* - Copyright 2023 Supercomputing Systems AG + Copyright 2024 Supercomputing Systems AG Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -11,18 +11,18 @@ limitations under the License. */ -//! Example that shows how to detect a runtime update and afterwards update the metadata. -//use kitchensink_runtime::RuntimeCall; -//use kitchensink_runtime::constants::currency::DOLLARS; +//! Example that some basic functions that can be executed in WebAssembly. + pub use pallet_balances::Call as BalancesCall; use sp_core::{ crypto::{AccountId32, Ss58Codec}, - sr25519, Bytes, Encode, Pair, + sr25519, Pair, }; use sp_runtime::MultiAddress; pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; use std::process::ExitCode; use substrate_api_client::ac_primitives::{AssetRuntimeConfig, ExtrinsicSigner}; + fn main() -> Result { let alice: sr25519::Pair = Pair::from_string( "0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a", @@ -44,51 +44,5 @@ fn main() -> Result { Ok(_) => panic!("Extrinsic should be invalid"), Err(_) => (), } - //let _xt1: Bytes = extrinsic.unwrap().encode().into(); - - //assert_eq!(4, 5); - - /*let call1 = RuntimeCall::Balances(BalancesCall::force_transfer { - source: bob.clone(), - dest: bob.clone(), - value: 10, - }); - let _xt1: Bytes = UncheckedExtrinsic::new_unsigned(call1).encode().into(); - */ - - /* - let recipients_extrinsic_address: ExtrinsicAddressOf = - bob_account.clone().into(); - - //let recipient = AccountKeyring::Bob.to_account_id(); - - let spec_version = 1; - let transaction_version = 2; - let genesis_hash = H256::zero(); - //let metadata = Metadata::new(); - let signer_nonce = 3; - println!("[+] Alice's Account Nonce is {}", signer_nonce); - - // Construct an extrinsic using only functionality available in no_std - let xt = { - let extrinsic_params = ::ExtrinsicParams::new( - spec_version, - transaction_version, - signer_nonce, - genesis_hash, - additional_extrinsic_params, - ); - - let call = compose_call!( - metadata, - "Balances", - "transfer_allow_death", - recipients_extrinsic_address, - Compact(4u32) - ) - .unwrap(); - compose_extrinsic_offline!(extrinsic_signer, call, extrinsic_params) - }; - */ Ok(ExitCode::from(0)) } From d00c01516bb65b74143cf5dd542da52691c889c2 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Tue, 11 Jun 2024 13:06:11 +0200 Subject: [PATCH 16/18] Revert "Implement functionality" This reverts commit 69005747926830e37e97af08479d84f51f26c9b1. --- src/extrinsic/balances.rs | 21 ---------- .../async/examples/dispatch_errors_tests.rs | 10 ++--- .../async/examples/pallet_balances_tests.rs | 41 +------------------ 3 files changed, 5 insertions(+), 67 deletions(-) diff --git a/src/extrinsic/balances.rs b/src/extrinsic/balances.rs index ebb4a2c57..709a9d816 100644 --- a/src/extrinsic/balances.rs +++ b/src/extrinsic/balances.rs @@ -30,15 +30,11 @@ use codec::{Compact, Encode}; pub const BALANCES_MODULE: &str = "Balances"; pub const TRANSFER_ALLOW_DEATH: &str = "transfer_allow_death"; -pub const TRANSFER_KEEP_ALIVE: &str = "transfer_keep_alive"; pub const FORCE_SET_BALANCE: &str = "force_set_balance"; /// Call for a balance transfer. pub type TransferAllowDeathCall = (CallIndex, Address, Compact); -/// Call for a balance transfer. -pub type TransferKeepAliveCall = (CallIndex, Address, Compact); - /// Call to the balance of an account. pub type ForceSetBalanceCall = (CallIndex, Address, Compact); @@ -56,14 +52,6 @@ pub trait BalancesExtrinsics { amount: Self::Balance, ) -> Option>>; - /// Transfer some liquid free balance to another account. - #[allow(clippy::type_complexity)] - async fn balance_transfer_keep_alive( - &self, - to: Self::Address, - amount: Self::Balance, - ) -> Option>>; - /// Set the balances of a given account. #[allow(clippy::type_complexity)] async fn balance_force_set_balance( @@ -97,15 +85,6 @@ where compose_extrinsic!(self, BALANCES_MODULE, TRANSFER_ALLOW_DEATH, to, Compact(amount)) } - #[allow(clippy::type_complexity)] - async fn balance_transfer_keep_alive( - &self, - to: Self::Address, - amount: Self::Balance, - ) -> Option>> { - compose_extrinsic!(self, BALANCES_MODULE, TRANSFER_KEEP_ALIVE, to, Compact(amount)) - } - async fn balance_force_set_balance( &self, who: Self::Address, diff --git a/testing/async/examples/dispatch_errors_tests.rs b/testing/async/examples/dispatch_errors_tests.rs index c1ab12e88..0ebc516b7 100644 --- a/testing/async/examples/dispatch_errors_tests.rs +++ b/testing/async/examples/dispatch_errors_tests.rs @@ -20,7 +20,7 @@ use sp_keyring::AccountKeyring; use sp_runtime::MultiAddress; use substrate_api_client::{ ac_primitives::AssetRuntimeConfig, extrinsic::BalancesExtrinsics, rpc::JsonrpseeClient, Api, - Error, GetAccountInformation, GetBalance, SubmitAndWatch, XtStatus, + Error, GetAccountInformation, SubmitAndWatch, XtStatus, }; #[tokio::main] @@ -59,10 +59,10 @@ async fn main() { assert!(report.block_hash.is_some()); assert!(report.events.is_some()); assert!(format!("{dispatch_error:?}").contains("BadOrigin")); - println!("[+] BadOrigin error: Bob can't force set balance"); }, _ => panic!("Expected Failed Extrinisc Error"), } + println!("[+] BadOrigin error: Bob can't force set balance"); //BelowMinimum api.set_signer(alice_signer.into()); @@ -80,9 +80,5 @@ async fn main() { }, _ => panic!("Expected Failed Extrinisc Error"), } - let existential_deposit = api.get_existential_deposit().await.unwrap(); - println!( - "[+] BelowMinimum error: balance (999999) is below the existential deposit ({})", - &existential_deposit - ); + println!("[+] BelowMinimum error: balance (999999) is below the existential deposit"); } diff --git a/testing/async/examples/pallet_balances_tests.rs b/testing/async/examples/pallet_balances_tests.rs index cfb6b1039..0eae6abca 100644 --- a/testing/async/examples/pallet_balances_tests.rs +++ b/testing/async/examples/pallet_balances_tests.rs @@ -15,52 +15,15 @@ //! Tests for the pallet balances interface functions. -use sp_core::H256; -use sp_keyring::AccountKeyring; -use sp_runtime::MultiAddress; use substrate_api_client::{ - ac_primitives::AssetRuntimeConfig, extrinsic::BalancesExtrinsics, rpc::JsonrpseeClient, Api, - Error, GetAccountInformation, GetBalance, SubmitAndWatch, XtStatus, + ac_primitives::AssetRuntimeConfig, rpc::JsonrpseeClient, Api, GetBalance, }; #[tokio::main] async fn main() { // Setup let client = JsonrpseeClient::with_default_url().await.unwrap(); - let mut api = Api::::new(client).await.unwrap(); + let api = Api::::new(client).await.unwrap(); let _ed = api.get_existential_deposit().await.unwrap(); - - let alice_signer = AccountKeyring::Alice.pair(); - - let alice = AccountKeyring::Alice.to_account_id(); - let balance_of_alice = api.get_account_data(&alice).await.unwrap().unwrap().free; - println!("[+] Alice's Free Balance is is {}\n", balance_of_alice); - - let one = AccountKeyring::One.to_account_id(); - - //BadOrigin - api.set_signer(alice_signer.into()); - //Can only be called by root - let xt = api - .balance_force_set_balance(MultiAddress::Id(alice.clone()), 100000000000000000) - .await - .unwrap(); - - let result = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await; - match result { - Err(Error::FailedExtrinsic(extrinsic_error)) => { - let dispatch_error = extrinsic_error.dispatch_error(); - let report = extrinsic_error.get_report::().unwrap(); - assert!(report.block_hash.is_some()); - assert!(report.events.is_some()); - assert!(format!("{dispatch_error:?}").contains("BadOrigin")); - println!("{dispatch_error:?}"); - println!("[+] BadOrigin error: Bob can't force set balance"); - }, - _ => panic!("Expected Failed Extrinisc Error"), - } - - let balance_of_one = api.get_account_data(&one).await.unwrap().unwrap_or_default().free; - println!("[+] One's Free Balance is {}\n", balance_of_one); } From 4d22b57908d80f3f3d5980ecec8d9f98d4ce9373 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Wed, 12 Jun 2024 08:13:54 +0200 Subject: [PATCH 17/18] Add test documentation --- examples/wasm/examples/wasm_example.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/wasm/examples/wasm_example.rs b/examples/wasm/examples/wasm_example.rs index 57a6a7cc1..d25262393 100644 --- a/examples/wasm/examples/wasm_example.rs +++ b/examples/wasm/examples/wasm_example.rs @@ -24,6 +24,8 @@ use std::process::ExitCode; use substrate_api_client::ac_primitives::{AssetRuntimeConfig, ExtrinsicSigner}; fn main() -> Result { + // This test is not yet very sophisticated and not exhaustive. + // Still it shows how some basic data structures can be constructed and used. let alice: sr25519::Pair = Pair::from_string( "0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a", None, From b4ad5d02d244e46ea09fdc0cffd60baccdf5b346 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger Date: Thu, 4 Jul 2024 09:19:36 +0200 Subject: [PATCH 18/18] Incorporate review feedback --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1cd8b331..55d4f55b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -244,6 +244,7 @@ jobs: nc -z -v 127.0.0.1 9944 chmod +x ${{ matrix.example }} ./${{ matrix.example }} + wasm_examples: runs-on: ${{ matrix.os }} needs: build @@ -271,7 +272,7 @@ jobs: merge: runs-on: ubuntu-latest - needs: examples + needs: [examples, wasm_examples] steps: - name: Merge Artifacts uses: actions/upload-artifact/merge@v4