Contracts: Add transfer event (#801)

This commit is contained in:
Sergey Pepyakin
2018-09-25 20:49:18 +01:00
committed by Gav Wood
parent a613c62dc1
commit 98e0a3a55a
7 changed files with 142 additions and 31 deletions
+32 -26
View File
@@ -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;
@@ -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> {
@@ -61,9 +62,16 @@ 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,
@@ -71,16 +79,10 @@ impl<'a, T: Trait> ExecutionContext<'a, T> {
&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,
@@ -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)
}
@@ -126,9 +129,16 @@ 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,
@@ -136,16 +146,10 @@ impl<'a, T: Trait> ExecutionContext<'a, T> {
&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,
@@ -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,
@@ -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()
@@ -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"),
@@ -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(())