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

Conversation

@gavofyork
Copy link
Member

@gavofyork gavofyork commented Mar 18, 2019

This introduces hooks to allow runtimes to handle the various points that the SRML modules need to mint or burn currency differently.

Also:

@gavofyork gavofyork added the A0-please_review Pull request needs code review. label Mar 18, 2019
fn on_free_too_low(who: &T::AccountId) {
Self::decrease_total_stake_by(Self::free_balance(who));
// underflow should never happen, but if it does, there's not much we can do about it.
let _ = Self::decrease_total_stake_by(Self::free_balance(who));
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we could introduce a set of Events for this particular cases, like standard event in system, Underflow(String) and Overflow(String) with String being the name of the value ?

Copy link
Contributor

Choose a reason for hiding this comment

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

First, you most likely don't want to use String, since we strive to avoid it in the runtime logic.
Second, what use-cases do you see for this?

Copy link
Contributor

@gui1117 gui1117 Mar 18, 2019

Choose a reason for hiding this comment

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

The idea is that it is better to be aware that a saturated overflow or underflow happens than it being silent

(I'm not sure about how much it is relevant)

Copy link
Member Author

Choose a reason for hiding this comment

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

if overflow/underflow happens, then it's a fundamental logic error/state corruption and governance or a hard fork is needed to fix it. it'll be obvious if it happens.


// this should be infallible since we just charged for it this block. nonetheless, we play it
// safe and only issue the refund if issuance doesn't overflow.
if let Ok(_) = <balances::Module<T>>::increase_total_stake_by(refund) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Because contracts executed can't increase issuance isn't it ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Practically, yes, this shouldn't be able to overflow because:

  1. we decrease the total issuance when we buy gas
  2. because gas is only spent, the total issuance is increased by lower amount than it was decreased.
  3. there are no* code executed between pt.1 and pt.2 beyond the contract module and it doesn't do any transfers.

(* with subtle caveat that the contract module can call callbacks such as T::DetermineContractAddress which theoretically could violate this, but we don't care about this cases and most likely will put a warning somewhere in the docs that this is not recommended since it can violate some assumptions here)

Copy link
Member Author

Choose a reason for hiding this comment

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

contracts module will need moving to the new model.

@gavofyork gavofyork changed the title Be a little safer with total issuance Revamp minting/reward handling Mar 18, 2019
@gavofyork gavofyork changed the title Revamp minting/reward handling Revamp minting/burning handling Mar 18, 2019
@gavofyork
Copy link
Member Author

@pepyakin please check my changes to contract module

This was referenced Mar 18, 2019
///
/// This just removes the nonce and leaves an event.
fn reap_account(who: &T::AccountId) {
<system::AccountNonce<T>>::remove(who);
Copy link
Contributor

Choose a reason for hiding this comment

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

There is T::OnNewAccount, this here also be T::OnReapAccount as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

You mostly care about the Free part of an account being destroyed (T::OnFreeBalanceZero). I don't mind adding a hook if you can come up with a use case.

Copy link
Contributor

@pepyakin pepyakin left a comment

Choose a reason for hiding this comment

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

Contract changes look good to me!

value: Self::Balance
) -> UpdateBalanceOutcome {
// Should be infallible if our state isn't corruption. Not much we can do if state it corrupted.
let _ = S::on_unbalanced_increase(value);
Copy link
Contributor

@gui1117 gui1117 Mar 19, 2019

Choose a reason for hiding this comment

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

OK I was wrong for this method:
the doc said: NOTE: This assumes that the total stake remains unchanged after this operation
because when I decoupled treasury it was not increase stake

// return their deposit.
let _ = <balances::Module<T>>::unreserve(&p.proposer, p.bond);
// provide the allocation.
<balances::Module<T>>::increase_free_balance_creating(&p.beneficiary, p.value);
Self::deposit_event(RawEvent::Awarded(index, p.value, p.beneficiary));

But finally it seems what I thought as intentionnal was a bug.
So this method shouldn't exist anymore and be renamed to reward_creating. (or reward_create_account as suggested by @joepetrowski )

Also this confirm the point of @shawntabrizi as TotalIssuance, ReservedBalance and FreeBalance are dependent storages, we could make ourself safer even by providing method that will operate them on them coherently. We can also provides bypass method for some optimisation (but most of usages can use safe abstraction actually as we almost always call modification of total issuance and then modification of free balance) and we can even name those bypass method with a unguaranted_ or other very warnant prefix.

This would make reviewing easier

Copy link
Contributor

Choose a reason for hiding this comment

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

hmm safe operator could be implemented in another PR obviously but renaming of increase_free_balance_creating to reward_create_account seems relevant to me

Copy link
Member Author

Choose a reason for hiding this comment

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

They are not dependent storages. Total issuance includes balances outside of the basic AccountId mapping such as that in parachains.

Copy link
Member Author

Choose a reason for hiding this comment

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

In any case, this is outside the scope of this PR.

Self::make_transfer(from, to, amount)
impl<T: Trait> OnUnbalancedDecrease<T::Balance> for BurnAndMint<T> {
fn on_unbalanced_decrease(amount: T::Balance) -> Result {
<Module<T>>::decrease_total_issuance_by(amount)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand how it could be useful, could you instance another implementation ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. You might want to put it in the treasury, for example.

Copy link
Contributor

@tomusdrw tomusdrw left a comment

Choose a reason for hiding this comment

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

lgtm after a brief look

rstd = { package = "sr-std", path = "../sr-std", default-features = false }
runtime_io = { package = "sr-io", path = "../sr-io", default-features = false }
log = { version = "0.4", optional = true }
keyring = { package = "substrate-keyring", path = "../keyring", optional = true }
Copy link
Contributor

Choose a reason for hiding this comment

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

What is keyring needed for?

Copy link
Contributor

Choose a reason for hiding this comment

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

This grumble is unaddressed

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this doesn't matter since this one is being superseded by #2048

fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &AnySigner) -> bool {
runtime_io::sr25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0.as_bytes()) ||
runtime_io::ed25519_verify(self.0.as_fixed_bytes(), msg.get(), &signer.0.as_bytes())
type Signer = sr25519::Public;
Copy link
Contributor

Choose a reason for hiding this comment

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

I've used AnySigner in #2033, I think it's a bit more explicit, can later work on merging this.

Self::decrease_total_stake_by(free_slash);
if free_slash < value {
Self::slash_reserved(who, value - free_slash)
let res = if free_slash < value {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could be:

if let Some(remaining_slash) = value.checked_sub(free_slash) {
 ...
}

Copy link
Member Author

Choose a reason for hiding this comment

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

this is about to be rewritten in an upcoming PR anyway so will leave it until then

let res = if free_slash < value {
let remaining_slash = value - free_slash;
let reserved_balance = Self::reserved_balance(who);
let reserved_slash = cmp::min(reserved_balance, remaining_slash);
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we have saturating_sub?

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah, i would prefer to address these minor things in the next PR though since merging will be a time drain.

let reserved_balance = Self::reserved_balance(who);
let reserved_slash = cmp::min(reserved_balance, remaining_slash);
Self::set_reserved_balance(who, reserved_balance - reserved_slash);
if reserved_slash < remaining_slash {
Copy link
Contributor

Choose a reason for hiding this comment

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

The entire if-else expression could be just remaining_slash.checked_sub(reserved_slash)

Copy link
Member Author

Choose a reason for hiding this comment

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

it's about to be rewitten :)

let b = Self::free_balance(transactor);
let transaction_fee = Self::transaction_base_fee() + Self::transaction_byte_fee() * <T::Balance as As<u64>>::sa(encoded_len as u64);
if b < transaction_fee + Self::existential_deposit() {
return Err("not enough funds for transaction fee");
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it not possible to go below existential_deposit? We don't want the account to be killed by paying fees?

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct.

Copy link
Member Author

Choose a reason for hiding this comment

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

We assume that the account exists at the point of dispatch.

let fee = <T::Gas as As<T::Balance>>::as_(gas_spent) * gas_meter.gas_price;

// this should be infallible since we just charged for it this block.
let _ = T::GasPayment::on_unbalanced_decrease(fee);
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't the comment be just expect proof?

Copy link
Member Author

Choose a reason for hiding this comment

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

nothing should ever panic in the runtime. better to fail and allow a chain to be rescued through governance in subsequent blocks than brick it completely.

}

#[derive(Copy, Clone, Eq, PartialEq)]
pub enum ExistenceRequirement {
Copy link
Contributor

Choose a reason for hiding this comment

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

docs?

@rphmeier
Copy link
Contributor

Generally approve. There are some other grumbles and needs a merge. I'm not an expert at this section of the code though.

@gavofyork gavofyork closed this Mar 20, 2019
@arkpar arkpar deleted the gav-fixes branch April 23, 2020 18:10
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants