-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Revamp minting/burning handling #2028
Conversation
srml/balances/src/lib.rs
Outdated
| 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)); |
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.
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 ?
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.
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?
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.
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)
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 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.
srml/contract/src/gas.rs
Outdated
|
|
||
| // 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) { |
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.
Because contracts executed can't increase issuance isn't it ?
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.
Practically, yes, this shouldn't be able to overflow because:
- we decrease the total issuance when we buy gas
- because gas is only spent, the total issuance is increased by lower amount than it was decreased.
- 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)
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.
contracts module will need moving to the new model.
|
@pepyakin please check my changes to contract module |
| /// | ||
| /// This just removes the nonce and leaves an event. | ||
| fn reap_account(who: &T::AccountId) { | ||
| <system::AccountNonce<T>>::remove(who); |
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.
There is T::OnNewAccount, this here also be T::OnReapAccount as well?
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.
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.
pepyakin
left a comment
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.
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); |
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.
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
substrate/srml/treasury/src/lib.rs
Lines 226 to 232 in e01b450
| // 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
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.
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
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.
They are not dependent storages. Total issuance includes balances outside of the basic AccountId mapping such as that in parachains.
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.
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) |
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.
I don't understand how it could be useful, could you instance another implementation ?
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.
Yes. You might want to put it in the treasury, for example.
tomusdrw
left a comment
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.
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 } |
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.
What is keyring needed for?
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.
This grumble is unaddressed
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.
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; |
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.
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 { |
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.
Could be:
if let Some(remaining_slash) = value.checked_sub(free_slash) {
...
}
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.
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); |
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.
Don't we have saturating_sub?
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, 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 { |
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.
The entire if-else expression could be just remaining_slash.checked_sub(reserved_slash)
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.
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"); |
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.
Why is it not possible to go below existential_deposit? We don't want the account to be killed by paying fees?
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.
Correct.
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.
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); |
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.
Shouldn't the comment be just expect proof?
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.
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 { |
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.
docs?
|
Generally approve. There are some other grumbles and needs a merge. I'm not an expert at this section of the code though. |
This introduces hooks to allow runtimes to handle the various points that the SRML modules need to mint or burn currency differently.
Also:
AnySignature;AnySignaturefor substrate-node (supersedes Fix MultiSigner, simplify tests #2033);