-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Make contract a separate runtime module #345
Changes from 1 commit
8bb5143
7fa574f
8c06e98
f315ca0
799e591
92922fd
d43ab98
92cfeeb
a4264f3
9d07af9
00919a4
900c859
593d51c
0b501c6
ce0e128
8915d76
ca48073
3f2423f
32b0e55
8577fad
14ee2f4
3a218d9
e8157c6
43508cd
a4b6480
a340742
e3b906c
8a541a3
77ee25b
30a72d3
51ee15d
9c1c246
3d3a4b7
6ccefe6
856de95
b3c256b
18a36a3
1872173
8be77ad
0df8491
25492de
f3a2ebf
ea2254d
315c0ea
3ab381c
b513597
cdb2eeb
d54cec0
4032b2f
3dfd294
f276d52
42d3fb8
75631f6
c2bc86d
bf07b3c
952112c
fa8991e
3e70be5
87c5b12
f15ac41
41f33b7
cb6e995
8e5f297
b16fec1
6072034
5bd0ee9
dadf9d8
6c93532
b84d090
259a32f
525df4b
8562de6
4122f48
f9497dd
7bf7759
de095a6
338fe9f
4377497
8ce5aed
d8fa9e4
a1ecfb0
91371c9
4dfc7dc
2348c18
5873335
62b498d
895386d
3e92676
ee97b9e
34189ee
a18292a
81e6eb7
9a52a44
d91dfbe
ee83701
f570351
4de767b
58878a8
7a712e1
eeebaba
595e534
a846bb1
3afe59a
dae4d40
9e13c68
d6c6250
af99a9d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,7 @@ use gas::GasMeter; | |
| use vm; | ||
|
|
||
| use rstd::prelude::*; | ||
| use runtime_primitives::traits::{As, Zero}; | ||
| use runtime_primitives::traits::Zero; | ||
| use runtime_support::StorageMap; | ||
| use staking; | ||
| use system; | ||
|
|
@@ -36,7 +36,6 @@ pub struct ExecutionContext<'a, 'b: 'a, T: Trait + 'b> { | |
| // typically should be dest | ||
| pub self_account: T::AccountId, | ||
| pub account_db: &'a mut OverlayAccountDb<'b, T>, | ||
| pub gas_price: T::Balance, | ||
| pub depth: usize, | ||
| } | ||
|
|
||
|
|
@@ -46,7 +45,7 @@ impl<'a, 'b: 'a, T: Trait> ExecutionContext<'a, 'b, T> { | |
| &mut self, | ||
| dest: T::AccountId, | ||
| value: T::Balance, | ||
| gas_meter: &mut GasMeter<T::Gas>, | ||
| gas_meter: &mut GasMeter<T>, | ||
| _data: Vec<u8>, | ||
| ) -> Result<vm::ExecutionResult, &'static str> { | ||
| let dest_code = <CodeOf<T>>::get(&dest); | ||
|
|
@@ -64,7 +63,6 @@ impl<'a, 'b: 'a, T: Trait> ExecutionContext<'a, 'b, T> { | |
| if value > T::Balance::zero() { | ||
| transfer( | ||
| gas_meter, | ||
| self.gas_price, | ||
| false, | ||
| &self.self_account, | ||
| &dest, | ||
|
|
@@ -78,7 +76,6 @@ impl<'a, 'b: 'a, T: Trait> ExecutionContext<'a, 'b, T> { | |
| account_db: &mut overlay, | ||
| _caller: self.self_account.clone(), | ||
| self_account: dest.clone(), | ||
| gas_price: self.gas_price, | ||
| depth: self.depth + 1, | ||
| }; | ||
|
|
||
|
|
@@ -102,7 +99,7 @@ impl<'a, 'b: 'a, T: Trait> ExecutionContext<'a, 'b, T> { | |
| pub fn create( | ||
| &mut self, | ||
| endownment: T::Balance, | ||
|
||
| gas_meter: &mut GasMeter<T::Gas>, | ||
| gas_meter: &mut GasMeter<T>, | ||
| ctor: &[u8], | ||
| _data: &[u8], | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're already using
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also possibly:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed! |
||
| ) -> Result<CreateReceipt<T>, &'static str> { | ||
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
Sorry, something went wrong. |
||
|
|
@@ -122,7 +119,6 @@ impl<'a, 'b: 'a, T: Trait> ExecutionContext<'a, 'b, T> { | |
| if endownment > T::Balance::zero() { | ||
| transfer( | ||
| gas_meter, | ||
| self.gas_price, | ||
| true, | ||
| &self.self_account, | ||
| &dest, | ||
|
|
@@ -136,7 +132,6 @@ impl<'a, 'b: 'a, T: Trait> ExecutionContext<'a, 'b, T> { | |
| account_db: &mut overlay, | ||
| _caller: self.self_account.clone(), | ||
| self_account: dest.clone(), | ||
| gas_price: self.gas_price, | ||
| depth: self.depth + 1, | ||
| }; | ||
| vm::execute(ctor, &mut nested, gas_meter) | ||
|
|
@@ -158,8 +153,7 @@ impl<'a, 'b: 'a, T: Trait> ExecutionContext<'a, 'b, T> { | |
| } | ||
|
|
||
| fn transfer<T: Trait>( | ||
| gas_meter: &mut GasMeter<T::Gas>, | ||
| gas_price: T::Balance, | ||
| gas_meter: &mut GasMeter<T>, | ||
| contract_create: bool, | ||
| transactor: &T::AccountId, | ||
| dest: &T::AccountId, | ||
|
|
@@ -178,10 +172,7 @@ fn transfer<T: Trait>( | |
| } | ||
| }; | ||
|
|
||
| // Convert fee into gas units and charge it from gas meter. | ||
| let gas_fee: T::Balance = fee / gas_price; | ||
| let gas_fee: T::Gas = <T::Gas as As<T::Balance>>::sa(gas_fee); | ||
| if gas_meter.charge(gas_fee).is_out_of_gas() { | ||
| if gas_meter.charge_by_balance(fee).is_out_of_gas() { | ||
| return Err("not enough gas to pay transfer fee"); | ||
| } | ||
|
|
||
|
|
@@ -223,7 +214,7 @@ impl<'a, 'b: 'a, T: Trait + 'b> vm::Ext<T> for ExecutionContext<'a, 'b, T> { | |
| &mut self, | ||
| code: &[u8], | ||
| endownment: T::Balance, | ||
|
||
| gas_meter: &mut GasMeter<T::Gas>, | ||
| gas_meter: &mut GasMeter<T>, | ||
| data: Vec<u8>, | ||
| ) -> Result<vm::CreateReceipt<T::AccountId, T::Gas>, ()> { | ||
| let receipt = self | ||
|
|
@@ -239,7 +230,7 @@ impl<'a, 'b: 'a, T: Trait + 'b> vm::Ext<T> for ExecutionContext<'a, 'b, T> { | |
| &mut self, | ||
| to: &T::AccountId, | ||
| value: T::Balance, | ||
| gas_meter: &mut GasMeter<T::Gas>, | ||
| gas_meter: &mut GasMeter<T>, | ||
| data: Vec<u8>, | ||
| ) -> Result<vm::ExecutionResult, ()> { | ||
| self.call(to.clone(), value, gas_meter, data) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,9 +14,9 @@ | |
| // You should have received a copy of the GNU General Public License | ||
| // along with Substrate. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| use runtime_primitives::traits::{As, CheckedMul, SimpleArithmetic}; | ||
| use {Trait, Module}; | ||
| use runtime_primitives::traits::{As, CheckedMul, CheckedSub, Zero}; | ||
| use staking; | ||
| use Trait; | ||
|
|
||
| #[must_use] | ||
| #[derive(Debug, PartialEq, Eq)] | ||
|
|
@@ -34,22 +34,24 @@ impl GasMeterResult { | |
| } | ||
| } | ||
|
|
||
| pub struct GasMeter<U> { | ||
| gas_left: U, | ||
| pub struct GasMeter<T: Trait> { | ||
| gas_left: T::Gas, | ||
| gas_price: T::Balance, | ||
| } | ||
| impl<U: SimpleArithmetic + Copy> GasMeter<U> { | ||
| impl<T: Trait> GasMeter<T> { | ||
| #[cfg(test)] | ||
| pub fn with_limit(gas_limit: U) -> GasMeter<U> { | ||
| pub fn with_limit(gas_limit: T::Gas, gas_price: T::Balance) -> GasMeter<T> { | ||
| GasMeter { | ||
| gas_left: gas_limit, | ||
| gas_price, | ||
| } | ||
| } | ||
|
|
||
| /// Account for used gas. | ||
| /// | ||
| /// Returns `OutOfGas` if there is not enough gas or addition of the specified | ||
| /// amount of gas has lead to overflow. On success returns `Proceed`. | ||
| pub fn charge(&mut self, amount: U) -> GasMeterResult { | ||
| pub fn charge(&mut self, amount: T::Gas) -> GasMeterResult { | ||
| match self.gas_left.checked_sub(&amount) { | ||
| None => GasMeterResult::OutOfGas, | ||
| Some(val) if val.is_zero() => GasMeterResult::OutOfGas, | ||
|
||
|
|
@@ -60,9 +62,15 @@ impl<U: SimpleArithmetic + Copy> GasMeter<U> { | |
| } | ||
| } | ||
|
|
||
| pub fn with_nested<R, F: FnOnce(Option<&mut GasMeter<U>>) -> R>( | ||
| pub fn charge_by_balance(&mut self, amount: T::Balance) -> GasMeterResult { | ||
| let amount_in_gas: T::Balance = amount / self.gas_price; | ||
| let amount_in_gas: T::Gas = <T::Gas as As<T::Balance>>::sa(amount_in_gas); | ||
| self.charge(amount_in_gas) | ||
| } | ||
|
|
||
| pub fn with_nested<R, F: FnOnce(Option<&mut GasMeter<T>>) -> R>( | ||
| &mut self, | ||
| amount: U, | ||
| amount: T::Gas, | ||
| f: F, | ||
| ) -> R { | ||
| // NOTE that it is ok to allocate all available gas since it still ensured | ||
|
|
@@ -71,7 +79,10 @@ impl<U: SimpleArithmetic + Copy> GasMeter<U> { | |
| f(None) | ||
| } else { | ||
| self.gas_left = self.gas_left - amount; | ||
| let mut nested = GasMeter { gas_left: amount }; | ||
| let mut nested = GasMeter { | ||
| gas_left: amount, | ||
| gas_price: self.gas_price, | ||
| }; | ||
|
|
||
| let r = f(Some(&mut nested)); | ||
|
|
||
|
|
@@ -82,16 +93,16 @@ impl<U: SimpleArithmetic + Copy> GasMeter<U> { | |
| } | ||
|
|
||
| /// Returns how much gas left from the initial budget. | ||
| pub fn gas_left(&self) -> U { | ||
| pub fn gas_left(&self) -> T::Gas { | ||
| self.gas_left | ||
| } | ||
| } | ||
|
|
||
| pub fn buy_gas<T: Trait>( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. where is this used? needs a doc comment.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok looks like it's just call/create. should probably be a little more restricted, like
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, and it isn't exported. There are quite a few places which relies on the fact they are declared in a not public sub-module. E.g.: Should I change them as well? |
||
| transactor: &T::AccountId, | ||
| gas_limit: T::Gas, | ||
| gas_price: T::Balance, | ||
| ) -> Result<GasMeter<T::Gas>, &'static str> { | ||
| ) -> Result<GasMeter<T>, &'static str> { | ||
| let gas_price = <Module<T>>::gas_price(); | ||
| let b = <staking::Module<T>>::free_balance(transactor); | ||
| let cost = <T::Gas as As<T::Balance>>::as_(gas_limit.clone()) | ||
| .checked_mul(&gas_price) | ||
|
|
@@ -102,15 +113,12 @@ pub fn buy_gas<T: Trait>( | |
| <staking::Module<T>>::set_free_balance(transactor, b - cost); | ||
| Ok(GasMeter { | ||
| gas_left: gas_limit, | ||
| gas_price, | ||
| }) | ||
| } | ||
|
|
||
| pub fn refund_unused_gas<T: Trait>( | ||
| transactor: &T::AccountId, | ||
| gas_meter: GasMeter<T::Gas>, | ||
| gas_price: T::Balance, | ||
| ) { | ||
| pub fn refund_unused_gas<T: Trait>(transactor: &T::AccountId, gas_meter: GasMeter<T>) { | ||
| let b = <staking::Module<T>>::free_balance(transactor); | ||
| let refund = <T::Gas as As<T::Balance>>::as_(gas_meter.gas_left) * gas_price; | ||
| let refund = <T::Gas as As<T::Balance>>::as_(gas_meter.gas_left) * gas_meter.gas_price; | ||
| <staking::Module<T>>::set_free_balance(transactor, b + refund); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understood this, we don't pass
_datatovm::executeorExtyet because it's unimplemented, right?And just a note on quadratic attacks -- it looks like we decide to put callstack directly on program stack, so in the future, using
&[u8]might be more efficient and lifetime should work.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, exactly, it is untackled issue right now. And I didn't delve into it.
And yes, in theory, we can directly read from/write to the caller memory.
But there is a complication with writing though. Maybe we will have to make a temporary copy. The reason for that is caller can't know the size of the return buffer before calling the callee, and thus, might want to allocate space after the return data size is known. This is an open research question right now.