Skip to content

Commit

Permalink
Add EVM call tests for XVM.
Browse files Browse the repository at this point in the history
  • Loading branch information
shaunxw committed Jul 29, 2023
1 parent 02bfcb9 commit 1317da5
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 7 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pallets/xvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ astar-primitives = { workspace = true }

[dev-dependencies]
fp-evm = { workspace = true }
hex = { workspace = true }
pallet-balances = { workspace = true, features = ["std"] }
pallet-insecure-randomness-collective-flip = { workspace = true, features = ["std"] }
pallet-timestamp = { workspace = true, features = ["std"] }
Expand Down
10 changes: 9 additions & 1 deletion pallets/xvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use frame_support::{
use pallet_contracts::{CollectEvents, DebugInfo, Determinism};
use pallet_evm::GasWeightMapping;
use parity_scale_codec::Decode;
use sp_core::U256;
use sp_core::{H160, U256};
use sp_runtime::traits::StaticLookup;
use sp_std::{marker::PhantomData, prelude::*};

Expand All @@ -64,6 +64,7 @@ pub mod weights;
pub use weights::WeightInfo;

mod mock;
mod tests;

pub use pallet::*;

Expand Down Expand Up @@ -158,6 +159,13 @@ where
context, source, target, input,
);

ensure!(
target.len() == H160::len_bytes(),
CallErrorWithWeight {
error: CallError::InvalidTarget,
used_weight: WeightInfoOf::<T>::evm_call_overheads(),
}
);
let target_decoded =
Decode::decode(&mut target.as_ref()).map_err(|_| CallErrorWithWeight {
error: CallError::InvalidTarget,
Expand Down
21 changes: 18 additions & 3 deletions pallets/xvm/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use sp_runtime::{
traits::{AccountIdLookup, BlakeTwo256},
AccountId32,
};
use sp_std::cell::RefCell;

parameter_types! {
pub BlockWeights: frame_system::limits::BlockWeights =
Expand Down Expand Up @@ -131,12 +132,22 @@ impl astar_primitives::ethereum_checked::AccountMapping<AccountId> for HashedAcc
}
}

thread_local! {
static TRANSACTED: RefCell<Option<(H160, CheckedEthereumTx)>> = RefCell::new(None);
}

pub struct MockEthereumTransact;
impl MockEthereumTransact {
pub(crate) fn assert_transacted(source: H160, checked_tx: CheckedEthereumTx) {
assert!(TRANSACTED.with(|v| v.eq(&RefCell::new(Some((source, checked_tx))))));
}
}
impl CheckedEthereumTransact for MockEthereumTransact {
fn xvm_transact(
_source: H160,
_checked_tx: CheckedEthereumTx,
source: H160,
checked_tx: CheckedEthereumTx,
) -> Result<(PostDispatchInfo, EvmCallInfo), DispatchErrorWithPostInfo> {
TRANSACTED.with(|v| *v.borrow_mut() = Some((source, checked_tx)));
Ok((
PostDispatchInfo {
actual_weight: Default::default(),
Expand Down Expand Up @@ -170,7 +181,7 @@ impl pallet_xvm::Config for TestRuntime {
type GasWeightMapping = MockGasWeightMapping;
type AccountMapping = HashedAccountMapping;
type EthereumTransact = MockEthereumTransact;
type WeightInfo = ();
type WeightInfo = weights::SubstrateWeight<TestRuntime>;
}

pub(crate) type AccountId = AccountId32;
Expand All @@ -195,12 +206,16 @@ construct_runtime!(
}
);

pub(crate) const ALICE: AccountId = AccountId32::new([0u8; 32]);

#[derive(Default)]
pub struct ExtBuilder;

impl ExtBuilder {
#[allow(dead_code)]
pub fn build(self) -> TestExternalities {
TRANSACTED.with(|v| *v.borrow_mut() = None);

let t = frame_system::GenesisConfig::default()
.build_storage::<TestRuntime>()
.unwrap();
Expand Down
160 changes: 160 additions & 0 deletions pallets/xvm/src/tests.rs
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

#![cfg(test)]

use super::*;
use mock::*;

use frame_support::{assert_noop, assert_ok, weights::Weight};
use parity_scale_codec::Encode;
use sp_core::H160;
use sp_runtime::MultiAddress;

#[test]
fn calling_into_same_vm_is_not_allowed() {
ExtBuilder::default().build().execute_with(|| {
// Calling EVM from EVM
let evm_context = Context {
source_vm_id: VmId::Evm,
weight_limit: Weight::from_parts(1_000_000, 1_000_000),
};
let evm_vm_id = VmId::Evm;
let evm_target = H160::repeat_byte(1).encode();
let input = vec![1, 2, 3];
let value = 1_000_000u128;
let evm_used_weight: Weight = weights::SubstrateWeight::<TestRuntime>::evm_call_overheads();
assert_noop!(
Xvm::call(
evm_context,
evm_vm_id,
ALICE,
evm_target,
input.clone(),
value
),
CallErrorWithWeight {
error: CallError::SameVmCallNotAllowed,
used_weight: evm_used_weight
},
);

// Calling WASM from WASM
let wasm_context = Context {
source_vm_id: VmId::Wasm,
weight_limit: Weight::from_parts(1_000_000, 1_000_000),
};
let wasm_vm_id = VmId::Wasm;
let wasm_target = MultiAddress::<AccountId, ()>::Id(ALICE).encode();
let wasm_used_weight: Weight =
weights::SubstrateWeight::<TestRuntime>::wasm_call_overheads();
assert_noop!(
Xvm::call(wasm_context, wasm_vm_id, ALICE, wasm_target, input, value),
CallErrorWithWeight {
error: CallError::SameVmCallNotAllowed,
used_weight: wasm_used_weight
},
);
});
}

#[test]
fn evm_call_works() {
ExtBuilder::default().build().execute_with(|| {
let context = Context {
source_vm_id: VmId::Wasm,
weight_limit: Weight::from_parts(1_000_000, 1_000_000),
};
let vm_id = VmId::Evm;
let target = H160::repeat_byte(0xFF);
let input = vec![1; 65_536];
let value = 1_000_000u128;
let used_weight: Weight = weights::SubstrateWeight::<TestRuntime>::evm_call_overheads();

// Invalid target
assert_noop!(
Xvm::call(
context.clone(),
vm_id,
ALICE,
ALICE.encode(),
input.clone(),
value
),
CallErrorWithWeight {
error: CallError::InvalidTarget,
used_weight
},
);
assert_noop!(
Xvm::call(
context.clone(),
vm_id,
ALICE,
vec![1, 2, 3],
input.clone(),
value
),
CallErrorWithWeight {
error: CallError::InvalidTarget,
used_weight
},
);
// Input too large
assert_noop!(
Xvm::call(
context.clone(),
vm_id,
ALICE,
target.encode(),
vec![1; 65_537],
value
),
CallErrorWithWeight {
error: CallError::InputTooLarge,
used_weight
},
);

assert_ok!(Xvm::call(
context,
vm_id,
ALICE,
target.encode(),
input.clone(),
value
));
let source = Decode::decode(
&mut hex::decode("f0bd9ffde7f9f4394d8cc1d86bf24d87e5d5a9a9")
.unwrap()
.as_ref(),
)
.unwrap();
MockEthereumTransact::assert_transacted(
source,
CheckedEthereumTx {
gas_limit: U256::from(182000),
target: H160::repeat_byte(0xFF),
value: U256::from(value),
input: BoundedVec::<u8, ConstU32<MAX_ETHEREUM_TX_INPUT_SIZE>>::try_from(input)
.unwrap(),
maybe_access_list: None,
},
);
});
}
2 changes: 1 addition & 1 deletion precompiles/xvm/evm_sdk/XVM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ interface XVM {
uint8 calldata vm_id,
bytes calldata to,
bytes calldata input
uint256 value
uint256 calldata value
) external returns (bool success, bytes memory data);
}
5 changes: 4 additions & 1 deletion precompiles/xvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

#![cfg_attr(not(feature = "std"), no_std)]

use astar_primitives::{xvm::{Context, VmId, XvmCall}, Balance};
use astar_primitives::{
xvm::{Context, VmId, XvmCall},
Balance,
};
use fp_evm::{PrecompileHandle, PrecompileOutput};
use frame_support::dispatch::Dispatchable;
use pallet_evm::{AddressMapping, GasWeightMapping, Precompile};
Expand Down
1 change: 1 addition & 0 deletions primitives/src/xvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub trait XvmCall<AccountId> {
/// - `source`: Caller Id.
/// - `target`: Target contract address.
/// - `input`: call input data.
/// - `value`: value to transfer.
fn call(
context: Context,
vm_id: VmId,
Expand Down
5 changes: 4 additions & 1 deletion tests/integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ homepage.workspace = true
repository.workspace = true

[dependencies]
parity-scale-codec = { workspace = true }

# frame dependencies
frame-support = { workspace = true }
frame-system = { workspace = true }
Expand All @@ -19,7 +21,8 @@ sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }

# runtime
# astar dependencies
astar-primitives = { workspace = true }
astar-runtime = { workspace = true, features = ["std"], optional = true }
shibuya-runtime = { workspace = true, features = ["std"], optional = true }
shiden-runtime = { workspace = true, features = ["std"], optional = true }
Expand Down
3 changes: 3 additions & 0 deletions tests/integration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ mod setup;

#[cfg(any(feature = "shibuya", feature = "shiden", feature = "astar"))]
mod proxy;

#[cfg(feature = "shibuya")]
mod xvm;
29 changes: 29 additions & 0 deletions tests/integration/src/xvm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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 <http://www.gnu.org/licenses/>.

use crate::setup::*;

// use astar_primitives::xvm::{Context, VmId, XvmCall};
// use frame_support::weights::Weight;
// use parity_scale_codec::Encode;
// use sp_core::H160;

#[test]
fn cross_vm_payable_call() {
new_test_ext().execute_with(|| {});
}

0 comments on commit 1317da5

Please sign in to comment.