From 4da81f8b79def8be080439049807ffbd460698e5 Mon Sep 17 00:00:00 2001 From: wd30130 Date: Fri, 26 Jul 2024 18:24:14 +0800 Subject: [PATCH 1/5] feat(test): add erc20wasm fn evm_abi_call --- external/contract/src/erc20wasm/Cargo.toml | 5 + external/contract/src/erc20wasm/lib.rs | 119 ++++++++++++++++++++- 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/external/contract/src/erc20wasm/Cargo.toml b/external/contract/src/erc20wasm/Cargo.toml index cb5eefb..414f4f3 100644 --- a/external/contract/src/erc20wasm/Cargo.toml +++ b/external/contract/src/erc20wasm/Cargo.toml @@ -16,8 +16,11 @@ scale = { package = "parity-scale-codec", version = "3.6.4", default-features = scale-info = { version = "0.6", default-features = false, features = ["derive"], optional = true } primitive-types = { version = "0.9.0", default-features = false, features = ["codec"] } +sp-core = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.11.0", default-features = false } sp-std = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.11.0", default-features = false } +precompile-utils = { git = "https://github.com/paritytech/frontier", branch = "polkadot-v1.11.0", default-features = false } + [lib] name = "erc20" path = "lib.rs" @@ -37,6 +40,8 @@ std = [ "scale-info/std", "primitive-types/std", "sp-std/std", + "sp-core/std", + "precompile-utils/std", ] ink-as-dependency = [] #ink-experimental-engine = ["ink_env/ink-experimental-engine"] diff --git a/external/contract/src/erc20wasm/lib.rs b/external/contract/src/erc20wasm/lib.rs index b6b1e26..b58ac67 100644 --- a/external/contract/src/erc20wasm/lib.rs +++ b/external/contract/src/erc20wasm/lib.rs @@ -22,14 +22,19 @@ use ink_env::Environment; use ink_prelude::string::String; -use sp_std::vec::Vec; +use sp_core::H160; +use ink_prelude::vec::Vec; +//use sp_std::vec::Vec; +type AccountId = ::AccountId; #[ink::chain_extension( extension = 0 )] pub trait MyChainExtension { type ErrorCode = i32; - + #[ink(function = 5, handle_status = false)] fn call_evm_extension(vm_input: Vec) -> String; + #[ink(function = 6, handle_status = false)] + fn h160_to_accountid(evm_address: H160) -> AccountId; } @@ -59,11 +64,15 @@ mod erc20 { use ink::storage::Lazy; use ink::storage::Mapping as StorageHashMap; + use ink_env::{hash, ReturnFlags}; use ink_prelude::string::String; use ink_prelude::string::ToString; + use ink_prelude::vec; use ink_prelude::vec::Vec; + use precompile_utils::prelude::*; + use sp_core::U256; + - /// A simple ERC-20 contract. #[ink(storage)] pub struct Erc20 { @@ -96,6 +105,20 @@ mod erc20 { spender: AccountId, value: Balance, } + + #[ink(event)] + pub struct SelectorError { + #[ink(topic)] + caller: AccountId, + selector: u32, + } + + #[ink(event)] + pub struct ParameterError { + #[ink(topic)] + caller: AccountId, + parameter: Vec, + } /// The ERC-20 error types. #[derive(Debug, PartialEq, Eq)] @@ -131,6 +154,96 @@ mod erc20 { }); instance } + + /// Evm ABI interface. + #[ink(message)] + pub fn evm_abi_call(&mut self, para: Vec) -> Vec { + let who = self.env().caller(); + + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&Self::hash_keccak_256(b"balanceOf(address)")[0..4]); + let balance_selector = u32::from_be_bytes(a); + + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&Self::hash_keccak_256(b"transfer(address,uint256)")[0..4]); + let transfer_selector = u32::from_be_bytes(a); + + let evm_selector = if para.len() < 4 { 0 } else { + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(¶[0..4]); + u32::from_be_bytes(a) + }; + + match evm_selector { + // 1. balanceOf(address account) external view returns (uint256); + // balance_of(&self, owner: AccountId) -> Balance; + a if a == balance_selector => { + let parameter = solidity::codec::decode_arguments::
(¶); + match parameter { + Ok(t) => { + let accountid = self.env().extension().h160_to_accountid(t.0); + + let return_result = self.balance_of(accountid); + solidity::codec::encode_arguments::(return_result) + } + Err(_) => { + self.env().emit_event(ParameterError { + caller: who, + parameter: para, + }); + ink_env::return_value::(ReturnFlags::REVERT, &12u8); + } + }; + } + // 2. transfer(address to, uint256 amount) external returns (bool); + // transfer(&mut self, to: AccountId, value: Balance) -> Result<()> + b if b == transfer_selector => { + let parameter = solidity::codec::decode_arguments::<(Address, U256)>(¶); + match parameter { + Ok(t) => { + let accountid = self.env().extension().h160_to_accountid(t.0.0); + let balance = match Balance::try_from(t.1) { + Ok(t) => t, + Err(_) => { + self.env().emit_event(ParameterError { + caller: who, + parameter: para, + }); + ink_env::return_value::(ReturnFlags::REVERT, &1u8); + } + }; + let return_result = if self.transfer(accountid, balance).is_ok(){ + true + } else { false }; + solidity::codec::encode_arguments::(return_result) + } + Err(_) => { + self.env().emit_event(ParameterError { + caller: who, + parameter: para, + }); + ink_env::return_value::(ReturnFlags::REVERT, &2u8); + } + }; + } + // None + _ => { + self.env().emit_event(SelectorError { + caller: who, + selector: evm_selector, + }); + ink_env::return_value::(ReturnFlags::REVERT, &3u8); + } + } + + vec![] + } + + pub fn hash_keccak_256(input: &[u8]) -> [u8; 32] { + let mut output = ::Type::default(); + ink_env::hash_bytes::(input, &mut output); + output + } /// Returns the total token supply. #[ink(message)] From b5dce352bf902da6906750ab01b2d22f6d019fb5 Mon Sep 17 00:00:00 2001 From: wd30130 Date: Fri, 26 Jul 2024 23:43:33 +0800 Subject: [PATCH 2/5] feat(test): add h160_to_accountid extension in mock --- frame/hybrid-vm/fixtures/erc20.wasm | Bin 15922 -> 20576 bytes frame/hybrid-vm/src/mock.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/frame/hybrid-vm/fixtures/erc20.wasm b/frame/hybrid-vm/fixtures/erc20.wasm index 6265d7adfcf7ba92d81d529a2ab1a9b06c4aeba4..9ba0bd6e529659e1e21b27b82c99c8be73d99624 100644 GIT binary patch literal 20576 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 C2E^t7 diff --git a/frame/hybrid-vm/src/mock.rs b/frame/hybrid-vm/src/mock.rs index 625d83a..00674e2 100644 --- a/frame/hybrid-vm/src/mock.rs +++ b/frame/hybrid-vm/src/mock.rs @@ -266,12 +266,29 @@ impl pallet_contracts::chain_extension::ChainExtension for HybridVMChainEx { let func_id = env.func_id(); match func_id { + //fn call_evm_extension(vm_input: Vec) -> String; 5 => HybridVM::call_evm::(env), + //fn h160_to_accountid(evm_address: H160) -> AccountId; + 6 => h160_to_accountid::(env), _ => Err(DispatchError::from("Passed unknown func_id to chain extension")), } } } +pub fn h160_to_accountid>(env: Environment) -> Result { + let mut envbuf = env.buf_in_buf_out(); + let input: H160 = envbuf.read_as()?; + let account_id = ::AddressMapping::into_account_id(input); + let account_id_slice = account_id.encode(); + let output = envbuf + .write(&account_id_slice, false, None) + .map_err(|_| DispatchError::from("ChainExtension failed to write result")); + match output { + Ok(_) => return Ok(RetVal::Converging(0)), + Err(e) => return Err(e), + } +} + pub enum AllowBalancesCall {} impl frame_support::traits::Contains for AllowBalancesCall { From 258818e980ccc89b903d1692debd5c82ecf3c1cc Mon Sep 17 00:00:00 2001 From: wd30130 Date: Sun, 28 Jul 2024 11:41:08 +0800 Subject: [PATCH 3/5] feat(test): add test item regist_contract works --- frame/hybrid-vm/src/lib.rs | 14 ---------- frame/hybrid-vm/src/mock.rs | 6 +++-- frame/hybrid-vm/src/tests.rs | 52 ++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/frame/hybrid-vm/src/lib.rs b/frame/hybrid-vm/src/lib.rs index 528dee1..9d53ebf 100644 --- a/frame/hybrid-vm/src/lib.rs +++ b/frame/hybrid-vm/src/lib.rs @@ -109,20 +109,6 @@ pub mod pallet { impl Pallet { #[pallet::call_index(0)] #[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().writes(1))] - pub fn call_hybrid_vm( - origin: OriginFor, - _transaction: Transaction, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - - // Todo - Self::deposit_event(Event::HybridVMCalled(who)); - - Ok(().into()) - } - - #[pallet::call_index(1)] - #[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().writes(1))] pub fn regist_contract( origin: OriginFor, unified_address: UnifiedAddress, diff --git a/frame/hybrid-vm/src/mock.rs b/frame/hybrid-vm/src/mock.rs index 00674e2..a6adfe6 100644 --- a/frame/hybrid-vm/src/mock.rs +++ b/frame/hybrid-vm/src/mock.rs @@ -269,13 +269,15 @@ impl pallet_contracts::chain_extension::ChainExtension for HybridVMChainEx //fn call_evm_extension(vm_input: Vec) -> String; 5 => HybridVM::call_evm::(env), //fn h160_to_accountid(evm_address: H160) -> AccountId; - 6 => h160_to_accountid::(env), + 6 => h160_to_accountid::(env), _ => Err(DispatchError::from("Passed unknown func_id to chain extension")), } } } -pub fn h160_to_accountid>(env: Environment) -> Result { +pub fn h160_to_accountid>( + env: Environment, +) -> Result { let mut envbuf = env.buf_in_buf_out(); let input: H160 = envbuf.read_as()?; let account_id = ::AddressMapping::into_account_id(input); diff --git a/frame/hybrid-vm/src/tests.rs b/frame/hybrid-vm/src/tests.rs index 3e3ee38..00c8932 100644 --- a/frame/hybrid-vm/src/tests.rs +++ b/frame/hybrid-vm/src/tests.rs @@ -1065,3 +1065,55 @@ fn test_evm_call_wasm_echo() { assert_eq!(echo_arr[0..echo_arr_len], [231usize, 19usize, 6usize][..]); }); } + +// Perform test for regist_contract. +#[test] +fn regist_contract_works() { + // 1. Get wasm bin + let (wasm, wasm_code_hash) = contract_module::("erc20.wasm", true).unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE_SHADOW, 10_000_000_000_000_000_000_000); + let _ = Balances::deposit_creating(&BOB_SHADOW, 10_000_000_000_000_000_000_000); + let subsistence = as Currency>::minimum_balance(); + + // 2. Create wasm contract + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"new")[0..4]); + let new_call = ExecutionInput::new(Selector::new(a)); + + let init_supply: ::Balance = + 100_000_000_000_000_000_000_000; + let new_call = new_call.push_arg(init_supply); + let creation = Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE_SHADOW.clone()), + subsistence * 100, + WEIGHT_LIMIT, + None, + wasm, + new_call.encode(), + vec![], + ); + let wasm_addr = + Contracts::contract_address(&ALICE_SHADOW, &wasm_code_hash, &new_call.encode(), &[]); + + assert_ok!(creation); + //assert!(ContractInfoOf::::contains_key(&wasm_addr)); + + assert_ok!(HybridVM::regist_contract( + RuntimeOrigin::signed(ALICE), + UnifiedAddress::::WasmVM(wasm_addr.clone()), + )); + let address = ::AccountIdMapping::into_address(wasm_addr.clone()); + + expect_event(Event::RegistContract( + address, + UnifiedAddress::::WasmVM(wasm_addr.clone()), + ALICE, + )); + assert_eq!( + HybridVM::hvm_contracts(address), + Some(UnifiedAddress::::WasmVM(wasm_addr)) + ); + }); +} From 5f73e426b30e1321a4ad0d84fbce685ade785260 Mon Sep 17 00:00:00 2001 From: wd30130 Date: Sun, 28 Jul 2024 22:39:36 +0800 Subject: [PATCH 4/5] feat(test): add test item call_hybrid_vm_works --- frame/hybrid-vm-port/Cargo.toml | 1 + frame/hybrid-vm-port/src/mock.rs | 45 ++++- frame/hybrid-vm-port/src/tests/eip1559.rs | 206 +++++++++++++++++++++- frame/hybrid-vm/src/tests.rs | 2 +- 4 files changed, 246 insertions(+), 8 deletions(-) diff --git a/frame/hybrid-vm-port/Cargo.toml b/frame/hybrid-vm-port/Cargo.toml index 6bd0172..7a12f5b 100644 --- a/frame/hybrid-vm-port/Cargo.toml +++ b/frame/hybrid-vm-port/Cargo.toml @@ -39,6 +39,7 @@ byte-slice-cast= { workspace = true } hex = { workspace = true } libsecp256k1 = { workspace = true, features = ["static-context", "hmac"] } rlp = { workspace = true } +sha3 = { workspace = true } # Substrate pallet-balances = { workspace = true, features = ["default", "insecure_zero_ed"] } pallet-insecure-randomness-collective-flip = { workspace = true, default-features = false} diff --git a/frame/hybrid-vm-port/src/mock.rs b/frame/hybrid-vm-port/src/mock.rs index 51c8a09..551940d 100644 --- a/frame/hybrid-vm-port/src/mock.rs +++ b/frame/hybrid-vm-port/src/mock.rs @@ -1,3 +1,5 @@ +// Modified by 2024 HybridVM + // This file is part of Frontier. // Copyright (C) Parity Technologies (UK) Ltd. @@ -17,6 +19,8 @@ //! Test utilities +// Modified by Alex Wang 2024 + use ethereum::{TransactionAction, TransactionSignature}; use rlp::RlpStream; // Substrate @@ -48,7 +52,7 @@ use crate::IntermediateStateRoot; pub type SignedExtra = (frame_system::CheckSpecVersion,); -type Balance = u64; +type Balance = u128; frame_support::construct_runtime! { pub enum Test { @@ -88,7 +92,7 @@ impl frame_system::Config for Test { type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; + type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); @@ -110,7 +114,7 @@ impl pallet_balances::Config for Test { type RuntimeHoldReason = RuntimeHoldReason; type RuntimeFreezeReason = RuntimeFreezeReason; type WeightInfo = (); - type Balance = u64; + type Balance = Balance; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -170,6 +174,16 @@ impl AddressMapping for HashedAddressMapping { } } +pub struct CompactAddressMapping; + +impl AddressMapping for CompactAddressMapping { + fn into_account_id(address: H160) -> AccountId32 { + let mut data = [0u8; 32]; + data[0..20].copy_from_slice(&address[..]); + AccountId32::from(data) + } +} + parameter_types! { pub SuicideQuickClearLimit: u32 = 0; } @@ -181,7 +195,7 @@ impl pallet_evm::Config for Test { type BlockHashMapping = crate::EthereumBlockHashMapping; type CallOrigin = EnsureAddressTruncated; type WithdrawOrigin = EnsureAddressTruncated; - type AddressMapping = HashedAddressMapping; + type AddressMapping = CompactAddressMapping; type Currency = Balances; type RuntimeEvent = RuntimeEvent; type PrecompilesType = (); @@ -215,12 +229,31 @@ impl pallet_contracts::chain_extension::ChainExtension for HybridVMChainEx { let func_id = env.func_id(); match func_id { + //fn call_evm_extension(vm_input: Vec) -> String; 5 => HybridVM::call_evm::(env), + //fn h160_to_accountid(evm_address: H160) -> AccountId; + 6 => h160_to_accountid::(env), _ => Err(DispatchError::from("Passed unknown func_id to chain extension")), } } } +pub fn h160_to_accountid>( + env: Environment, +) -> Result { + let mut envbuf = env.buf_in_buf_out(); + let input: H160 = envbuf.read_as()?; + let account_id = ::AddressMapping::into_account_id(input); + let account_id_slice = account_id.encode(); + let output = envbuf + .write(&account_id_slice, false, None) + .map_err(|_| DispatchError::from("ChainExtension failed to write result")); + match output { + Ok(_) => return Ok(RetVal::Converging(0)), + Err(e) => return Err(e), + } +} + pub enum AllowBalancesCall {} impl frame_support::traits::Contains for AllowBalancesCall { @@ -329,7 +362,7 @@ parameter_types! { } impl U256BalanceMapping for Test { - type Balance = u64; + type Balance = Balance; fn u256_to_balance(value: U256) -> Result { Balance::try_from(value) } @@ -477,7 +510,7 @@ pub fn new_test_ext(accounts_len: usize) -> (Vec, sp_io::TestExtern // our desired mockup. pub fn new_test_ext_with_initial_balance( accounts_len: usize, - initial_balance: u64, + initial_balance: Balance, ) -> (Vec, sp_io::TestExternalities) { // sc_cli::init_logger(""); let mut ext = frame_system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/frame/hybrid-vm-port/src/tests/eip1559.rs b/frame/hybrid-vm-port/src/tests/eip1559.rs index 47bffbe..c377f9f 100644 --- a/frame/hybrid-vm-port/src/tests/eip1559.rs +++ b/frame/hybrid-vm-port/src/tests/eip1559.rs @@ -1,3 +1,5 @@ +// Modified by 2024 HybridVM + // This file is part of Frontier. // Copyright (C) Parity Technologies (UK) Ltd. @@ -17,11 +19,60 @@ //! Consensus extension module tests for BABE consensus. +// Modified by Alex Wang 2024 + use super::*; use evm::{ExitReason, ExitRevert, ExitSucceed}; use fp_ethereum::{TransactionData, ValidatedTransaction}; -use frame_support::{dispatch::DispatchClass, traits::Get, weights::Weight}; +use frame_support::{ + dispatch::DispatchClass, + traits::{Currency, Get}, + weights::Weight, +}; +use hp_system::AccountIdMapping; +use ink_env::call::{ExecutionInput, Selector}; +use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; use pallet_evm::{AddressMapping, GasWeightMapping}; +use pallet_hybrid_vm::UnifiedAddress; +use sha3::{Digest, Keccak256}; +use sp_runtime::codec::{Decode, Encode}; +use sp_runtime::traits::{BlakeTwo256, Hash}; +use std::error::Error; +use std::fs::File; +use std::io::Read; + +const GAS_LIMIT: u64 = 10_000u64; +const WEIGHT_LIMIT: Weight = Weight::from_parts(1_000_000_000, u64::MAX); + +fn read_a_file(filename: &str) -> std::io::Result> { + let mut file = File::open(filename)?; + + let mut data = Vec::new(); + file.read_to_end(&mut data)?; + + return Ok(data); +} + +fn contract_module( + contract_name: &str, + wasmtype: bool, +) -> Result<(Vec, ::Output), Box> +where + T: frame_system::Config, +{ + let contract_path = ["../hybrid-vm/fixtures/", contract_name].concat(); + let contract_binary: Vec; + + if wasmtype { + contract_binary = read_a_file(&contract_path)?; + } else { + let bytecode = read_a_file(&contract_path)?; + contract_binary = hex::decode(bytecode)?; + } + + let code_hash = T::Hashing::hash(&contract_binary); + Ok((contract_binary, code_hash)) +} fn eip1559_erc20_creation_unsigned_transaction() -> EIP1559UnsignedTransaction { EIP1559UnsignedTransaction { @@ -602,3 +653,156 @@ fn proof_size_base_cost_should_keep_the_same_in_execution_and_estimate() { assert_eq!(estimate_tx_data.proof_size_base_cost(), tx_data.proof_size_base_cost()); }); } + +#[test] +fn call_hybrid_vm_works() { + let (pairs, mut ext) = new_test_ext_with_initial_balance(2, 1_000_000_000_000); + let alice = &pairs[0]; + let bob = &pairs[1]; + let substrate_alice = + ::AddressMapping::into_account_id(alice.address); + let substrate_bob = ::AddressMapping::into_account_id(bob.address); + + // 1. Get wasm and evm contract bin + let (wasm, wasm_code_hash) = contract_module::("erc20.wasm", true).unwrap(); + + ext.execute_with(|| { + let _ = Balances::deposit_creating(&substrate_alice, 1_000_000_000_000_000); + let _ = Balances::deposit_creating(&substrate_bob, 1_000_000_000_000_000); + let subsistence = as Currency< + ::AccountId, + >>::minimum_balance(); + + // 2. Create wasm contract + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"new")[0..4]); + let new_call = ExecutionInput::new(Selector::new(a)); + + let init_supply: ::Balance = 100_000_000_000_000_000; + let new_call = new_call.push_arg(init_supply); + let creation = Contracts::instantiate_with_code( + RuntimeOrigin::signed(substrate_alice.clone()), + subsistence * 100, + WEIGHT_LIMIT, + None, + wasm, + new_call.encode(), + vec![], + ); + + assert_ok!(creation); + let wasm_addr = + Contracts::contract_address(&substrate_alice, &wasm_code_hash, &new_call.encode(), &[]); + + //3. regist contract + + assert_ok!(HybridVM::regist_contract( + RuntimeOrigin::signed(substrate_alice.clone()), + UnifiedAddress::::WasmVM(wasm_addr.clone()), + )); + + //4. Transfer Token to substrate_bob + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"transfer")[0..4]); + let transfer_call = ExecutionInput::new(Selector::new(a)); + + let token: ::Balance = 1_213_000_789_000_000; + let transfer_call = transfer_call.push_arg(&substrate_bob).push_arg(token); + + let result = Contracts::bare_call( + substrate_alice.clone(), + wasm_addr.clone(), + 0, + WEIGHT_LIMIT, + None, + transfer_call.encode(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + .unwrap(); + + assert!(!result.did_revert()); + + //5. Get substrate_bob balance of wasm token + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"balance_of")[0..4]); + let balance_of_call = ExecutionInput::new(Selector::new(a)); + + let balance_of_call = balance_of_call.push_arg(&substrate_bob); + + let result = Contracts::bare_call( + substrate_bob.clone(), + wasm_addr.clone(), + 0, + WEIGHT_LIMIT, + None, + //Encode::encode(&balance_of_call).to_vec(), + balance_of_call.encode(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + .unwrap(); + assert!(!result.did_revert()); + + println!("result data before:{:?}", result); + let bob_balance_before = result.data; + + //6. Ethereum call hybrid vm (wasm contract) transfer wasm token to bob + let wasm_contract = + ::AccountIdMapping::into_address(wasm_addr.clone()); + let transfer_selector = &Keccak256::digest(b"transfer(address,uint256)")[0..4]; + let transfer_value: u128 = 12000000000000000000; + + let call_input = [ + &transfer_selector[..], + &[0u8; 12], + bob.address.as_fixed_bytes(), + &[0u8; 16], + &transfer_value.to_be_bytes(), + ] + .concat(); + let t = EIP1559UnsignedTransaction { + nonce: U256::from(2), + max_priority_fee_per_gas: U256::from(1), + max_fee_per_gas: U256::from(1), + gas_limit: U256::from(0x100000), + action: TransactionAction::Call(wasm_contract), + value: U256::zero(), + input: call_input, + } + .sign(&alice.private_key, None); + assert_ok!(Ethereum::execute(alice.address, &t, None,)); + + //7. Get bob balance of wasm token + let result = Contracts::bare_call( + substrate_bob.clone(), + wasm_addr.clone(), + 0, + WEIGHT_LIMIT, + None, + Encode::encode(&balance_of_call).to_vec(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + .unwrap(); + assert!(!result.did_revert()); + + println!("result data after:{:?}", result); + let bob_balance_after = result.data; + + //8. Test the balance of bob being correct + let after = as Decode>::decode(&mut &bob_balance_after[..]) + .unwrap() + .unwrap(); + let before = as Decode>::decode(&mut &bob_balance_before[..]) + .unwrap() + .unwrap(); + assert_eq!(after, before + transfer_value); + }); +} diff --git a/frame/hybrid-vm/src/tests.rs b/frame/hybrid-vm/src/tests.rs index 00c8932..3da9faf 100644 --- a/frame/hybrid-vm/src/tests.rs +++ b/frame/hybrid-vm/src/tests.rs @@ -17,7 +17,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Modified by Alex Wang +// Modified by Alex Wang 2024 use super::*; From 0063d07d1aba9d73629c31724b15450d071ca087 Mon Sep 17 00:00:00 2001 From: wd30130 Date: Tue, 30 Jul 2024 19:20:14 +0800 Subject: [PATCH 5/5] fix(*): fix pallet=hybrid-vm,port tests and wasm test contract --- external/contract/src/erc20wasm/lib.rs | 18 ++- frame/hybrid-vm-port/src/lib.rs | 12 +- frame/hybrid-vm-port/src/mock.rs | 24 +-- frame/hybrid-vm-port/src/tests/eip1559.rs | 47 +----- frame/hybrid-vm-port/src/tests/eip2930.rs | 171 +++++++++++++++++++++- frame/hybrid-vm-port/src/tests/legacy.rs | 167 ++++++++++++++++++++- frame/hybrid-vm-port/src/tests/mod.rs | 44 ++++++ frame/hybrid-vm/fixtures/erc20.wasm | Bin 20576 -> 20702 bytes 8 files changed, 403 insertions(+), 80 deletions(-) diff --git a/external/contract/src/erc20wasm/lib.rs b/external/contract/src/erc20wasm/lib.rs index b58ac67..40bc500 100644 --- a/external/contract/src/erc20wasm/lib.rs +++ b/external/contract/src/erc20wasm/lib.rs @@ -178,7 +178,14 @@ mod erc20 { // 1. balanceOf(address account) external view returns (uint256); // balance_of(&self, owner: AccountId) -> Balance; a if a == balance_selector => { - let parameter = solidity::codec::decode_arguments::
(¶); + if para.len() < 5 { + self.env().emit_event(ParameterError { + caller: who, + parameter: para, + }); + ink_env::return_value::(ReturnFlags::REVERT, &13u8); + }; + let parameter = solidity::codec::decode_arguments::
(¶[4..]); match parameter { Ok(t) => { let accountid = self.env().extension().h160_to_accountid(t.0); @@ -198,7 +205,14 @@ mod erc20 { // 2. transfer(address to, uint256 amount) external returns (bool); // transfer(&mut self, to: AccountId, value: Balance) -> Result<()> b if b == transfer_selector => { - let parameter = solidity::codec::decode_arguments::<(Address, U256)>(¶); + if para.len() < 5 { + self.env().emit_event(ParameterError { + caller: who, + parameter: para, + }); + ink_env::return_value::(ReturnFlags::REVERT, &13u8); + }; + let parameter = solidity::codec::decode_arguments::<(Address, U256)>(¶[4..]); match parameter { Ok(t) => { let accountid = self.env().extension().h160_to_accountid(t.0.0); diff --git a/frame/hybrid-vm-port/src/lib.rs b/frame/hybrid-vm-port/src/lib.rs index 05b9e39..1d90853 100644 --- a/frame/hybrid-vm-port/src/lib.rs +++ b/frame/hybrid-vm-port/src/lib.rs @@ -82,6 +82,10 @@ use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; use pallet_evm::{AddressMapping, BlockHashMapping, FeeCalculator, GasWeightMapping, Runner}; use pallet_hybrid_vm::UnifiedAddress; +fn str2s(s: String) -> &'static str { + Box::leak(s.into_boxed_str()) +} + #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] pub enum RawOrigin { EthereumTransaction(H160), @@ -737,12 +741,18 @@ impl Pallet { CallOrCreateInfo::Call(call_info), )); } else { + let mut return_code = String::from("None"); + if return_value.data.len() > 0 { + return_code = return_value.data[0].to_string(); + } return Err(DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: Some(info.gas_consumed), pays_fee: Pays::Yes, }, - error: DispatchError::from("Call wasm contract failed(REVERT)"), + error: DispatchError::from(str2s( + ["Call wasm contract failed(REVERT):", &return_code].concat(), + )), }); } }, diff --git a/frame/hybrid-vm-port/src/mock.rs b/frame/hybrid-vm-port/src/mock.rs index 551940d..e61fdcb 100644 --- a/frame/hybrid-vm-port/src/mock.rs +++ b/frame/hybrid-vm-port/src/mock.rs @@ -26,7 +26,7 @@ use rlp::RlpStream; // Substrate use frame_support::{ derive_impl, parameter_types, - traits::{ConstU32, FindAuthor}, + traits::{ConstU128, ConstU32, FindAuthor}, weights::Weight, ConsensusEngineId, PalletId, }; @@ -101,28 +101,12 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } -parameter_types! { - pub const ExistentialDeposit: u64 = 0; - // For weight estimation, we assume that the most locks on an individual account will be 50. - // This number may need to be adjusted in the future if this assumption no longer holds true. - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 50; -} - +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { - type RuntimeEvent = RuntimeEvent; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type WeightInfo = (); type Balance = Balance; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; + type ExistentialDeposit = ConstU128<1>; type ReserveIdentifier = [u8; 8]; - type FreezeIdentifier = RuntimeFreezeReason; - type MaxLocks = MaxLocks; - type MaxReserves = MaxReserves; - type MaxFreezes = ConstU32<1>; + type AccountStore = System; } parameter_types! { diff --git a/frame/hybrid-vm-port/src/tests/eip1559.rs b/frame/hybrid-vm-port/src/tests/eip1559.rs index c377f9f..82126ed 100644 --- a/frame/hybrid-vm-port/src/tests/eip1559.rs +++ b/frame/hybrid-vm-port/src/tests/eip1559.rs @@ -27,7 +27,6 @@ use fp_ethereum::{TransactionData, ValidatedTransaction}; use frame_support::{ dispatch::DispatchClass, traits::{Currency, Get}, - weights::Weight, }; use hp_system::AccountIdMapping; use ink_env::call::{ExecutionInput, Selector}; @@ -35,44 +34,6 @@ use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; use pallet_evm::{AddressMapping, GasWeightMapping}; use pallet_hybrid_vm::UnifiedAddress; use sha3::{Digest, Keccak256}; -use sp_runtime::codec::{Decode, Encode}; -use sp_runtime::traits::{BlakeTwo256, Hash}; -use std::error::Error; -use std::fs::File; -use std::io::Read; - -const GAS_LIMIT: u64 = 10_000u64; -const WEIGHT_LIMIT: Weight = Weight::from_parts(1_000_000_000, u64::MAX); - -fn read_a_file(filename: &str) -> std::io::Result> { - let mut file = File::open(filename)?; - - let mut data = Vec::new(); - file.read_to_end(&mut data)?; - - return Ok(data); -} - -fn contract_module( - contract_name: &str, - wasmtype: bool, -) -> Result<(Vec, ::Output), Box> -where - T: frame_system::Config, -{ - let contract_path = ["../hybrid-vm/fixtures/", contract_name].concat(); - let contract_binary: Vec; - - if wasmtype { - contract_binary = read_a_file(&contract_path)?; - } else { - let bytecode = read_a_file(&contract_path)?; - contract_binary = hex::decode(bytecode)?; - } - - let code_hash = T::Hashing::hash(&contract_binary); - Ok((contract_binary, code_hash)) -} fn eip1559_erc20_creation_unsigned_transaction() -> EIP1559UnsignedTransaction { EIP1559UnsignedTransaction { @@ -722,7 +683,6 @@ fn call_hybrid_vm_works() { ) .result .unwrap(); - assert!(!result.did_revert()); //5. Get substrate_bob balance of wasm token @@ -755,7 +715,7 @@ fn call_hybrid_vm_works() { let wasm_contract = ::AccountIdMapping::into_address(wasm_addr.clone()); let transfer_selector = &Keccak256::digest(b"transfer(address,uint256)")[0..4]; - let transfer_value: u128 = 12000000000000000000; + let transfer_value: u128 = 12_000_000_000_000_000; let call_input = [ &transfer_selector[..], @@ -769,13 +729,14 @@ fn call_hybrid_vm_works() { nonce: U256::from(2), max_priority_fee_per_gas: U256::from(1), max_fee_per_gas: U256::from(1), - gas_limit: U256::from(0x100000), + gas_limit: U256::from(GAS_LIMIT), action: TransactionAction::Call(wasm_contract), value: U256::zero(), input: call_input, } .sign(&alice.private_key, None); - assert_ok!(Ethereum::execute(alice.address, &t, None,)); + let result = Ethereum::transact(RawOrigin::EthereumTransaction(alice.address).into(), t); + assert_ok!(result); //7. Get bob balance of wasm token let result = Contracts::bare_call( diff --git a/frame/hybrid-vm-port/src/tests/eip2930.rs b/frame/hybrid-vm-port/src/tests/eip2930.rs index 4ecbc42..241c054 100644 --- a/frame/hybrid-vm-port/src/tests/eip2930.rs +++ b/frame/hybrid-vm-port/src/tests/eip2930.rs @@ -1,3 +1,5 @@ +// Modified by 2024 HybridVM + // This file is part of Frontier. // Copyright (C) Parity Technologies (UK) Ltd. @@ -17,14 +19,18 @@ //! Consensus extension module tests for BABE consensus. +// Modified by Alex Wang 2024 + use super::*; use evm::{ExitReason, ExitRevert, ExitSucceed}; use fp_ethereum::{TransactionData, ValidatedTransaction}; -use frame_support::{ - dispatch::{DispatchClass, GetDispatchInfo}, - weights::Weight, -}; -use pallet_evm::AddressMapping; +use frame_support::{dispatch::DispatchClass, traits::Currency}; +use hp_system::AccountIdMapping; +use ink_env::call::{ExecutionInput, Selector}; +use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; +use pallet_evm::{AddressMapping, GasWeightMapping}; +use pallet_hybrid_vm::UnifiedAddress; +use sha3::{Digest, Keccak256}; fn eip2930_erc20_creation_unsigned_transaction() -> EIP2930UnsignedTransaction { EIP2930UnsignedTransaction { @@ -462,8 +468,6 @@ fn validated_transaction_apply_zero_gas_price_works() { #[test] fn proof_size_weight_limit_validation_works() { - use pallet_evm::GasWeightMapping; - let (pairs, mut ext) = new_test_ext(1); let alice = &pairs[0]; @@ -525,3 +529,156 @@ fn proof_size_base_cost_should_keep_the_same_in_execution_and_estimate() { assert_eq!(estimate_tx_data.proof_size_base_cost(), tx_data.proof_size_base_cost()); }); } + +#[test] +fn call_hybrid_vm_works() { + let (pairs, mut ext) = new_test_ext_with_initial_balance(2, 1_000_000_000_000); + let alice = &pairs[0]; + let bob = &pairs[1]; + let substrate_alice = + ::AddressMapping::into_account_id(alice.address); + let substrate_bob = ::AddressMapping::into_account_id(bob.address); + + // 1. Get wasm and evm contract bin + let (wasm, wasm_code_hash) = contract_module::("erc20.wasm", true).unwrap(); + + ext.execute_with(|| { + let _ = Balances::deposit_creating(&substrate_alice, 1_000_000_000_000_000); + let _ = Balances::deposit_creating(&substrate_bob, 1_000_000_000_000_000); + let subsistence = as Currency< + ::AccountId, + >>::minimum_balance(); + + // 2. Create wasm contract + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"new")[0..4]); + let new_call = ExecutionInput::new(Selector::new(a)); + + let init_supply: ::Balance = 100_000_000_000_000_000; + let new_call = new_call.push_arg(init_supply); + let creation = Contracts::instantiate_with_code( + RuntimeOrigin::signed(substrate_alice.clone()), + subsistence * 100, + WEIGHT_LIMIT, + None, + wasm, + new_call.encode(), + vec![], + ); + + assert_ok!(creation); + let wasm_addr = + Contracts::contract_address(&substrate_alice, &wasm_code_hash, &new_call.encode(), &[]); + + //3. regist contract + + assert_ok!(HybridVM::regist_contract( + RuntimeOrigin::signed(substrate_alice.clone()), + UnifiedAddress::::WasmVM(wasm_addr.clone()), + )); + + //4. Transfer Token to substrate_bob + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"transfer")[0..4]); + let transfer_call = ExecutionInput::new(Selector::new(a)); + + let token: ::Balance = 1_213_000_789_000_000; + let transfer_call = transfer_call.push_arg(&substrate_bob).push_arg(token); + + let result = Contracts::bare_call( + substrate_alice.clone(), + wasm_addr.clone(), + 0, + WEIGHT_LIMIT, + None, + transfer_call.encode(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + .unwrap(); + assert!(!result.did_revert()); + + //5. Get substrate_bob balance of wasm token + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"balance_of")[0..4]); + let balance_of_call = ExecutionInput::new(Selector::new(a)); + + let balance_of_call = balance_of_call.push_arg(&substrate_bob); + + let result = Contracts::bare_call( + substrate_bob.clone(), + wasm_addr.clone(), + 0, + WEIGHT_LIMIT, + None, + //Encode::encode(&balance_of_call).to_vec(), + balance_of_call.encode(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + .unwrap(); + assert!(!result.did_revert()); + + println!("result data before:{:?}", result); + let bob_balance_before = result.data; + + //6. Ethereum call hybrid vm (wasm contract) transfer wasm token to bob + let wasm_contract = + ::AccountIdMapping::into_address(wasm_addr.clone()); + let transfer_selector = &Keccak256::digest(b"transfer(address,uint256)")[0..4]; + let transfer_value: u128 = 12_000_000_000_000_000; + + let call_input = [ + &transfer_selector[..], + &[0u8; 12], + bob.address.as_fixed_bytes(), + &[0u8; 16], + &transfer_value.to_be_bytes(), + ] + .concat(); + + let t = EIP2930UnsignedTransaction { + nonce: U256::from(2), + gas_price: U256::zero(), + gas_limit: U256::from(GAS_LIMIT), + action: TransactionAction::Call(wasm_contract), + value: U256::zero(), + input: call_input, + } + .sign(&alice.private_key, None); + let result = Ethereum::transact(RawOrigin::EthereumTransaction(alice.address).into(), t); + assert_ok!(result); + + //7. Get bob balance of wasm token + let result = Contracts::bare_call( + substrate_bob.clone(), + wasm_addr.clone(), + 0, + WEIGHT_LIMIT, + None, + Encode::encode(&balance_of_call).to_vec(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + .unwrap(); + assert!(!result.did_revert()); + + println!("result data after:{:?}", result); + let bob_balance_after = result.data; + + //8. Test the balance of bob being correct + let after = as Decode>::decode(&mut &bob_balance_after[..]) + .unwrap() + .unwrap(); + let before = as Decode>::decode(&mut &bob_balance_before[..]) + .unwrap() + .unwrap(); + assert_eq!(after, before + transfer_value); + }); +} diff --git a/frame/hybrid-vm-port/src/tests/legacy.rs b/frame/hybrid-vm-port/src/tests/legacy.rs index 2006ed7..08fe853 100644 --- a/frame/hybrid-vm-port/src/tests/legacy.rs +++ b/frame/hybrid-vm-port/src/tests/legacy.rs @@ -20,11 +20,13 @@ use super::*; use evm::{ExitReason, ExitRevert, ExitSucceed}; use fp_ethereum::{TransactionData, ValidatedTransaction}; -use frame_support::{ - dispatch::{DispatchClass, GetDispatchInfo}, - weights::Weight, -}; -use pallet_evm::AddressMapping; +use frame_support::{dispatch::DispatchClass, traits::Currency}; +use hp_system::AccountIdMapping; +use ink_env::call::{ExecutionInput, Selector}; +use pallet_contracts::{CollectEvents, DebugInfo, Determinism}; +use pallet_evm::{AddressMapping, GasWeightMapping}; +use pallet_hybrid_vm::UnifiedAddress; +use sha3::{Digest, Keccak256}; fn legacy_erc20_creation_unsigned_transaction() -> LegacyUnsignedTransaction { LegacyUnsignedTransaction { @@ -462,8 +464,6 @@ fn validated_transaction_apply_zero_gas_price_works() { #[test] fn proof_size_weight_limit_validation_works() { - use pallet_evm::GasWeightMapping; - let (pairs, mut ext) = new_test_ext(1); let alice = &pairs[0]; @@ -525,3 +525,156 @@ fn proof_size_base_cost_should_keep_the_same_in_execution_and_estimate() { assert_eq!(estimate_tx_data.proof_size_base_cost(), tx_data.proof_size_base_cost()); }); } + +#[test] +fn call_hybrid_vm_works() { + let (pairs, mut ext) = new_test_ext_with_initial_balance(2, 1_000_000_000_000); + let alice = &pairs[0]; + let bob = &pairs[1]; + let substrate_alice = + ::AddressMapping::into_account_id(alice.address); + let substrate_bob = ::AddressMapping::into_account_id(bob.address); + + // 1. Get wasm and evm contract bin + let (wasm, wasm_code_hash) = contract_module::("erc20.wasm", true).unwrap(); + + ext.execute_with(|| { + let _ = Balances::deposit_creating(&substrate_alice, 1_000_000_000_000_000); + let _ = Balances::deposit_creating(&substrate_bob, 1_000_000_000_000_000); + let subsistence = as Currency< + ::AccountId, + >>::minimum_balance(); + + // 2. Create wasm contract + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"new")[0..4]); + let new_call = ExecutionInput::new(Selector::new(a)); + + let init_supply: ::Balance = 100_000_000_000_000_000; + let new_call = new_call.push_arg(init_supply); + let creation = Contracts::instantiate_with_code( + RuntimeOrigin::signed(substrate_alice.clone()), + subsistence * 100, + WEIGHT_LIMIT, + None, + wasm, + new_call.encode(), + vec![], + ); + + assert_ok!(creation); + let wasm_addr = + Contracts::contract_address(&substrate_alice, &wasm_code_hash, &new_call.encode(), &[]); + + //3. regist contract + + assert_ok!(HybridVM::regist_contract( + RuntimeOrigin::signed(substrate_alice.clone()), + UnifiedAddress::::WasmVM(wasm_addr.clone()), + )); + + //4. Transfer Token to substrate_bob + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"transfer")[0..4]); + let transfer_call = ExecutionInput::new(Selector::new(a)); + + let token: ::Balance = 1_213_000_789_000_000; + let transfer_call = transfer_call.push_arg(&substrate_bob).push_arg(token); + + let result = Contracts::bare_call( + substrate_alice.clone(), + wasm_addr.clone(), + 0, + WEIGHT_LIMIT, + None, + transfer_call.encode(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + .unwrap(); + assert!(!result.did_revert()); + + //5. Get substrate_bob balance of wasm token + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&BlakeTwo256::hash(b"balance_of")[0..4]); + let balance_of_call = ExecutionInput::new(Selector::new(a)); + + let balance_of_call = balance_of_call.push_arg(&substrate_bob); + + let result = Contracts::bare_call( + substrate_bob.clone(), + wasm_addr.clone(), + 0, + WEIGHT_LIMIT, + None, + //Encode::encode(&balance_of_call).to_vec(), + balance_of_call.encode(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + .unwrap(); + assert!(!result.did_revert()); + + println!("result data before:{:?}", result); + let bob_balance_before = result.data; + + //6. Ethereum call hybrid vm (wasm contract) transfer wasm token to bob + let wasm_contract = + ::AccountIdMapping::into_address(wasm_addr.clone()); + let transfer_selector = &Keccak256::digest(b"transfer(address,uint256)")[0..4]; + let transfer_value: u128 = 12_000_000_000_000_000; + + let call_input = [ + &transfer_selector[..], + &[0u8; 12], + bob.address.as_fixed_bytes(), + &[0u8; 16], + &transfer_value.to_be_bytes(), + ] + .concat(); + + let t = LegacyUnsignedTransaction { + nonce: U256::from(2), + gas_price: U256::zero(), + gas_limit: U256::from(GAS_LIMIT), + action: TransactionAction::Call(wasm_contract), + value: U256::zero(), + input: call_input, + } + .sign(&alice.private_key); + let result = Ethereum::transact(RawOrigin::EthereumTransaction(alice.address).into(), t); + assert_ok!(result); + + //7. Get bob balance of wasm token + let result = Contracts::bare_call( + substrate_bob.clone(), + wasm_addr.clone(), + 0, + WEIGHT_LIMIT, + None, + Encode::encode(&balance_of_call).to_vec(), + DebugInfo::Skip, + CollectEvents::Skip, + Determinism::Enforced, + ) + .result + .unwrap(); + assert!(!result.did_revert()); + + println!("result data after:{:?}", result); + let bob_balance_after = result.data; + + //8. Test the balance of bob being correct + let after = as Decode>::decode(&mut &bob_balance_after[..]) + .unwrap() + .unwrap(); + let before = as Decode>::decode(&mut &bob_balance_before[..]) + .unwrap() + .unwrap(); + assert_eq!(after, before + transfer_value); + }); +} diff --git a/frame/hybrid-vm-port/src/tests/mod.rs b/frame/hybrid-vm-port/src/tests/mod.rs index c7b2c81..099e323 100644 --- a/frame/hybrid-vm-port/src/tests/mod.rs +++ b/frame/hybrid-vm-port/src/tests/mod.rs @@ -1,3 +1,5 @@ +// Modified by 2024 HybridVM + // This file is part of Frontier. // Copyright (C) Parity Technologies (UK) Ltd. @@ -15,8 +17,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Modified by Alex Wang 2024 + use frame_support::{ assert_err, assert_ok, dispatch::GetDispatchInfo, unsigned::TransactionValidityError, + weights::Weight, }; use sp_runtime::{ traits::Applyable, @@ -29,6 +34,12 @@ use crate::{ }; use fp_self_contained::CheckedExtrinsic; +use sp_runtime::codec::{Decode, Encode}; +use sp_runtime::traits::{BlakeTwo256, Hash}; +use std::error::Error; +use std::fs::File; +use std::io::Read; + mod eip1559; mod eip2930; mod legacy; @@ -52,3 +63,36 @@ pub const ERC20_CONTRACT_BYTECODE: &str = include_str!("./res/erc20_contract_byt // } // } pub const TEST_CONTRACT_CODE: &str = "608060405234801561001057600080fd5b50610129806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c8063c2985578146037578063febb0f7e146055575b600080fd5b603d605d565b60405180821515815260200191505060405180910390f35b605b6066565b005b60006001905090565b600060bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260358152602001806100bf6035913960400191505060405180910390fd5b56fe766572795f6c6f6e675f6572726f725f6d73675f746861745f77655f6578706563745f746f5f62655f7472696d6d65645f61776179a26469706673582212207af96dd688d3a3adc999c619e6073d5b6056c72c79ace04a90ea4835a77d179364736f6c634300060c0033"; + +const GAS_LIMIT: u64 = 10_000_000u64; +const WEIGHT_LIMIT: Weight = Weight::from_parts(1_000_000_000_000, u64::MAX); + +fn read_a_file(filename: &str) -> std::io::Result> { + let mut file = File::open(filename)?; + + let mut data = Vec::new(); + file.read_to_end(&mut data)?; + + return Ok(data); +} + +fn contract_module( + contract_name: &str, + wasmtype: bool, +) -> Result<(Vec, ::Output), Box> +where + T: frame_system::Config, +{ + let contract_path = ["../hybrid-vm/fixtures/", contract_name].concat(); + let contract_binary: Vec; + + if wasmtype { + contract_binary = read_a_file(&contract_path)?; + } else { + let bytecode = read_a_file(&contract_path)?; + contract_binary = hex::decode(bytecode)?; + } + + let code_hash = T::Hashing::hash(&contract_binary); + Ok((contract_binary, code_hash)) +} diff --git a/frame/hybrid-vm/fixtures/erc20.wasm b/frame/hybrid-vm/fixtures/erc20.wasm index 9ba0bd6e529659e1e21b27b82c99c8be73d99624..8ca1d8519ef22f95c17ba0f47e61d863cafed879 100644 GIT binary patch delta 248 zcmaE`fbrf!#to+#nQlzoe3ns7j%kV0=CASR_`%oKAjg|=qnq^n=m;jusO1V#26hJ%$Qmj6&Qg6EZJsE4In1FBTJSUQw>n^24fbG z{KJqXptdAQss`?U{VW;3Ff;=6!}%j7TOZO+IX7io};;?{ia D^4~Wa delta 191 zcmcb&knzC+#to+#nQl$le3ns7j%k_W=CASNYb%o)Qjg|=qyCaJ~ zi-Q8&