diff --git a/Cargo.lock b/Cargo.lock index 7f9cbc8..6f05f23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1015,6 +1015,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "derive-where" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "derive_more" version = "1.0.0" @@ -1851,6 +1862,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hmac" version = "0.8.1" @@ -3007,6 +3024,7 @@ dependencies = [ "serde", "serde_json", "sp-core", + "staging-xcm", "tracing", "tracing-subscriber", ] @@ -4156,6 +4174,28 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "staging-xcm" +version = "16.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0126278d7fc6d7dec55e5a109f838bbf401dd084aecf2597e4e11ea07515a0a" +dependencies = [ + "array-bytes", + "bounded-collections", + "derive-where", + "environmental", + "frame-support", + "hex-literal", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime", + "sp-weights", + "xcm-procedural", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -4972,6 +5012,18 @@ dependencies = [ "tap", ] +[[package]] +name = "xcm-procedural" +version = "11.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d3d21c65cbf847ae0b1a8e6411b614d269d3108c6c649b039bffcf225e89aa4" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 6f24267..9e7828a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ pallet-sudo = { version = "40.0.0", default-features = false } pallet-timestamp = { version = "39.0.0", default-features = false } pallet-transaction-payment = { version = "40.0.0", default-features = false } pallet-transaction-payment-rpc-runtime-api = { version = "40.0.0", default-features = false } +xcm = { version = "16.2.0", default-features = false, package = "staging-xcm" } # genesis builder that allows us to interacto with runtime genesis config sp-genesis-builder = { version = "0.17.0", default-features = false } diff --git a/pvq-test-runner/Cargo.toml b/pvq-test-runner/Cargo.toml index 3729175..c424953 100644 --- a/pvq-test-runner/Cargo.toml +++ b/pvq-test-runner/Cargo.toml @@ -24,4 +24,5 @@ pvq-extension-fungibles = { workspace = true, features = ["std"] } pvq-extension-swap = { workspace = true, features = ["std"] } pvq-primitives = { workspace = true, features = ["std"] } +xcm = { workspace = true, features = ["std"] } polkavm = { workspace = true, features = ["std"] } diff --git a/pvq-test-runner/src/bin/pvq-test-runner.rs b/pvq-test-runner/src/bin/pvq-test-runner.rs index e8e4a0c..b174480 100644 --- a/pvq-test-runner/src/bin/pvq-test-runner.rs +++ b/pvq-test-runner/src/bin/pvq-test-runner.rs @@ -1,4 +1,5 @@ use clap::Parser; +use sp_core::hexdisplay::HexDisplay; use tracing_subscriber::prelude::*; use pvq_test_runner::TestRunner; @@ -9,6 +10,35 @@ struct Cli { /// Path to the PolkaVM program to execute #[arg(short, long)] program: std::path::PathBuf, + + /// Chain to use for execution + #[arg(short, long, value_enum)] + chain: Chain, + + /// Print test data and expected result without executing the test + #[arg(long)] + print_data: bool, + + /// Entrypoint index to use for execution + #[arg(short, long)] + entrypoint_idx: u8, +} + +#[derive(clap::ValueEnum, Clone, Debug)] +enum Chain { + Poc, + Acala, + Ah, +} + +impl std::fmt::Display for Chain { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Chain::Poc => write!(f, "poc"), + Chain::Acala => write!(f, "acala"), + Chain::Ah => write!(f, "ah"), + } + } } fn main() { @@ -25,10 +55,23 @@ fn main() { let cli = Cli::parse(); - let blob = std::fs::read(&cli.program).expect("Failed to read program"); let program_str = cli.program.to_string_lossy(); + let input_data = TestRunner::prepare_input_data(&program_str, &cli.chain.to_string()); + let expected_result = TestRunner::expected_result(&program_str, &cli.chain.to_string(), cli.entrypoint_idx); + + if cli.print_data { + println!("=== Test Data ==="); + println!("Program: {}", program_str); + println!("Chain: {}", cli.chain); + println!("Input data (hex): {}", HexDisplay::from(&input_data)); + println!("Input data (bytes): {:?}", input_data); + println!("Expected result (hex): {}", HexDisplay::from(&expected_result)); + println!("Expected result (bytes): {:?}", expected_result); + return; + } + + let blob = std::fs::read(&cli.program).expect("Failed to read program"); - let input_data = TestRunner::prepare_input_data(&program_str); tracing::info!("Input data: {:?}", input_data); let mut runner = TestRunner::new(); diff --git a/pvq-test-runner/src/lib.rs b/pvq-test-runner/src/lib.rs index e9f1b2a..704818c 100644 --- a/pvq-test-runner/src/lib.rs +++ b/pvq-test-runner/src/lib.rs @@ -1,7 +1,11 @@ -use parity_scale_codec::Encode; +use parity_scale_codec::{Decode, Encode}; use pvq_extension::{extensions_impl, ExtensionsExecutor, InvokeSource}; +use pvq_primitives::PvqResult; use sp_core::crypto::{AccountId32, Ss58Codec}; use sp_core::hexdisplay::HexDisplay; +use xcm::v5::Junction::{GeneralIndex, PalletInstance}; +use xcm::v5::Junctions::Here; +use xcm::v5::Location; #[derive(Encode)] #[allow(non_camel_case_types)] @@ -42,7 +46,7 @@ pub mod extensions { #[extensions_impl::extension] impl pvq_extension_swap::extension::ExtensionSwap for ExtensionsImpl { type AssetId = Vec; - type Balance = u128; + type Balance = u64; fn quote_price_tokens_for_exact_tokens( _asset1: Self::AssetId, _asset2: Self::AssetId, @@ -84,47 +88,58 @@ impl TestRunner { } } - pub fn prepare_input_data(program_path: &str) -> Vec { + pub fn prepare_input_data(program_path: &str, chain: &str) -> Vec { let mut input_data = Vec::new(); if program_path.contains("sum-balance") { - input_data.extend_from_slice(&[0u8]); - input_data.extend_from_slice(&21u32.encode()); - let alice_account: [u8; 32] = - AccountId32::from_ss58check("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") - .expect("Failed to decode Alice's address") - .into(); - input_data.extend_from_slice(&vec![alice_account].encode()); + if chain == "poc" { + input_data.extend_from_slice(&[0u8]); + input_data.extend_from_slice(&21u32.encode()); + let alice_account: [u8; 32] = + AccountId32::from_ss58check("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") + .expect("Failed to decode Alice's address") + .into(); + input_data.extend_from_slice(&vec![alice_account].encode()); + } } else if program_path.contains("total-supply") { - input_data.extend_from_slice(&[0u8]); - input_data.extend_from_slice(&21u32.encode()); - } else if program_path.contains("transparent-call") { - input_data.extend_from_slice(&4071833530116166512u64.encode()); - let alice_account = AccountId32::from_ss58check("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY") - .expect("Failed to decode Alice's address"); - input_data.extend_from_slice( - &ExtensionFungiblesFunctions::balance { - asset: 21u32, - who: alice_account.into(), - } - .encode(), - ); - } else if program_path.contains("liquidity-pool") { - let asset1 = u32::encode(&21); - let asset2 = u32::encode(&22); - input_data.extend_from_slice(&asset1.encode()); - input_data.extend_from_slice(&asset2.encode()); + if chain == "poc" { + input_data.extend_from_slice(&[0u8]); + input_data.extend_from_slice(&21u32.encode()); + } } else if program_path.contains("swap-info") { - input_data.extend_from_slice(&[0u8]); - let asset1 = u32::encode(&21); - let asset2 = u32::encode(&22); - input_data.extend_from_slice(&asset1.encode()); - input_data.extend_from_slice(&asset2.encode()); + if chain == "ah" { + input_data.extend_from_slice(&[2u8]); + let asset1 = Location::parent().encode(); + let asset2 = Location::new(0, (PalletInstance(50), GeneralIndex(2511))).encode(); + input_data.extend_from_slice(&asset1.encode()); + input_data.extend_from_slice(&asset2.encode()); + } } tracing::info!("Input data (hex): {}", HexDisplay::from(&input_data)); + tracing::info!("Using chain: {}", chain); input_data } + pub fn expected_result(program_path: &str, chain: &str, entrypoint_idx: u8) -> Vec { + // TODO: add more entrypoints + if program_path.contains("swap-info") { + if chain == "poc" { + return Vec::new(); + } else if chain == "ah" { + if entrypoint_idx == 2 { + return (10_235_709_412_325u128, 12_117_819_770_919u128).encode(); + } + } + } else if program_path.contains("sum-balance") { + return Vec::new(); + } else if program_path.contains("total-supply") { + return Vec::new(); + } + + // Default empty result + Vec::new() + } + pub fn execute_program(&mut self, program_blob: &[u8], input_data: &[u8]) -> pvq_primitives::PvqResult { let (result, _) = self.executor.execute(program_blob, input_data, None); result