-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Partial fix for transaction priority #7034
Changes from all commits
7a2ff0e
655a52a
b34b934
37dc0fa
6a585af
048064e
6c94d7a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -467,6 +467,23 @@ impl<T: Trait + Send + Sync> ChargeTransactionPayment<T> where | |
Err(_) => Err(InvalidTransaction::Payment.into()), | ||
} | ||
} | ||
|
||
/// Get an appropriate priority for a transaction with the given length and info. | ||
/// | ||
/// This will try and optimise the `fee/weight` `fee/length`, whichever is consuming more of the | ||
/// maximum corresponding limit. | ||
/// | ||
/// For example, if a transaction consumed 1/4th of the block length and half of the weight, its | ||
/// final priority is `fee * min(2, 4) = fee * 2`. If it consumed `1/4th` of the block length | ||
/// and the entire block weight `(1/1)`, its priority is `fee * min(1, 4) = fee * 1`. This means | ||
/// that the transaction which consumes more resources (either length or weight) with the same | ||
/// `fee` ends up having lower priority. | ||
fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority { | ||
let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1); | ||
let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1); | ||
let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>(); | ||
final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>() | ||
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. I am wondering if this operation would saturate too easily but it seems fine: MaximumBlockWeight/BaseExtrinsicWeight ~ 10^4 TransactionByteFee ~ 10^10 so this operation would result ~ 10^18 so it is less than 2^64 (== 10^19) So it seems to handle all kind of transaction though not with big margin. I guess it seems fine 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 this could get tricky.. But yes I think your estimate is on the extreme end. A typical fee in a chain with 12 decimals (such as kusama) would probably be around 10^9~10^10. Given that a coefficient of even 10^6 is fine, even though that is also a very high estimate. This means that we have a transaction, which weight-wise or size-wise, is 10^6 times smaller than the block limit, i.e. a million of them can fit in a block. Do we have this in reality? I think most weights are such that we can fit a few thousand transactions in a block at most. 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. Yes I agree. My worry is if submitting a full block extrinsic saturate the priority then you can't tip beyond this. But tip is important for when you actually really need to get your transaction in. |
||
} | ||
} | ||
|
||
impl<T: Trait + Send + Sync> sp_std::fmt::Debug for ChargeTransactionPayment<T> { | ||
|
@@ -499,12 +516,10 @@ impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T> whe | |
len: usize, | ||
) -> TransactionValidity { | ||
let (fee, _) = self.withdraw_fee(who, info, len)?; | ||
|
||
let mut r = ValidTransaction::default(); | ||
// NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which | ||
// will be a bit more than setting the priority to tip. For now, this is enough. | ||
r.priority = fee.saturated_into::<TransactionPriority>(); | ||
Ok(r) | ||
Ok(ValidTransaction { | ||
priority: Self::get_priority(len, info, fee), | ||
..Default::default() | ||
}) | ||
} | ||
|
||
fn pre_dispatch( | ||
|
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 know what our take on
SignedExtensions
composability is, but we should make it clear thatCheckWeight
is now required, cause without it the prioritisation would not work at all.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.
is it an issue if there is no prioritisation ?
I agree we should make clear that chain should handle their prioritisation correctly for production chain, but a dev chain can work without it no ?
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.
Ahh so this must have been the reason why we set the weight as priority in
CheckWeight
andCheckNonce
.I am ambivalent. Honestly, at the end of the day, I think all 3 of these signed extensions are absolutely vital for any chain: CheckNonce, CheckWeight, ChargeFee, and if someone is to faff around with them they should be super careful about the detail, so I am still in for not setting any priority here. I will also remove it from
CheckWeight
.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.
Actually, no,
CheckWeight
is important because it is the only one that is bumpingOperational
class.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.
And I think this is correct because setting the distinction of Normal and Operational should be the concern of the system module, not TransactionPayment.