-
Notifications
You must be signed in to change notification settings - Fork 158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix!(calc): fee calculation #974
Conversation
@athei I was wondering if you had any pointers here for using Fixed precision with sp_arithmetic in order to do the above calculations as accurately as possible. |
I thought no calculation is necessary anymore since we can get all of that from the node via RPC? |
So yes it is not necessary for chains specific to parity (ie. Polkadot, Kusama, Westend etc.) but for parachains |
If you just want to know the fee in a retrospective way, we can kiss and goodbye this whole wasm calculation because we added paritytech/substrate#11618 |
Just to add a brief history from chatting with @TarikGul:
But the results we get don't quite match up to the real known fees for some transactions. Notes:
And now some questions:
|
Could be, I recall that during the creation of Reading all of this, I really hope that we can solve this in a fundamentally new way, using the runtime as the source of truth and not some opaque formula by subscan that may or may not be respected in any given runtime. So as far as I know, subscan has the machinery to decode the tx-fee of most of the ranges of historical blocks, right? and from now on, it should rely on this event. Isn't this more or less "problem solved"? |
So it's mostly/partially problem solved. Moving forward we would be able to use the new event as a source of truth for future blocks. For historical blocks there is a solution in place currently that uses events to collect fee information, but I dont think the solution is the be all end all for sidecar. In addition, Sidecar is not able to get any information from Subscan, so if they have a solution in place we would have to adopt it to retrieve any of that fee accuracy. My main concern (and this concern is also shared across exchanges) is that Sidecar needs a guarantee that every block historically has the correct fees. For Polkadot, Kusama, and Westend this is true so on that front Sidecar is great. But for parachains is a bit more tricky. I briefly mentioned it above, but I added a query param called
I definitely agree on this. Having the runtime be the source of truth is definitely the route I hope is taken. It's always better especially for anything downstream because it's usually easier to handle or deal with if there are any changes. |
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 to me!
Just to check; is the partial_fee_as_string
method all you'll need on the sidecar side? I think so, but worth being sure before you do a release and then find you need another release to add some missing thing :)
@jsdw So I checked everything out and ran it locally. I like the current API we are exposing. 👍 from me. All checked out as well |
This PR will be followed up by a release of
@substrate/calc
, then a updated PR to implement the changes provided by the wasm_bindgenSummary (PR Co-authored by @jsdw, and Summary written by @jsdw)
Uses the following formula to calculate an extrinsics
partial_fee
(ie the total fee minus any tip).Where:
base_fee
is a fixed base fee to include some transaction in a block. It accountsfor the work needed to verify the signature and such and is constant for any tx.
len_fee
is a fee paid based on the size (length in bytes) of the transaction. Longertransactions require more storage.
adjusted_weight_fee
is a fee that is itselfestimated_weight * targeted_fee_adjustment
.targeted_fee_adjustment
is some adjustment made based on the network load and such, and isan opaque internal value we have no access to.
estimated_weight
is the "pre-dispatch" weight of the transaction. It's set based on the cost of processing the transaction on reference hardware.actual_weight
is the weight that is found in theExtrinsicSuccess
event for the extrinsic ina block (it's just called
weight
in the event), and is often the same asestimated_weight
,but the node has the opportunity to change it to whatever it likes, I think.
The RPC endpoint
payment_queryFeeDetails
returnsbase_fee
,len_fee
andadjusted_weight_fee
/The RPC endpoint
payment_queryInfo
returnsestimated_weight
(calledweight
in the response), anda
partialFee
value, which is our best guess at the inclusion fee for the tx without actually submittingit and seeing whether the node changes the weight/decides not to take a fee at all.
To get the correct values for some extrinsic from both endpoints, provide the extrinsic bytes, and the
block number one before the block it made it into (eg if the extrinsic was in block 100, you'd use
block 99 as an argument). This is very important.
Once you've called these endpoints, access the
ExtrinsicSuccess
event to find theactual_weight
, butalso a
paysFee
value which signals whether the extrinsic actually incurred a fee at all or not (a nodehas the opportunity to refund the fee entirely if it likes by setting this).
With all of those values to hand, the equation above calculates the correct Fee. Why? Well, the basic
way to calculate a pre-dispatch fee is:
We can do this from just the RPC methods. But then once it's in a block, we need to swap out the weight used
to calculate that
adjusted_weight_fee
with the actual weight that was used from theExtrinsicSuccess
event.In the end, the maths is simple and gathering the details needed is the main difficulty. We do this all in
Rust simply to limit any precision loss.
Note
This PR removes legacy calc_fee