Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
8bb5143
decl_module and extract runtime mod
pepyakin Jul 4, 2018
7fa574f
Invert dependency staking←→contract
pepyakin Jul 4, 2018
8c06e98
Remove CodeOf
pepyakin Jul 4, 2018
f315ca0
Remove StorageOf and move double_map
pepyakin Jul 4, 2018
799e591
Comment staking test
pepyakin Jul 4, 2018
92922fd
Clean
pepyakin Jul 4, 2018
d43ab98
Add gas_price and gas_limit
pepyakin Jul 4, 2018
92cfeeb
Commit.
pepyakin Jul 4, 2018
a4264f3
Renames
pepyakin Jul 4, 2018
9d07af9
Params
pepyakin Jul 5, 2018
00919a4
WIP
pepyakin Jul 5, 2018
900c859
Rename transfer to call
pepyakin Jul 6, 2018
593d51c
WIP
pepyakin Jul 11, 2018
0b501c6
Rebuild binaries.
pepyakin Jul 11, 2018
ce0e128
WIP
pepyakin Jul 11, 2018
8915d76
Backport ctro changes
pepyakin Jul 11, 2018
ca48073
Call wiring
pepyakin Jul 12, 2018
3f2423f
Commit overlay.
pepyakin Jul 13, 2018
32b0e55
Rename merge → commit, into_state → ..._change_set
pepyakin Jul 13, 2018
8577fad
WIP
pepyakin Jul 14, 2018
14ee2f4
Contract creation routines
pepyakin Jul 14, 2018
3a218d9
Set code of the created account.
pepyakin Jul 14, 2018
e8157c6
Fix the ID of `create` Call
pepyakin Jul 14, 2018
43508cd
Fix most of the warning.
pepyakin Jul 14, 2018
a4b6480
Add the simplest test in the contract crate
pepyakin Jul 14, 2018
a340742
Transfers work!
pepyakin Jul 14, 2018
e3b906c
Add contract_create test.
pepyakin Jul 14, 2018
8a541a3
Clean
pepyakin Jul 14, 2018
77ee25b
Add top-level create test
pepyakin Jul 14, 2018
30a72d3
Clean a bit.
pepyakin Jul 14, 2018
51ee15d
Pass gas_limit and data via create.
pepyakin Jul 14, 2018
9c1c246
Introduce OnAccountKill callback in staking
pepyakin Jul 14, 2018
3d3a4b7
Hook up OnAccountKill
pepyakin Jul 14, 2018
6ccefe6
Comments
pepyakin Jul 14, 2018
856de95
Pay for gas.
pepyakin Jul 15, 2018
b3c256b
Refund unused gas in call
pepyakin Jul 15, 2018
18a36a3
Tests for zero call and zero endownment.
pepyakin Jul 15, 2018
1872173
Add todo about rewriting docs
pepyakin Jul 15, 2018
8be77ad
Pay for gas in create transactions
pepyakin Jul 15, 2018
0df8491
Fix refunds
pepyakin Jul 15, 2018
25492de
Clean unrelevant comments
pepyakin Jul 15, 2018
f3a2ebf
fixup! Fix refunds
pepyakin Jul 15, 2018
ea2254d
fixup! Clean unrelevant comments
pepyakin Jul 15, 2018
315c0ea
Move DetermineContractAddress to contract
pepyakin Jul 15, 2018
3ab381c
fixup! Clean unrelevant comments
pepyakin Jul 15, 2018
b513597
Inline effect_transfer, remove effect_create
pepyakin Jul 15, 2018
cdb2eeb
Merge 'origin/master' into ser-contract-ioc
pepyakin Jul 15, 2018
d54cec0
Use own new_test_ext.
pepyakin Jul 15, 2018
4032b2f
Don't account for liability
pepyakin Jul 15, 2018
3dfd294
Add some docs
pepyakin Jul 16, 2018
f276d52
Move contract_fee into contract module
pepyakin Jul 16, 2018
42d3fb8
Take GasMeter in vm::execute
pepyakin Jul 16, 2018
75631f6
Use GasMeter throughout contract module for meter
pepyakin Jul 16, 2018
c2bc86d
gas module refactoring
pepyakin Jul 16, 2018
bf07b3c
Clean
pepyakin Jul 16, 2018
952112c
Add base call fee
pepyakin Jul 16, 2018
fa8991e
note about gas price should be taken from storage
pepyakin Jul 16, 2018
3e70be5
Add base fee for create
pepyakin Jul 16, 2018
87c5b12
Rename send → call
pepyakin Jul 16, 2018
f15ac41
Clean
pepyakin Jul 16, 2018
41f33b7
Take fee expressed in dots in gas
pepyakin Jul 16, 2018
cb6e995
Add Checked{Add,Sub,Mul,Div} to SimpleArithmetic
pepyakin Jul 16, 2018
8e5f297
Make Gas generic
pepyakin Jul 16, 2018
b16fec1
Store {call,create}_base_fee in storage
pepyakin Jul 16, 2018
6072034
Clean
pepyakin Jul 16, 2018
5bd0ee9
Rename buy_gas
pepyakin Jul 16, 2018
dadf9d8
Store gas_price in the storage
pepyakin Jul 16, 2018
6c93532
Remove unneeded comment.
pepyakin Jul 16, 2018
b84d090
Bail out if contract already has code.
pepyakin Jul 16, 2018
259a32f
Todos
pepyakin Jul 16, 2018
525df4b
Refund even if top-level contract fails.
pepyakin Jul 16, 2018
8562de6
Fix error msg
pepyakin Jul 16, 2018
4122f48
Fix caller issue
pepyakin Jul 16, 2018
f9497dd
Extract tests module
pepyakin Jul 16, 2018
7bf7759
Add max_depth var in storage
pepyakin Jul 16, 2018
de095a6
Remove left over gas_left
pepyakin Jul 16, 2018
338fe9f
Refactor exec
pepyakin Jul 16, 2018
4377497
Add test oog test.
pepyakin Jul 16, 2018
8ce5aed
set_free_balance_creating
pepyakin Jul 16, 2018
d8fa9e4
Docs and comments.
pepyakin Jul 17, 2018
a1ecfb0
Merge 'origin/master' into ser-contract-ioc
pepyakin Jul 17, 2018
91371c9
Update storage roots because of ContractFee move
pepyakin Jul 17, 2018
4dfc7dc
Rebuild binaries.
pepyakin Jul 17, 2018
2348c18
Simplify vm code.
pepyakin Jul 17, 2018
5873335
Wrapping.
pepyakin Jul 17, 2018
62b498d
Refactor a bit.
pepyakin Jul 17, 2018
895386d
Typo
pepyakin Jul 17, 2018
3e92676
UpdateBalanceOutcome enum
pepyakin Jul 17, 2018
ee97b9e
Style grumbles.
pepyakin Jul 17, 2018
34189ee
Merge 'origin/master' into ser-contract-ioc
pepyakin Jul 17, 2018
a18292a
Rebuild binaries.
pepyakin Jul 17, 2018
81e6eb7
Always consume the given amount of gas.
pepyakin Jul 17, 2018
9a52a44
[skip ci] endownment → endowment
pepyakin Jul 18, 2018
d91dfbe
Rename `AccountId` generic in on_account_kill
pepyakin Jul 23, 2018
ee83701
Merge branch 'master' into ser-contract-ioc
pepyakin Jul 24, 2018
f570351
Fix Cargo.lock
pepyakin Jul 24, 2018
4de767b
Refine docs for gas meter.
pepyakin Jul 24, 2018
58878a8
[skip ci] Add comments for gas module
pepyakin Jul 24, 2018
7a712e1
Merge branch 'master' into ser-contract-ioc
pepyakin Jul 24, 2018
eeebaba
Directly assign to `return_data` at declaration
pepyakin Jul 25, 2018
595e534
Use slices instead of vecs to pass the input data
pepyakin Jul 25, 2018
a846bb1
Add todo about passing return data without copy
pepyakin Jul 25, 2018
3afe59a
Use checked_add instead of add with overflow
pepyakin Jul 25, 2018
dae4d40
Use return_data directly.
pepyakin Jul 25, 2018
9e13c68
Rebuild binaries.
pepyakin Jul 25, 2018
d6c6250
Merge 'origin/master' into ser-contract-ioc
pepyakin Jul 27, 2018
af99a9d
Rebuild binaries.
pepyakin Jul 27, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Store gas_price in the storage
  • Loading branch information
pepyakin committed Jul 16, 2018
commit dadf9d8af4ce6f43ac94a3424b30533f013fbd05
23 changes: 7 additions & 16 deletions substrate/runtime/contract/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
}

Expand All @@ -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>,
Copy link
Contributor

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 _data to vm::execute or Ext yet 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.

Copy link
Contributor Author

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.

) -> Result<vm::ExecutionResult, &'static str> {
let dest_code = <CodeOf<T>>::get(&dest);
Expand All @@ -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,
Expand All @@ -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,
};

Expand All @@ -102,7 +99,7 @@ impl<'a, 'b: 'a, T: Trait> ExecutionContext<'a, 'b, T> {
pub fn create(
&mut self,
endownment: T::Balance,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here too

gas_meter: &mut GasMeter<T::Gas>,
gas_meter: &mut GasMeter<T>,
ctor: &[u8],
_data: &[u8],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're already using &[u8] here. So I think it may be better to change above L51 to use &[u8] as well to keep it consistent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also possibly:

  • L237 and L250.
  • substrate/runtime/contract/src/lib.rs: L120, L128 and L217.
  • substrate/runtime/contract/src/vm.rs: L65.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed!

) -> Result<CreateReceipt<T>, &'static str> {

This comment was marked as resolved.

This comment was marked as resolved.

Expand All @@ -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,
Expand All @@ -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)
Expand All @@ -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,
Expand All @@ -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");
}

Expand Down Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: endownment -> endowment

gas_meter: &mut GasMeter<T::Gas>,
gas_meter: &mut GasMeter<T>,
data: Vec<u8>,
) -> Result<vm::CreateReceipt<T::AccountId, T::Gas>, ()> {
let receipt = self
Expand All @@ -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)
Expand Down
46 changes: 27 additions & 19 deletions substrate/runtime/contract/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ending up with 0 is not enough Gas? We can never spend our last 1 gas?

Copy link
Contributor Author

@pepyakin pepyakin Jul 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not only about spending last 1 gas, it is in general about spending more gas than available. For example, you have 100 gas left, if you try to consume 200 gas it will lead to OutOfGas, but the gas won't be substracted.

Although this exact code is shamelessly copied from kovan-wasm impl (see parity/ethcore/wasm/src/runtime.rs) and, I believe, ultimately is borrowed from the ethereum, I think we can revise it. For example, we can use saturating substraction.

However, I would rather leave it for later. I'll update the PR description.

Expand All @@ -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
Expand All @@ -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));

Expand All @@ -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>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this used? needs a doc comment.

Copy link
Member

Choose a reason for hiding this comment

The 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 pub(crate) or something

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.: pub struct GasMeter, pub enum GasMeterResult or bunch of others in other modules (e.g. account_db::AccountDb).

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)
Expand All @@ -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);
}
6 changes: 4 additions & 2 deletions substrate/runtime/contract/src/genesis_config.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 {Trait, ContractFee, CallBaseFee, CreateBaseFee};
use {Trait, ContractFee, CallBaseFee, CreateBaseFee, GasPrice};

use runtime_primitives;
use runtime_io::{self, twox_128};
Expand All @@ -28,14 +28,16 @@ pub struct GenesisConfig<T: Trait> {
pub contract_fee: T::Balance,
pub call_base_fee: T::Gas,
pub create_base_fee: T::Gas,
pub gas_price: T::Balance,
}

impl<T: Trait> runtime_primitives::BuildStorage for GenesisConfig<T> {
fn build_storage(self) -> Result<runtime_io::TestExternalities, String> {
let r: runtime_io::TestExternalities = map![
twox_128(<ContractFee<T>>::key()).to_vec() => self.contract_fee.encode(),
twox_128(<CallBaseFee<T>>::key()).to_vec() => self.call_base_fee.encode(),
twox_128(<CreateBaseFee<T>>::key()).to_vec() => self.create_base_fee.encode()
twox_128(<CreateBaseFee<T>>::key()).to_vec() => self.create_base_fee.encode(),
twox_128(<GasPrice<T>>::key()).to_vec() => self.gas_price.encode()
];
Ok(r)
}
Expand Down
Loading