-
Notifications
You must be signed in to change notification settings - Fork 162
fix!(calc): fee calculation #974
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
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. |
jsdw
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 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_feeis 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_feeis a fee paid based on the size (length in bytes) of the transaction. Longertransactions require more storage.
adjusted_weight_feeis a fee that is itselfestimated_weight * targeted_fee_adjustment.targeted_fee_adjustmentis some adjustment made based on the network load and such, and isan opaque internal value we have no access to.
estimated_weightis the "pre-dispatch" weight of the transaction. It's set based on the cost of processing the transaction on reference hardware.actual_weightis the weight that is found in theExtrinsicSuccessevent for the extrinsic ina block (it's just called
weightin 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_queryFeeDetailsreturnsbase_fee,len_feeandadjusted_weight_fee/The RPC endpoint
payment_queryInforeturnsestimated_weight(calledweightin the response), anda
partialFeevalue, 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
ExtrinsicSuccessevent to find theactual_weight, butalso a
paysFeevalue 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_feewith the actual weight that was used from theExtrinsicSuccessevent.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