Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Contracts: Add transfer event (#801)
Browse files Browse the repository at this point in the history
  • Loading branch information
pepyakin authored and gavofyork committed Sep 25, 2018
1 parent a5077f3 commit 062886e
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 31 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ impl treasury::Trait for Runtime {
impl contract::Trait for Runtime {
type Gas = u64;
type DetermineContractAddress = contract::SimpleAddressDeterminator<Runtime>;
type Event = Event;
}

impl DigestItem for Log {
Expand Down Expand Up @@ -208,7 +209,7 @@ construct_runtime!(
CouncilVoting: council_voting::{Module, Call, Storage, Event<T>},
CouncilMotions: council_motions::{Module, Call, Storage, Event<T>, Origin},
Treasury: treasury,
Contract: contract::{Module, Call, Config},
Contract: contract::{Module, Call, Config, Event<T>},
}
);

Expand Down
1 change: 1 addition & 0 deletions node/runtime/wasm/Cargo.lock

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

4 changes: 3 additions & 1 deletion srml/contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
serde = { version = "1.0", default_features = false }
serde_derive = { version = "1.0", optional = true }
pwasm-utils = { version = "0.3", default_features = false }
parity-codec = { version = "2.0", default_features = false }
parity-codec = { version = "~2.0.1", default_features = false }
parity-codec-derive = { version = "~2.0.1", default-features = false }
parity-wasm = { version = "0.31", default_features = false }
substrate-primitives = { path = "../../core/primitives", default_features = false }
sr-primitives = { path = "../../core/sr-primitives", default_features = false }
Expand All @@ -28,6 +29,7 @@ std = [
"serde_derive",
"serde/std",
"parity-codec/std",
"parity-codec-derive/std",
"substrate-primitives/std",
"sr-primitives/std",
"sr-io/std",
Expand Down
58 changes: 32 additions & 26 deletions srml/contract/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// 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 super::{CodeOf, MaxDepth, ContractAddressFor, Module, Trait, Event, RawEvent};
use account_db::{AccountDb, OverlayAccountDb};
use gas::GasMeter;
use vm;
Expand All @@ -37,6 +37,7 @@ pub struct ExecutionContext<'a, T: Trait + 'a> {
pub self_account: T::AccountId,
pub overlay: OverlayAccountDb<'a, T>,
pub depth: usize,
pub events: Vec<Event<T>>,
}

impl<'a, T: Trait> ExecutionContext<'a, T> {
Expand All @@ -61,26 +62,27 @@ impl<'a, T: Trait> ExecutionContext<'a, T> {

let dest_code = <CodeOf<T>>::get(&dest);

let change_set = {
let (change_set, events) = {
let mut overlay = OverlayAccountDb::new(&self.overlay);

let mut nested = ExecutionContext {
overlay: overlay,
self_account: dest.clone(),
depth: self.depth + 1,
events: Vec::new(),
};

if value > T::Balance::zero() {
transfer(
gas_meter,
false,
&self.self_account,
&dest,
value,
&mut overlay,
&mut nested,
)?;
}

let mut nested = ExecutionContext {
overlay: overlay,
self_account: dest.clone(),
depth: self.depth + 1,
};

if !dest_code.is_empty() {
vm::execute(
&dest_code,
Expand All @@ -95,10 +97,11 @@ impl<'a, T: Trait> ExecutionContext<'a, T> {
).map_err(|_| "vm execute returned error while call")?;
}

nested.overlay.into_change_set()
(nested.overlay.into_change_set(), nested.events)
};

self.overlay.commit(change_set);
self.events.extend(events);

Ok(CallReceipt)
}
Expand Down Expand Up @@ -126,26 +129,27 @@ impl<'a, T: Trait> ExecutionContext<'a, T> {
return Err("contract already exists");
}

let change_set = {
let (change_set, events) = {
let mut overlay = OverlayAccountDb::new(&self.overlay);

let mut nested = ExecutionContext {
overlay: overlay,
self_account: dest.clone(),
depth: self.depth + 1,
events: Vec::new(),
};

if endowment > T::Balance::zero() {
transfer(
gas_meter,
true,
&self.self_account,
&dest,
endowment,
&mut overlay,
&mut nested,
)?;
}

let mut nested = ExecutionContext {
overlay: overlay,
self_account: dest.clone(),
depth: self.depth + 1,
};

let mut contract_code = Vec::new();
vm::execute(
init_code,
Expand All @@ -160,10 +164,11 @@ impl<'a, T: Trait> ExecutionContext<'a, T> {
).map_err(|_| "vm execute returned error while create")?;

nested.overlay.set_code(&dest, contract_code);
nested.overlay.into_change_set()
(nested.overlay.into_change_set(), nested.events)
};

self.overlay.commit(change_set);
self.events.extend(events);

Ok(CreateReceipt {
address: dest,
Expand All @@ -183,15 +188,15 @@ impl<'a, T: Trait> ExecutionContext<'a, T> {
/// Note, that the fee is denominated in `T::Balance` units, but
/// charged in `T::Gas` from the provided `gas_meter`. This means
/// that the actual amount charged might differ.
fn transfer<T: Trait>(
fn transfer<'a, T: Trait>(
gas_meter: &mut GasMeter<T>,
contract_create: bool,
transactor: &T::AccountId,
dest: &T::AccountId,
value: T::Balance,
overlay: &mut OverlayAccountDb<T>,
ctx: &mut ExecutionContext<'a, T>,
) -> Result<(), &'static str> {
let would_create = overlay.get_balance(dest).is_zero();
let would_create = ctx.overlay.get_balance(dest).is_zero();

let fee: T::Balance = if contract_create {
<Module<T>>::contract_fee()
Expand All @@ -207,7 +212,7 @@ fn transfer<T: Trait>(
return Err("not enough gas to pay transfer fee");
}

let from_balance = overlay.get_balance(transactor);
let from_balance = ctx.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"),
Expand All @@ -217,15 +222,16 @@ fn transfer<T: Trait>(
}
<T as balances::Trait>::EnsureAccountLiquid::ensure_account_liquid(transactor)?;

let to_balance = overlay.get_balance(dest);
let to_balance = ctx.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);
ctx.overlay.set_balance(transactor, new_from_balance);
ctx.overlay.set_balance(dest, new_to_balance);
ctx.events.push(RawEvent::Transfer(transactor.clone(), dest.clone(), value));
}

Ok(())
Expand Down
30 changes: 30 additions & 0 deletions srml/contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ extern crate serde_derive;
#[cfg(feature = "std")]
extern crate serde;

#[macro_use]
extern crate parity_codec_derive;

extern crate parity_wasm;
extern crate pwasm_utils;

Expand Down Expand Up @@ -116,6 +119,9 @@ pub trait Trait: balances::Trait {

// As<u32> is needed for wasm-utils
type Gas: Parameter + Default + Codec + SimpleArithmetic + Copy + As<Self::Balance> + As<u64> + As<u32>;

/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}

pub trait ContractAddressFor<AccountId: Sized> {
Expand Down Expand Up @@ -169,6 +175,17 @@ decl_module! {
}
}

decl_event! {
pub enum Event<T>
where
<T as balances::Trait>::Balance,
<T as system::Trait>::AccountId
{
/// Transfer happened `from` -> `to` with given `value` as part of a `message-call` or `create`.
Transfer(AccountId, AccountId, Balance),
}
}

decl_storage! {
trait Store for Module<T: Trait> as Contract {
/// The fee required to create a contract. At least as big as staking's ReclaimRebate.
Expand Down Expand Up @@ -206,6 +223,11 @@ impl<T: Trait> double_map::StorageDoubleMap for StorageOf<T> {
}

impl<T: Trait> Module<T> {
/// Deposit one of this module's events.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}

/// Make a call to a specified account, optionally transferring some balance.
fn call(
origin: <T as system::Trait>::Origin,
Expand All @@ -226,6 +248,7 @@ impl<T: Trait> Module<T> {
self_account: origin.clone(),
depth: 0,
overlay: OverlayAccountDb::<T>::new(&account_db::DirectAccountDb),
events: Vec::new(),
};

let mut output_data = Vec::new();
Expand All @@ -234,6 +257,9 @@ impl<T: Trait> Module<T> {
if let Ok(_) = result {
// Commit all changes that made it thus far into the persistant storage.
account_db::DirectAccountDb.commit(ctx.overlay.into_change_set());

// Then deposit all events produced.
ctx.events.into_iter().for_each(Self::deposit_event);
}

// Refund cost of the unused gas.
Expand Down Expand Up @@ -273,12 +299,16 @@ impl<T: Trait> Module<T> {
self_account: origin.clone(),
depth: 0,
overlay: OverlayAccountDb::<T>::new(&account_db::DirectAccountDb),
events: Vec::new(),
};
let result = ctx.create(origin.clone(), endowment, &mut gas_meter, &ctor_code, &data);

if let Ok(_) = result {
// Commit all changes that made it thus far into the persistant storage.
account_db::DirectAccountDb.commit(ctx.overlay.into_change_set());

// Then deposit all events produced.
ctx.events.into_iter().for_each(Self::deposit_event);
}

// Refund cost of the unused gas.
Expand Down
Loading

0 comments on commit 062886e

Please sign in to comment.