# Fee Estimation
A B estimates the fee required for a segment in [estimateFee()](https://github.com/livepeer/go-livepeer/blob/731f6a5954e3ea190b9c5f0139491aa31e854a0a/server/segment_rpc.go#L692).
Note: [This line](https://github.com/livepeer/go-livepeer/blob/8bf42baf3b363a03ee432dd1e9676e552e59f12c/server/segment_rpc.go#L709) sets the FPS for the outputs to 120 if transcoding is using passthrough FPS. The historical reason for this was that B did not have access to the FPS of the source segment because it did not do any probing so we just conservatively set the output FPS to 120 - this results in overpaying most of the time if the source FPS < 120, but also provides a higher likelihood that the estimated fee is always >= the actual fee.
At the moment, the payment protocol only requires O to charge for encoding (and not for decoding) so the fee for a segment only depends on the # of pixels encoded i.e. the # of pixels in the set of transcoded outputs. For example, if O transcodes a segment to 720p/30fps and 360p/30fps outputs then the # of pixels encoded would be `(1280 * 720 * 30) + (640 * 360 * 120)`. The # of pixels can then be multiplied by the price per pixel to determine the fee for the segment.
B needs to estimate the fee required for a segment before sending the segment so it can make sure that its balance with O for the current session is sufficient to pay for the segment. If the estimated fee cannot be covered by B's current balance with O for the session then B will send a payment to increase its balance in order to pay for the segment. A payment consists of one or many "probabilistic micropayment tickets" - the sum of the expected value of each ticket in the payment is the overall value of the payment.
B uses the estimated fee to determine the # of tickets to include in a payment i.e. the overall payment value in [newBalanceUpdate()](https://github.com/livepeer/go-livepeer/blob/731f6a5954e3ea190b9c5f0139491aa31e854a0a/server/segment_rpc.go#L730). Internally, [StageUpdate()](https://github.com/livepeer/go-livepeer/blob/731f6a5954e3ea190b9c5f0139491aa31e854a0a/core/accounting.go#L34) is called which will calculate the # of tickets required - the sum of the expected value of the tickets needs to be >= `max(estimatedFee, ticketEV(O))` (see [here](https://github.com/livepeer/go-livepeer/blob/731f6a5954e3ea190b9c5f0139491aa31e854a0a/server/segment_rpc.go#L750)) where `ticketEV(O)` is the required expected value of tickets required by O.
# total ticket EV 3000000000000.00000 for 3 tickets > max total ticket EV 3000000000000.00000
We observed the above error in [these logs](https://eu-metrics-monitoring.livepeer.monster/grafana/explore?orgId=1&left=%7B%22datasource%22:%22P8E80F9AEF21F6940%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22expr%22:%22%7Bapp%3D~%5C%22staging-task-runner%7Ccatalyst%7Cmist%7Ccatalyst-api%5C%22%7D%20%7C%3D%20%5C%22haaffedd%5C%22%22,%22editorMode%22:%22code%22,%22queryType%22:%22range%22%7D%5D,%22range%22:%7B%22from%22:%22now-1h%22,%22to%22:%22now%22%7D%7D).
This occurred for the first segment so we can calculate the estimated fee of the first segment.
```
curl -O https://storage.googleapis.com/lp-us-catalyst-vod-monster/hls/86a8ud00i9cpasp5/mist/source/0.ts
```
`ffprobe` tells us that the segment is ~6s and 1920x1440 resolution.
The output profiles use the following resolutions:
- 1920x1440
- 1280x720
- 640x30
Based on the `estimateFee()`, the estimated fee for a price of 900 wei/pixel would be:
```
pixelsPerSec = (1920 * 1440 * 120) + (1280 * 720 * 120) + (640 * 360 * 120)
dur = 6
price = 900
pixelsPerSec * dur * price = 2538086400000
```
In order to pay for this segment...
```
estimatedFee = 2538086400000
ticketEV = 1000000000000 > estimatedFee -> need to cover this
ticketEV * 3 > estimatedFee
```
So, we need 3 tickets to cover this fee. 3000000000000.00000 is exactly the `maxTicketEV` currently set by our Bs and the check [here](https://github.com/livepeer/go-livepeer/blob/4b6ede31f040a084ff9e55bd798a0d6fffee1e1b/pm/sender.go#L183) is probably triggering the error due to floating point precision causing the sum of the expected value of the tickets to be slightly larger than 3000000000000.00000 in a rightmost decimal place.
In the short term, we can consider increasing `maxTicketEV` to something greater like 2x the current value. The tradeoff for increasing is that this value controls what the maximum value that B will send out with any given payment - generally want to avoid having this be too high or else Os can request larger payments which means more value at risk if transcoding for a segment is not completed (since B pays O before O returns results).
Separately, we could consider removing the 120 FPS placeholder in the fee estimate algorithm so we stop overestimating the fee by so much.
Note that while the high FPS placeholder means that B overestimates the fee (i.e. if the actual source FPS is 30 and we're doing passthrough then the estimate is roughly 3x greater), there is a session balance system between B & O (see [here](https://github.com/livepeer/go-livepeer/blob/731f6a5954e3ea190b9c5f0139491aa31e854a0a/server/segment_rpc.go#L222) and [here](https://github.com/livepeer/go-livepeer/blob/731f6a5954e3ea190b9c5f0139491aa31e854a0a/server/segment_rpc.go#L457)) and O will deduct the actual fee based on the actual # of output pixels from the session balance after finishing a segment.
A way to think about this is that B "credits" its session balance with a payment - if it overpays then it adds extra credit to the session balance. Then O "debits" the session balance with the actual fee for a segment. Any remaining amount in the balance (i.e. from over-crediting) can be used to cover future segments for the session.