-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Per-transaction weight for srml #2799
Conversation
|
It is possible somehow incorporated this with smart contract transactions? The (maximum) weight of a smart call is not determine by size, but rather by parameter gas limit. |
As far as I know, no, since this is meant to be sth flexible (for general substrate users) and at the end of the day to serve Polkadot's fee and block fullness target, both of which being radically different between the runtime abstraction and smart contract afaik. cc @pepyakin ^ |
core/sr-primitives/src/weights.rs
Outdated
| fn calculate_weight(self) -> Weight { | ||
| match self { | ||
| TransactionWeight::Basic(w) => w, | ||
| TransactionWeight::Max => (4 * 1024 * 1024, 0), |
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.
Should this use a constant?
Also it seems pretty tricky to define it like that - it means that this transaction can only be included solo in a block. The documentation though kind of implies that it can be included whenever, but when it's included no more transactions can.
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 --honestly-- didn't bother now with a constant since even the value needs to change. Same goes for the semantic meaning (your point is valid, it should be less than the actual maximum). These are placeholders until some actual benchmarking results come out.
At the end of the day, weight should not really be directly connected/correlated with block size, so having the maximum of it as 4 mb is already moot.
Will make it a const, but really have no idea for the value. The documentation is correct (we want some weight that says okay this goes in but nothing else), implementation cannot be correct for now.
core/sr-primitives/src/weights.rs
Outdated
| /// a _dispatchable_ function (anything inside `decl_module! {}`) that can be weighted. | ||
| /// A type implementing this trait can _optionally_ be passed to the as | ||
| /// `#[weight = X]`. Otherwise, default implementation will be used. | ||
| pub trait WeighableTransaction { |
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 feel this trait is very useful. The WeighableCall interfaces is limitting this stuff to linear cost of base and bytes , I think that it might be worth allowing users to specify different cost calculations that are based on the call and it's encoded len, which is not possible currently.
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 still think it's unnecessary. WeighableCall and WeighableTransaction look almost identical - they just have different method names and in transaciton self is consumed (for no apparent reason).
I'd unify this into Weighable and implement for multiple things if needed.
|
I don’t think this flexible because otherwise it should be able support contract case no problem. |
| ]), | ||
| documentation: DecodeDifferent::Encode(&[]), | ||
| }, | ||
| FunctionMetadata { |
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.
Do we need the weight in the metadata?
CC @jacogr
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.
no clue. I just added it to pass the test tbh and assumed it happens by default.
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 this is affecting fee calculation (down the line), it should be made available. (There is obviously a downstream effect for any metadata version bumps, which this should be if the structure changes - at least the JS and Python metadata parsers should be updated to cater for the new v5)
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.
@jacogr, for now, it is not affecting the fee calculation and at least in this PR I don't intend to do that but rather build the building blocks. Though, for sure, very soon the fees will be affected by the weight. Not sure what this means for js/client side.
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, so then I would suggest not yet exposing the weights on the metadata. For each change on the metadata formats, we basically -
- need to bump the metadata version
- downstream projects need to implement new versions of the Metadata (unlike Substrate, they need to support all. This also includes stuff like Polkascan, just like the polkadotjs/api they support from v0 all the way up to current v4)
I'm not against a v5 bump now the works needs to be done at some point anyway, however if things may change again and end up with a v6, maybe not - especially not if the stuff is not used atm.
Without the metadata changes (where there go down the wire), as it stands (and yes, looked at what the code does), there is no impact as of yet.
Excited to see how this evolves, it is a really cool approach.
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.
@bkchr how can one prevent this information to sneak into metadata then?
|
Thanks for the heads-up @xlc. I think the current plan for the smart-contract is to tap on the weight mechanism, although we would need to add some customization here. |
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.
Looks good! Few more minor nitpicks.
I'm wondering if weight should affect transaction fee or transaction priority as well - seems it's currently not taken into account, however you can fill up the entire block and pay little for some kinds of transactions (i.e. short encoded_len, but high weight)
core/sr-primitives/src/weights.rs
Outdated
| /// a _dispatchable_ function (anything inside `decl_module! {}`) that can be weighted. | ||
| /// A type implementing this trait can _optionally_ be passed to the as | ||
| /// `#[weight = X]`. Otherwise, default implementation will be used. | ||
| pub trait WeighableTransaction { |
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 still think it's unnecessary. WeighableCall and WeighableTransaction look almost identical - they just have different method names and in transaciton self is consumed (for no apparent reason).
I'd unify this into Weighable and implement for multiple things if needed.
| fn calculate_weight(self, len: usize) -> Weight { | ||
| match self { | ||
| TransactionWeight::Basic(base, byte) => base + byte * len as Weight, | ||
| TransactionWeight::Max => 3 * 1024 * 1024, |
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 just realised that we could calculate max given current block weight (we would have to pass it to the function along with len) - then you could just return whatever is left in a block.
I don't like it that much though, due to additional argument that has to be passed so if we have a better solution for longer term or we are satisfied enough with this, then let's just leave it as is.
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 you propose will actually work (haven't tried but shouldn't have a problem).
The potential long term solution is the other approach I explained here. I think in that design the weight calculation is internal to the Module<T> and can simply query system. I am still not fully convinced of how that should work (+ if it is absolutely needed) hence rather get this stable and clean first to be able to proceed to fee + tip steps and then refactor if needed (hopefully a decision I won't regret ♻️)
Yeah, these are the next steps, see the top PR description for the roadmap. |
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!
bkchr
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.
Some last nitpicks.
node/runtime/src/lib.rs
Outdated
| spec_name: create_runtime_str!("node"), | ||
| impl_name: create_runtime_str!("substrate-node"), | ||
| authoring_version: 10, | ||
| spec_version: 92, |
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 we should bump the spec.
Co-Authored-By: Bastian Köcher <[email protected]>
Co-Authored-By: Bastian Köcher <[email protected]>
Co-Authored-By: Bastian Köcher <[email protected]>
Co-Authored-By: Amar Singh <[email protected]>
Co-Authored-By: Bastian Köcher <[email protected]>
* debug checkpoint. * new * Worked. * Worked and weight propagated to executive. * Works with some tests. * Cleanup debug prints. * More cleanup. * Undo more logs. * Undo a few more. * Fix build. * Allow len to be used in weight calculation. * Remove noop function from dispath. * Cleanup. * Unify traits. * Update docs and nits. * line width * Update core/sr-primitives/src/weights.rs Co-Authored-By: Bastian Köcher <[email protected]> * Update core/sr-primitives/src/weights.rs Co-Authored-By: Bastian Köcher <[email protected]> * Update core/sr-primitives/src/weights.rs Co-Authored-By: Bastian Köcher <[email protected]> * Update core/sr-primitives/src/weights.rs Co-Authored-By: Amar Singh <[email protected]> * Update srml/example/src/lib.rs Co-Authored-By: Bastian Köcher <[email protected]> * Final cleanup. * Fix build.
Fix #2796.
How it works:
decl_module!now understands#[weight = $x:expr]Calland fetched and examined inexecutive'sapply_extrinsic.I've added a usage example in
srml/example. The documentation there should help.For now, this is technically not changing any logic since the default
#[weight]annotation puts{base_weight: 0, byte_weight: 1}andMAX_TRANSACTION_WEIGHTis4 * 1024 * 1024=> we are still enforcing 4mb block size (current limit is 4mb per block).Up next
As soon as possible:
MAX_TRANSACTION_WEIGHT.base_feeandbyte_feewould be deprecated in favor offee_multiplierand henceforth:fee = weight * fee_multiplier.fee_multiplierhas some embedded logic and must be updated per-block based on the size of previous blocks. Block fullness targeting with fee multiplier #2430 explains it.Then: