Skip to content

Commit

Permalink
Merge pull request #3 from BolarityNetwork/main-develop
Browse files Browse the repository at this point in the history
add  vm-port-tests item
  • Loading branch information
wd30130 authored Jul 31, 2024
2 parents 56324f6 + ebb960d commit ff1885a
Show file tree
Hide file tree
Showing 13 changed files with 796 additions and 60 deletions.
5 changes: 5 additions & 0 deletions external/contract/src/erc20wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"]
133 changes: 130 additions & 3 deletions external/contract/src/erc20wasm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <ink_env::DefaultEnvironment as Environment>::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<u8>) -> String;
#[ink(function = 6, handle_status = false)]
fn h160_to_accountid(evm_address: H160) -> AccountId;
}


Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<u8>,
}

/// The ERC-20 error types.
#[derive(Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -131,6 +154,110 @@ mod erc20 {
});
instance
}

/// Evm ABI interface.
#[ink(message)]
pub fn evm_abi_call(&mut self, para: Vec<u8>) -> Vec<u8> {
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(&para[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 => {
if para.len() < 5 {
self.env().emit_event(ParameterError {
caller: who,
parameter: para,
});
ink_env::return_value::<u8>(ReturnFlags::REVERT, &13u8);
};
let parameter = solidity::codec::decode_arguments::<Address>(&para[4..]);
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::<Balance>(return_result)
}
Err(_) => {
self.env().emit_event(ParameterError {
caller: who,
parameter: para,
});
ink_env::return_value::<u8>(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 => {
if para.len() < 5 {
self.env().emit_event(ParameterError {
caller: who,
parameter: para,
});
ink_env::return_value::<u8>(ReturnFlags::REVERT, &13u8);
};
let parameter = solidity::codec::decode_arguments::<(Address, U256)>(&para[4..]);
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::<u8>(ReturnFlags::REVERT, &1u8);
}
};
let return_result = if self.transfer(accountid, balance).is_ok(){
true
} else { false };
solidity::codec::encode_arguments::<bool>(return_result)
}
Err(_) => {
self.env().emit_event(ParameterError {
caller: who,
parameter: para,
});
ink_env::return_value::<u8>(ReturnFlags::REVERT, &2u8);
}
};
}
// None
_ => {
self.env().emit_event(SelectorError {
caller: who,
selector: evm_selector,
});
ink_env::return_value::<u8>(ReturnFlags::REVERT, &3u8);
}
}

vec![]
}

pub fn hash_keccak_256(input: &[u8]) -> [u8; 32] {
let mut output = <hash::Keccak256 as hash::HashOutput>::Type::default();
ink_env::hash_bytes::<hash::Keccak256>(input, &mut output);
output
}

/// Returns the total token supply.
#[ink(message)]
Expand Down
1 change: 1 addition & 0 deletions frame/hybrid-vm-port/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
12 changes: 11 additions & 1 deletion frame/hybrid-vm-port/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -737,12 +741,18 @@ impl<T: Config> Pallet<T> {
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(),
)),
});
}
},
Expand Down
69 changes: 43 additions & 26 deletions frame/hybrid-vm-port/src/mock.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Modified by 2024 HybridVM

// This file is part of Frontier.

// Copyright (C) Parity Technologies (UK) Ltd.
Expand All @@ -17,12 +19,14 @@

//! Test utilities
// Modified by Alex Wang 2024

use ethereum::{TransactionAction, TransactionSignature};
use rlp::RlpStream;
// Substrate
use frame_support::{
derive_impl, parameter_types,
traits::{ConstU32, FindAuthor},
traits::{ConstU128, ConstU32, FindAuthor},
weights::Weight,
ConsensusEngineId, PalletId,
};
Expand All @@ -48,7 +52,7 @@ use crate::IntermediateStateRoot;

pub type SignedExtra = (frame_system::CheckSpecVersion<Test>,);

type Balance = u64;
type Balance = u128;

frame_support::construct_runtime! {
pub enum Test {
Expand Down Expand Up @@ -88,7 +92,7 @@ impl frame_system::Config for Test {
type DbWeight = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<u64>;
type AccountData = pallet_balances::AccountData<Balance>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
Expand All @@ -97,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 = u64;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type Balance = Balance;
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! {
Expand Down Expand Up @@ -170,6 +158,16 @@ impl AddressMapping<AccountId32> for HashedAddressMapping {
}
}

pub struct CompactAddressMapping;

impl AddressMapping<AccountId32> 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;
}
Expand All @@ -181,7 +179,7 @@ impl pallet_evm::Config for Test {
type BlockHashMapping = crate::EthereumBlockHashMapping<Self>;
type CallOrigin = EnsureAddressTruncated;
type WithdrawOrigin = EnsureAddressTruncated;
type AddressMapping = HashedAddressMapping;
type AddressMapping = CompactAddressMapping;
type Currency = Balances;
type RuntimeEvent = RuntimeEvent;
type PrecompilesType = ();
Expand Down Expand Up @@ -215,12 +213,31 @@ impl pallet_contracts::chain_extension::ChainExtension<Test> for HybridVMChainEx
{
let func_id = env.func_id();
match func_id {
//fn call_evm_extension(vm_input: Vec<u8>) -> String;
5 => HybridVM::call_evm::<E>(env),
//fn h160_to_accountid(evm_address: H160) -> AccountId;
6 => h160_to_accountid::<E>(env),
_ => Err(DispatchError::from("Passed unknown func_id to chain extension")),
}
}
}

pub fn h160_to_accountid<E: Ext<T = Test>>(
env: Environment<E, InitState>,
) -> Result<RetVal, DispatchError> {
let mut envbuf = env.buf_in_buf_out();
let input: H160 = envbuf.read_as()?;
let account_id = <Test as pallet_evm::Config>::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<RuntimeCall> for AllowBalancesCall {
Expand Down Expand Up @@ -329,7 +346,7 @@ parameter_types! {
}

impl U256BalanceMapping for Test {
type Balance = u64;
type Balance = Balance;
fn u256_to_balance(value: U256) -> Result<Self::Balance, &'static str> {
Balance::try_from(value)
}
Expand Down Expand Up @@ -477,7 +494,7 @@ pub fn new_test_ext(accounts_len: usize) -> (Vec<AccountInfo>, sp_io::TestExtern
// our desired mockup.
pub fn new_test_ext_with_initial_balance(
accounts_len: usize,
initial_balance: u64,
initial_balance: Balance,
) -> (Vec<AccountInfo>, sp_io::TestExternalities) {
// sc_cli::init_logger("");
let mut ext = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
Expand Down
Loading

0 comments on commit ff1885a

Please sign in to comment.