mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 04:01:10 +00:00
Phase 1 of repo reorg (#719)
* Remove unneeded script * Rename Substrate Demo -> Substrate * Rename demo -> node * Build wasm from last rename. * Merge ed25519 into substrate-primitives * Minor tweak * Rename substrate -> core * Move substrate-runtime-support to core/runtime/support * Rename/move substrate-runtime-version * Move codec up a level * Rename substrate-codec -> parity-codec * Move environmental up a level * Move pwasm-* up to top, ready for removal * Remove requirement of s-r-support from s-r-primitives * Move core/runtime/primitives into core/runtime-primitives * Remove s-r-support dep from s-r-version * Remove dep of s-r-support from bft * Remove dep of s-r-support from node/consensus * Sever all other core deps from s-r-support * Forgot the no_std directive * Rename non-SRML modules to sr-* to avoid match clashes * Move runtime/* to srml/* * Rename substrate-runtime-* -> srml-* * Move srml to top-level
This commit is contained in:
committed by
Arkadiy Paronyan
parent
8fe5aa4c81
commit
1e01162505
@@ -0,0 +1,266 @@
|
||||
// Copyright 2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate 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.
|
||||
|
||||
// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::{CodeOf, MaxDepth, ContractAddressFor, Module, Trait};
|
||||
use account_db::{AccountDb, OverlayAccountDb};
|
||||
use gas::GasMeter;
|
||||
use vm;
|
||||
|
||||
use rstd::prelude::*;
|
||||
use runtime_primitives::traits::{Zero, CheckedAdd, CheckedSub};
|
||||
use runtime_support::{StorageMap, StorageValue};
|
||||
use balances::{self, EnsureAccountLiquid};
|
||||
|
||||
pub struct CreateReceipt<T: Trait> {
|
||||
pub address: T::AccountId,
|
||||
}
|
||||
|
||||
pub struct CallReceipt {
|
||||
pub return_data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct ExecutionContext<'a, T: Trait + 'a> {
|
||||
// typically should be dest
|
||||
pub self_account: T::AccountId,
|
||||
pub overlay: OverlayAccountDb<'a, T>,
|
||||
pub depth: usize,
|
||||
}
|
||||
|
||||
impl<'a, T: Trait> ExecutionContext<'a, T> {
|
||||
/// Make a call to the specified address.
|
||||
pub fn call(
|
||||
&mut self,
|
||||
caller: T::AccountId,
|
||||
dest: T::AccountId,
|
||||
value: T::Balance,
|
||||
gas_meter: &mut GasMeter<T>,
|
||||
data: &[u8],
|
||||
) -> Result<CallReceipt, &'static str> {
|
||||
if self.depth == <MaxDepth<T>>::get() as usize {
|
||||
return Err("reached maximum depth, cannot make a call");
|
||||
}
|
||||
|
||||
let call_base_fee = <Module<T>>::call_base_fee();
|
||||
if gas_meter.charge(call_base_fee).is_out_of_gas() {
|
||||
return Err("not enough gas to pay base call fee");
|
||||
}
|
||||
|
||||
let dest_code = <CodeOf<T>>::get(&dest);
|
||||
|
||||
let (exec_result, change_set) = {
|
||||
let mut overlay = OverlayAccountDb::new(&self.overlay);
|
||||
|
||||
if value > T::Balance::zero() {
|
||||
transfer(
|
||||
gas_meter,
|
||||
false,
|
||||
&self.self_account,
|
||||
&dest,
|
||||
value,
|
||||
&mut overlay,
|
||||
)?;
|
||||
}
|
||||
|
||||
let mut nested = ExecutionContext {
|
||||
overlay: overlay,
|
||||
self_account: dest.clone(),
|
||||
depth: self.depth + 1,
|
||||
};
|
||||
let exec_result = if !dest_code.is_empty() {
|
||||
vm::execute(
|
||||
&dest_code,
|
||||
data,
|
||||
&mut CallContext {
|
||||
ctx: &mut nested,
|
||||
_caller: caller,
|
||||
},
|
||||
gas_meter,
|
||||
).map_err(|_| "vm execute returned error while call")?
|
||||
} else {
|
||||
// that was a plain transfer
|
||||
vm::ExecutionResult {
|
||||
return_data: Vec::new(),
|
||||
}
|
||||
};
|
||||
|
||||
(exec_result, nested.overlay.into_change_set())
|
||||
};
|
||||
|
||||
self.overlay.commit(change_set);
|
||||
|
||||
Ok(CallReceipt {
|
||||
return_data: exec_result.return_data,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create(
|
||||
&mut self,
|
||||
caller: T::AccountId,
|
||||
endowment: T::Balance,
|
||||
gas_meter: &mut GasMeter<T>,
|
||||
ctor: &[u8],
|
||||
data: &[u8],
|
||||
) -> Result<CreateReceipt<T>, &'static str> {
|
||||
if self.depth == <MaxDepth<T>>::get() as usize {
|
||||
return Err("reached maximum depth, cannot create");
|
||||
}
|
||||
|
||||
let create_base_fee = <Module<T>>::create_base_fee();
|
||||
if gas_meter.charge(create_base_fee).is_out_of_gas() {
|
||||
return Err("not enough gas to pay base create fee");
|
||||
}
|
||||
|
||||
let dest = T::DetermineContractAddress::contract_address_for(ctor, data, &self.self_account);
|
||||
if <CodeOf<T>>::exists(&dest) {
|
||||
// TODO: Is it enough?
|
||||
return Err("contract already exists");
|
||||
}
|
||||
|
||||
let change_set = {
|
||||
let mut overlay = OverlayAccountDb::new(&self.overlay);
|
||||
|
||||
if endowment > T::Balance::zero() {
|
||||
transfer(
|
||||
gas_meter,
|
||||
true,
|
||||
&self.self_account,
|
||||
&dest,
|
||||
endowment,
|
||||
&mut overlay,
|
||||
)?;
|
||||
}
|
||||
|
||||
let mut nested = ExecutionContext {
|
||||
overlay: overlay,
|
||||
self_account: dest.clone(),
|
||||
depth: self.depth + 1,
|
||||
};
|
||||
let exec_result = {
|
||||
vm::execute(
|
||||
ctor,
|
||||
data,
|
||||
&mut CallContext {
|
||||
ctx: &mut nested,
|
||||
_caller: caller,
|
||||
},
|
||||
gas_meter,
|
||||
).map_err(|_| "vm execute returned error while create")?
|
||||
};
|
||||
|
||||
nested.overlay.set_code(&dest, exec_result.return_data);
|
||||
nested.overlay.into_change_set()
|
||||
};
|
||||
|
||||
self.overlay.commit(change_set);
|
||||
|
||||
Ok(CreateReceipt {
|
||||
address: dest,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn transfer<T: Trait>(
|
||||
gas_meter: &mut GasMeter<T>,
|
||||
contract_create: bool,
|
||||
transactor: &T::AccountId,
|
||||
dest: &T::AccountId,
|
||||
value: T::Balance,
|
||||
overlay: &mut OverlayAccountDb<T>,
|
||||
) -> Result<(), &'static str> {
|
||||
let would_create = overlay.get_balance(transactor).is_zero();
|
||||
|
||||
let fee: T::Balance = if contract_create {
|
||||
<Module<T>>::contract_fee()
|
||||
} else {
|
||||
if would_create {
|
||||
<balances::Module<T>>::creation_fee()
|
||||
} else {
|
||||
<balances::Module<T>>::transfer_fee()
|
||||
}
|
||||
};
|
||||
|
||||
if gas_meter.charge_by_balance(fee).is_out_of_gas() {
|
||||
return Err("not enough gas to pay transfer fee");
|
||||
}
|
||||
|
||||
let from_balance = overlay.get_balance(transactor);
|
||||
let new_from_balance = match from_balance.checked_sub(&value) {
|
||||
Some(b) => b,
|
||||
None => return Err("balance too low to send value"),
|
||||
};
|
||||
if would_create && value < <balances::Module<T>>::existential_deposit() {
|
||||
return Err("value too low to create account");
|
||||
}
|
||||
<T as balances::Trait>::EnsureAccountLiquid::ensure_account_liquid(transactor)?;
|
||||
|
||||
let to_balance = overlay.get_balance(dest);
|
||||
let new_to_balance = match to_balance.checked_add(&value) {
|
||||
Some(b) => b,
|
||||
None => return Err("destination balance too high to receive value"),
|
||||
};
|
||||
|
||||
if transactor != dest {
|
||||
overlay.set_balance(transactor, new_from_balance);
|
||||
overlay.set_balance(dest, new_to_balance);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct CallContext<'a, 'b: 'a, T: Trait + 'b> {
|
||||
ctx: &'a mut ExecutionContext<'b, T>,
|
||||
_caller: T::AccountId,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, T: Trait + 'b> vm::Ext for CallContext<'a, 'b, T> {
|
||||
type T = T;
|
||||
|
||||
fn get_storage(&self, key: &[u8]) -> Option<Vec<u8>> {
|
||||
self.ctx.overlay.get_storage(&self.ctx.self_account, key)
|
||||
}
|
||||
|
||||
fn set_storage(&mut self, key: &[u8], value: Option<Vec<u8>>) {
|
||||
self.ctx
|
||||
.overlay
|
||||
.set_storage(&self.ctx.self_account, key.to_vec(), value)
|
||||
}
|
||||
|
||||
fn create(
|
||||
&mut self,
|
||||
code: &[u8],
|
||||
endowment: T::Balance,
|
||||
gas_meter: &mut GasMeter<T>,
|
||||
data: &[u8],
|
||||
) -> Result<CreateReceipt<T>, ()> {
|
||||
let caller = self.ctx.self_account.clone();
|
||||
self.ctx
|
||||
.create(caller, endowment, gas_meter, code, &data)
|
||||
.map_err(|_| ())
|
||||
}
|
||||
|
||||
fn call(
|
||||
&mut self,
|
||||
to: &T::AccountId,
|
||||
value: T::Balance,
|
||||
gas_meter: &mut GasMeter<T>,
|
||||
data: &[u8],
|
||||
) -> Result<CallReceipt, ()> {
|
||||
let caller = self.ctx.self_account.clone();
|
||||
self.ctx
|
||||
.call(caller, to.clone(), value, gas_meter, data)
|
||||
.map_err(|_| ())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user