diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000000..acb41063fa --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,34 @@ +name: Tests +on: + push: + branches: + - '**' + tags-ignore: + - v[0-9]+.[0-9]+.[0-9]+* + workflow_dispatch: +jobs: + run-tests: + runs-on: ubuntu-latest + steps: + - name: Free disk space + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf "/usr/local/share/boost" + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + df -h + + - name: Checkout the source code + uses: actions/checkout@v3 + + - name: Install deps + run: sudo apt -y install protobuf-compiler + + - name: Install & display rust toolchain + run: rustup show + + - name: Check targets are installed correctly + run: rustup target list --installed + + - name: Runtime integration tests + run: make test-runtimes diff --git a/Cargo.lock b/Cargo.lock index 4a6d329249..2f53e93477 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4246,6 +4246,24 @@ dependencies = [ "num-traits", ] +[[package]] +name = "integration-tests" +version = "0.1.0" +dependencies = [ + "astar-runtime", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-dapps-staking", + "pallet-proxy", + "pallet-utility", + "shibuya-runtime", + "shiden-runtime", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "interceptor" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index bc5746b6d4..f53d14221c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "runtime/shiden", "runtime/shibuya", "tests/xcm-simulator", + "tests/integration", ] exclude = ["vendor"] diff --git a/Makefile b/Makefile index ebea3495fb..19c89747e5 100644 --- a/Makefile +++ b/Makefile @@ -2,3 +2,9 @@ runtime-upgrade-test: cargo build -p $(runtime)-runtime --release --locked cd tests/e2e && yarn --frozen-lockfile && yarn test:runtime-upgrade-$(runtime) + +.PHONY: test-runtimes +test-runtimes: + SKIP_WASM_BUILD= cargo test -p integration-tests --features=shibuya + SKIP_WASM_BUILD= cargo test -p integration-tests --features=shiden + SKIP_WASM_BUILD= cargo test -p integration-tests --features=astar diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index ccb966cd6d..c82cd4373b 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -1950,257 +1950,3 @@ cumulus_pallet_parachain_system::register_validate_block! { BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, CheckInherents = CheckInherents, } - -#[cfg(test)] -mod proxy_test { - use super::*; - use crate::sp_api_hidden_includes_construct_runtime::hidden_include::traits::Hooks; - use frame_support::*; - use pallet_balances::Call as BalancesCall; - use pallet_dapps_staking as DappStakingCall; - use pallet_proxy::Event as ProxyEvent; - use pallet_utility::{Call as UtilityCall, Event as UtilityEvent}; - use sp_runtime::AccountId32; - - type SystemError = frame_system::Error; - - const INITIAL_AMOUNT: u128 = 100_000 * SBY; - const ALICE: AccountId32 = AccountId32::new([1_u8; 32]); - const BOB: AccountId32 = AccountId32::new([2_u8; 32]); - const CAT: AccountId32 = AccountId32::new([3_u8; 32]); - - pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (ALICE, INITIAL_AMOUNT), - (BOB, INITIAL_AMOUNT), - (CAT, INITIAL_AMOUNT), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext - } - - fn last_events(n: usize) -> Vec { - frame_system::Pallet::::events() - .into_iter() - .rev() - .take(n) - .rev() - .map(|e| e.event) - .collect() - } - - fn expect_events(e: Vec) { - assert_eq!(last_events(e.len()), e); - } - - pub fn run_to_block(n: u32) { - while System::block_number() < n { - as Hooks>::on_finalize( - System::block_number(), - ); - System::set_block_number(System::block_number() + 1); - as Hooks>::on_initialize( - System::block_number(), - ); - } - } - - #[test] - fn test_utility_call_pass_for_any() { - new_test_ext().execute_with(|| { - // Any proxy should be allowed to make balance transfer call - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(ALICE), - sp_runtime::MultiAddress::Id(BOB), - ProxyType::Any, - 0 - )); - - // Preparing Utility call - let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { - dest: sp_runtime::MultiAddress::Id(CAT), - value: 100_000_000_000, - }); - let inner = Box::new(transfer_call); - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { - calls: vec![*inner], - })); - - // Utility call passed through filter - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(ALICE), - None, - call.clone() - )); - expect_events(vec![ - UtilityEvent::BatchCompleted.into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - }); - } - #[test] - fn test_utility_call_pass_for_balances() { - new_test_ext().execute_with(|| { - // Balances proxy should be allowed to make balance transfer call - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(ALICE), - sp_runtime::MultiAddress::Id(BOB), - ProxyType::Balances, - 0 - )); - - // Preparing Utility call - let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { - dest: sp_runtime::MultiAddress::Id(CAT), - value: 100_000_000_000, - }); - let inner = Box::new(transfer_call); - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { - calls: vec![*inner], - })); - - // Utility call passed through filter - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(ALICE), - None, - call.clone() - )); - expect_events(vec![ - UtilityEvent::BatchCompleted.into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - }); - } - - #[test] - fn test_utility_call_fail_non_transfer() { - new_test_ext().execute_with(|| { - // NonTransfer proxy shouldn't be allowed to make balance transfer call - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(ALICE), - sp_runtime::MultiAddress::Id(BOB), - ProxyType::NonTransfer, - 0 - )); - - // Preparing Utility call - let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { - dest: sp_runtime::MultiAddress::Id(CAT), - value: 100_000_000_000, - }); - let inner = Box::new(transfer_call); - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { - calls: vec![*inner], - })); - - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(ALICE), - None, - call.clone() - )); - - // Utility call filtered out - expect_events(vec![ - UtilityEvent::BatchInterrupted { - index: 0, - error: SystemError::CallFiltered.into(), - } - .into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - }); - } - #[test] - fn test_utility_call_fail_for_dappstaking() { - new_test_ext().execute_with(|| { - // Dappstaking proxy shouldn't be allowed to make balance transfer call - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(ALICE), - sp_runtime::MultiAddress::Id(BOB), - ProxyType::DappsStaking, - 0 - )); - - // Preparing Utility call - let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { - dest: sp_runtime::MultiAddress::Id(CAT), - value: 100_000_000_000, - }); - let inner = Box::new(transfer_call); - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { - calls: vec![*inner], - })); - - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(ALICE), - None, - call.clone() - )); - // Utility call filtered out - expect_events(vec![ - UtilityEvent::BatchInterrupted { - index: 0, - error: SystemError::CallFiltered.into(), - } - .into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - }); - } - #[test] - fn test_staker_reward_claim_proxy_works() { - new_test_ext().execute_with(|| { - // Make CAT delegate for StakerRewardClaim proxy - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(CAT), - ProxyType::StakerRewardClaim, - 0 - )); - - let contract = SmartContract::Evm(H160::repeat_byte(0x01)); - let staker_reward_claim_call = - RuntimeCall::DappsStaking(DappStakingCall::Call::claim_staker { - contract_id: contract.clone(), - }); - let call = Box::new(staker_reward_claim_call); - - // contract must be registered - assert_ok!(DappsStaking::register( - RuntimeOrigin::root(), - ALICE.clone(), - contract.clone() - )); - - // some amount must be staked - assert_ok!(DappsStaking::bond_and_stake( - RuntimeOrigin::signed(BOB), - contract.clone(), - 20 * SBY - )); - run_to_block(10); - - // CAT making proxy call on behalf of staker (BOB) - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(CAT), - sp_runtime::MultiAddress::Id(BOB), - None, - call.clone() - )); - - expect_events(vec![ProxyEvent::ProxyExecuted { result: Ok(()) }.into()]); - }) - } -} diff --git a/runtime/shiden/src/lib.rs b/runtime/shiden/src/lib.rs index 15d1214411..62627801a8 100644 --- a/runtime/shiden/src/lib.rs +++ b/runtime/shiden/src/lib.rs @@ -1706,257 +1706,3 @@ cumulus_pallet_parachain_system::register_validate_block! { BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, CheckInherents = CheckInherents, } - -#[cfg(test)] -mod proxy_test { - use super::*; - use crate::sp_api_hidden_includes_construct_runtime::hidden_include::traits::Hooks; - use frame_support::*; - use pallet_balances::Call as BalancesCall; - use pallet_dapps_staking as DappStakingCall; - use pallet_proxy::Event as ProxyEvent; - use pallet_utility::{Call as UtilityCall, Event as UtilityEvent}; - use sp_runtime::AccountId32; - - type SystemError = frame_system::Error; - - const INITIAL_AMOUNT: u128 = 100_000 * SDN; - const ALICE: AccountId32 = AccountId32::new([1_u8; 32]); - const BOB: AccountId32 = AccountId32::new([2_u8; 32]); - const CAT: AccountId32 = AccountId32::new([3_u8; 32]); - - pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (ALICE, INITIAL_AMOUNT), - (BOB, INITIAL_AMOUNT), - (CAT, INITIAL_AMOUNT), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext - } - - fn last_events(n: usize) -> Vec { - frame_system::Pallet::::events() - .into_iter() - .rev() - .take(n) - .rev() - .map(|e| e.event) - .collect() - } - - fn expect_events(e: Vec) { - assert_eq!(last_events(e.len()), e); - } - - pub fn run_to_block(n: u32) { - while System::block_number() < n { - as Hooks>::on_finalize( - System::block_number(), - ); - System::set_block_number(System::block_number() + 1); - as Hooks>::on_initialize( - System::block_number(), - ); - } - } - - #[test] - fn test_utility_call_pass_for_any() { - new_test_ext().execute_with(|| { - // Any proxy should be allowed to make balance transfer call - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(ALICE), - sp_runtime::MultiAddress::Id(BOB), - ProxyType::Any, - 0 - )); - - // Preparing Utility call - let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { - dest: sp_runtime::MultiAddress::Id(CAT), - value: 100_000_000_000, - }); - let inner = Box::new(transfer_call); - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { - calls: vec![*inner], - })); - - // Utility call passed through filter - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(ALICE), - None, - call.clone() - )); - expect_events(vec![ - UtilityEvent::BatchCompleted.into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - }); - } - #[test] - fn test_utility_call_pass_for_balances() { - new_test_ext().execute_with(|| { - // Balances proxy should be allowed to make balance transfer call - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(ALICE), - sp_runtime::MultiAddress::Id(BOB), - ProxyType::Balances, - 0 - )); - - // Preparing Utility call - let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { - dest: sp_runtime::MultiAddress::Id(CAT), - value: 100_000_000_000, - }); - let inner = Box::new(transfer_call); - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { - calls: vec![*inner], - })); - - // Utility call passed through filter - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(ALICE), - None, - call.clone() - )); - expect_events(vec![ - UtilityEvent::BatchCompleted.into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - }); - } - - #[test] - fn test_utility_call_fail_non_transfer() { - new_test_ext().execute_with(|| { - // NonTransfer proxy shouldn't be allowed to make balance transfer call - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(ALICE), - sp_runtime::MultiAddress::Id(BOB), - ProxyType::NonTransfer, - 0 - )); - - // Preparing Utility call - let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { - dest: sp_runtime::MultiAddress::Id(CAT), - value: 100_000_000_000, - }); - let inner = Box::new(transfer_call); - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { - calls: vec![*inner], - })); - - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(ALICE), - None, - call.clone() - )); - - // Utility call filtered out - expect_events(vec![ - UtilityEvent::BatchInterrupted { - index: 0, - error: SystemError::CallFiltered.into(), - } - .into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - }); - } - #[test] - fn test_utility_call_fail_for_dappstaking() { - new_test_ext().execute_with(|| { - // Dappstaking proxy shouldn't be allowed to make balance transfer call - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(ALICE), - sp_runtime::MultiAddress::Id(BOB), - ProxyType::DappsStaking, - 0 - )); - - // Preparing Utility call - let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { - dest: sp_runtime::MultiAddress::Id(CAT), - value: 100_000_000_000, - }); - let inner = Box::new(transfer_call); - let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { - calls: vec![*inner], - })); - - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(ALICE), - None, - call.clone() - )); - // Utility call filtered out - expect_events(vec![ - UtilityEvent::BatchInterrupted { - index: 0, - error: SystemError::CallFiltered.into(), - } - .into(), - ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), - ]); - }); - } - #[test] - fn test_staker_reward_claim_proxy_works() { - new_test_ext().execute_with(|| { - // Make CAT delegate for StakerRewardClaim proxy - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(BOB), - sp_runtime::MultiAddress::Id(CAT), - ProxyType::StakerRewardClaim, - 0 - )); - - let contract = SmartContract::Evm(H160::repeat_byte(0x01)); - let staker_reward_claim_call = - RuntimeCall::DappsStaking(DappStakingCall::Call::claim_staker { - contract_id: contract.clone(), - }); - let call = Box::new(staker_reward_claim_call); - - // contract must be registered - assert_ok!(DappsStaking::register( - RuntimeOrigin::root(), - ALICE.clone(), - contract.clone() - )); - - // some amount must be staked - assert_ok!(DappsStaking::bond_and_stake( - RuntimeOrigin::signed(BOB), - contract.clone(), - 100 * SDN - )); - run_to_block(10); - - // CAT making proxy call on behalf of staker (BOB) - assert_ok!(Proxy::proxy( - RuntimeOrigin::signed(CAT), - sp_runtime::MultiAddress::Id(BOB), - None, - call.clone() - )); - - expect_events(vec![ProxyEvent::ProxyExecuted { result: Ok(()) }.into()]); - }) - } -} diff --git a/tests/integration/Cargo.toml b/tests/integration/Cargo.toml new file mode 100644 index 0000000000..cd4d39f289 --- /dev/null +++ b/tests/integration/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "integration-tests" +version = "0.1.0" +description = "Astar integration tests." +authors.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +# frame dependencies +frame-support = { workspace = true } +frame-system = { workspace = true } +pallet-balances = { workspace = true } +pallet-dapps-staking = { workspace = true } +pallet-proxy = { workspace = true } +pallet-utility = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } + +# runtime +astar-runtime = { path = "../../runtime/astar", optional = true } +shibuya-runtime = { path = "../../runtime/shibuya", optional = true } +shiden-runtime = { path = "../../runtime/shiden", optional = true } + +[features] +default = ["std"] +std = [] +shibuya = ["shibuya-runtime"] +shiden = ["shiden-runtime"] +astar = ["astar-runtime"] diff --git a/tests/integration/README.md b/tests/integration/README.md new file mode 100644 index 0000000000..ef17f0a341 --- /dev/null +++ b/tests/integration/README.md @@ -0,0 +1,25 @@ +# Integration tests + +## Overview + +Instead of mocks, integration tests covers tests on production runtimes, including Shibuya, Shiden and Astar. It's expected tests are added to cover major custom configurations in runtime, for instance `pallet-proxy` settings. + +## Usages + +To run integration tests for a specific runtime, for instance, Shibuya: + +```shell +cargo test -p integration-tests --features=shibuya +``` + +To run integration tests for all runtimes: + +```shell +make test-runtimes +``` + +## Development guidelines + +General imports and configures that are shared across tests should be added to `setup.rs`. When new pallets are added to runtime, their hooks need to be checked and added to `run_to_block` if needed. + +For specific tests like `pallet-proxy`, group them in one source file like `proxy.rs`. Then add the module to `lib.rs` with proper features config. diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs new file mode 100644 index 0000000000..e2c677cd30 --- /dev/null +++ b/tests/integration/src/lib.rs @@ -0,0 +1,27 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . + +//! Runtime integration tests. + +#![cfg(test)] + +#[cfg(any(feature = "shibuya", feature = "shiden", feature = "astar"))] +mod setup; + +#[cfg(any(feature = "shibuya", feature = "shiden"))] +mod proxy; diff --git a/tests/integration/src/proxy.rs b/tests/integration/src/proxy.rs new file mode 100644 index 0000000000..a59289593f --- /dev/null +++ b/tests/integration/src/proxy.rs @@ -0,0 +1,213 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . + +use crate::setup::*; + +#[test] +fn test_utility_call_pass_for_any() { + new_test_ext().execute_with(|| { + // Any proxy should be allowed to make balance transfer call + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(ALICE), + MultiAddress::Id(BOB), + ProxyType::Any, + 0 + )); + + // Preparing Utility call + let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { + dest: MultiAddress::Id(CAT), + value: 100_000_000_000, + }); + let inner = Box::new(transfer_call); + let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { + calls: vec![*inner], + })); + + // Utility call passed through filter + assert_ok!(Proxy::proxy( + RuntimeOrigin::signed(BOB), + MultiAddress::Id(ALICE), + None, + call.clone() + )); + expect_events(vec![ + UtilityEvent::BatchCompleted.into(), + ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), + ]); + }); +} + +#[test] +fn test_utility_call_pass_for_balances() { + new_test_ext().execute_with(|| { + // Balances proxy should be allowed to make balance transfer call + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(ALICE), + MultiAddress::Id(BOB), + ProxyType::Balances, + 0 + )); + + // Preparing Utility call + let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { + dest: MultiAddress::Id(CAT), + value: 100_000_000_000, + }); + let inner = Box::new(transfer_call); + let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { + calls: vec![*inner], + })); + + // Utility call passed through filter + assert_ok!(Proxy::proxy( + RuntimeOrigin::signed(BOB), + MultiAddress::Id(ALICE), + None, + call.clone() + )); + expect_events(vec![ + UtilityEvent::BatchCompleted.into(), + ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), + ]); + }); +} + +#[test] +fn test_utility_call_fail_non_transfer() { + new_test_ext().execute_with(|| { + // NonTransfer proxy shouldn't be allowed to make balance transfer call + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(ALICE), + MultiAddress::Id(BOB), + ProxyType::NonTransfer, + 0 + )); + + // Preparing Utility call + let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { + dest: MultiAddress::Id(CAT), + value: 100_000_000_000, + }); + let inner = Box::new(transfer_call); + let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { + calls: vec![*inner], + })); + + assert_ok!(Proxy::proxy( + RuntimeOrigin::signed(BOB), + MultiAddress::Id(ALICE), + None, + call.clone() + )); + + // Utility call filtered out + expect_events(vec![ + UtilityEvent::BatchInterrupted { + index: 0, + error: SystemError::CallFiltered.into(), + } + .into(), + ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), + ]); + }); +} + +#[test] +fn test_utility_call_fail_for_dappstaking() { + new_test_ext().execute_with(|| { + // Dappstaking proxy shouldn't be allowed to make balance transfer call + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(ALICE), + MultiAddress::Id(BOB), + ProxyType::DappsStaking, + 0 + )); + + // Preparing Utility call + let transfer_call = RuntimeCall::Balances(BalancesCall::transfer { + dest: MultiAddress::Id(CAT), + value: 100_000_000_000, + }); + let inner = Box::new(transfer_call); + let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { + calls: vec![*inner], + })); + + assert_ok!(Proxy::proxy( + RuntimeOrigin::signed(BOB), + MultiAddress::Id(ALICE), + None, + call.clone() + )); + // Utility call filtered out + expect_events(vec![ + UtilityEvent::BatchInterrupted { + index: 0, + error: SystemError::CallFiltered.into(), + } + .into(), + ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), + ]); + }); +} + +#[test] +fn test_staker_reward_claim_proxy_works() { + new_test_ext().execute_with(|| { + // Make CAT delegate for StakerRewardClaim proxy + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(BOB), + MultiAddress::Id(CAT), + ProxyType::StakerRewardClaim, + 0 + )); + + let contract = SmartContract::Evm(H160::repeat_byte(0x01)); + let staker_reward_claim_call = + RuntimeCall::DappsStaking(DappStakingCall::Call::claim_staker { + contract_id: contract.clone(), + }); + let call = Box::new(staker_reward_claim_call); + + // contract must be registered + assert_ok!(DappsStaking::register( + RuntimeOrigin::root(), + ALICE.clone(), + contract.clone() + )); + + // some amount must be staked + assert_ok!(DappsStaking::bond_and_stake( + RuntimeOrigin::signed(BOB), + contract.clone(), + 100 * UNIT + )); + run_to_block(10); + + // CAT making proxy call on behalf of staker (BOB) + assert_ok!(Proxy::proxy( + RuntimeOrigin::signed(CAT), + MultiAddress::Id(BOB), + None, + call.clone() + )); + + expect_events(vec![ProxyEvent::ProxyExecuted { result: Ok(()) }.into()]); + }) +} diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs new file mode 100644 index 0000000000..8510d70cfb --- /dev/null +++ b/tests/integration/src/setup.rs @@ -0,0 +1,160 @@ +// This file is part of Astar. + +// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +// Astar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar. If not, see . + +//! Runtime integration tests setup & imports. + +pub use frame_support::{ + assert_ok, + traits::{OnFinalize, OnIdle, OnInitialize}, + weights::Weight, +}; +pub use sp_core::H160; +pub use sp_runtime::{AccountId32, MultiAddress}; + +#[cfg(feature = "shibuya")] +pub use shibuya::*; +#[cfg(feature = "shibuya")] +mod shibuya { + pub use shibuya_runtime::*; + + /// 1 SBY. + pub const UNIT: Balance = SBY; +} + +#[cfg(feature = "shiden")] +pub use shiden::*; +#[cfg(feature = "shiden")] +mod shiden { + pub use shiden_runtime::*; + + /// 1 SDN. + pub const UNIT: Balance = SDN; +} + +#[cfg(feature = "astar")] +pub use astar::*; +#[cfg(feature = "astar")] +mod astar { + pub use astar_runtime::*; + + /// 1 ASTR. + pub const UNIT: Balance = ASTR; +} + +pub const ALICE: AccountId32 = AccountId32::new([1_u8; 32]); +pub const BOB: AccountId32 = AccountId32::new([2_u8; 32]); +pub const CAT: AccountId32 = AccountId32::new([3_u8; 32]); + +pub const INITIAL_AMOUNT: u128 = 100_000 * UNIT; + +pub type SystemError = frame_system::Error; +pub use pallet_balances::Call as BalancesCall; +pub use pallet_dapps_staking as DappStakingCall; +pub use pallet_proxy::Event as ProxyEvent; +pub use pallet_utility::{Call as UtilityCall, Event as UtilityEvent}; + +pub struct ExtBuilder { + balances: Vec<(AccountId32, Balance)>, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { balances: vec![] } + } +} + +impl ExtBuilder { + pub fn balances(mut self, balances: Vec<(AccountId32, Balance)>) -> Self { + self.balances = balances; + self + } + + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances, + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + ExtBuilder::default() + .balances(vec![ + (ALICE, INITIAL_AMOUNT), + (BOB, INITIAL_AMOUNT), + (CAT, INITIAL_AMOUNT), + ]) + .build() +} + +// Block time: 12 seconds. +pub const BLOCK_TIME: u64 = 12_000; + +pub fn run_to_block(n: u32) { + while System::block_number() < n { + let block_number = System::block_number(); + Timestamp::set_timestamp(block_number as u64 * BLOCK_TIME); + DappsStaking::on_finalize(block_number); + Authorship::on_finalize(block_number); + Session::on_finalize(block_number); + AuraExt::on_finalize(block_number); + PolkadotXcm::on_finalize(block_number); + Ethereum::on_finalize(block_number); + BaseFee::on_finalize(block_number); + + System::set_block_number(block_number + 1); + + TransactionPayment::on_initialize(block_number); + DappsStaking::on_initialize(block_number); + Authorship::on_initialize(block_number); + Aura::on_initialize(block_number); + AuraExt::on_initialize(block_number); + Ethereum::on_initialize(block_number); + BaseFee::on_initialize(block_number); + #[cfg(any(feature = "shibuya", feature = "shiden"))] + RandomnessCollectiveFlip::on_initialize(block_number); + StateTrieMigration::on_initialize(block_number); + + XcmpQueue::on_idle(block_number, Weight::MAX); + DmpQueue::on_idle(block_number, Weight::MAX); + Contracts::on_idle(block_number, Weight::MAX); + } +} + +fn last_events(n: usize) -> Vec { + frame_system::Pallet::::events() + .into_iter() + .rev() + .take(n) + .rev() + .map(|e| e.event) + .collect() +} + +pub fn expect_events(e: Vec) { + assert_eq!(last_events(e.len()), e); +}