Closed adaki2004 closed 1 year ago
@Brechtpd @dantaik So here is a draft version from what we just talked about here.
This is the version of race 2 (moving average is the target) however I'd have some questions after doing some benchmark tests (python code vs. solidity/foundry tests). Tendencies (python code vs this) seems to be the same(slower time of proof -> higher fee and reward) but for example the reward - ratio is very weird in both.
'proof reward
' vs. the 'proposer_fee
' are not on the same 'level'.
Here is an example logs i extracted from my test:
(you can run if you pull this branch and forge build
&&forge test -vv
)
Proving time increases:
1.
Proposer fee: 0
FeeBase : 0
Prover reward: 3320,31250000 (TKO)
2.
Proposer fee: 425000,00000000 (TKO)
FeeBase: 42500000
Prover reward: 7080,07812500 (TKO)
3.
Proposer fee: 453125,00000000 (TKO)
FeeBase: 45312500
Prover reward: 9624,38648001 (TKO)
4.
Proposer fee: 451704,54000000
FeeBase: 45170454
Prover reward: 10780,03874648 (TKO)
Proving time decreases:
1.
Proposer fee: 0
FeeBase : 0
Prover reward: 21240,23437500 (TKO)
2.
Proposer fee: 543750,00000000 (TKO)
FeeBase: 54375000
Prover reward: 523,43750000 (TKO)
3.
Proposer fee: 83750,00000000 (TKO)
FeeBase: 8375000
Prover reward: 402,66423264 (TKO)
4.
Proposer fee: 83333,33000000 (TKO)
FeeBase: 8333333
Prover reward: 288,94990704 (TKO)
So as you see the TKO as fee is much higher, than the reward.
I do not know if this is within the math, but i somewhat conclude both (so in the math somewhere, and also in my code. The latter also comes from the fact that solidity has no floating point operations, so for example 1.001 - 1.99 exp is always 1. I tried to create a workaround for it, and use higher precision, this is also within this branch - please see EXPONENTIAL_REWARD_FACTOR
).
So the python script from here has same kind of an issue when i run them it shows 6-8 x between fee and reward):
print("Quciker proving proving")
propose_block(50000000)
time = 400
prove_block(50000000)
propose_block(50000000)
time = 600
prove_block(50000000)
propose_block(50000000)
time = 650
prove_block(50000000)
propose_block(50000000)
time = 675
prove_block(50000000)
The results are:
Quciker proving proving
******* propose ********
network fee: 0.3668379411737963
prover fee: 500.00000000000006
basefee_network: 8.542737132336227e-09
******* prove ********
proof_time: 400
prover reward: 526700.2765236852
basefee_proof: 0.0015801008295710556
proof_time_average: 77.00000000000001
******* propose ********
network fee: 0.3668379411737963
prover fee: 79005.04147855278
basefee_network: 8.542737132336227e-09
******* prove ********
proof_time: 200
prover reward: 161161.83912022863
basefee_proof: 0.0012409461612257608
proof_time_average: 83.15000000000002
******* propose ********
network fee: 0.3668379411737963
prover fee: 62047.30806128804
basefee_network: 8.542737132336227e-09
******* prove ********
proof_time: 50
prover reward: 32658.909283771933
basefee_proof: 0.0010862353227782547
proof_time_average: 81.49250000000002
******* propose ********
network fee: 0.3668379411737963
prover fee: 54311.76613891274
basefee_network: 8.542737132336227e-09
******* prove ********
proof_time: 25
prover reward: 16402.00134360839
basefee_proof: 0.0010693120755952057
proof_time_average: 78.66787500000001
Quickest way to trace back calculation in the solidity code is searching for 2 debug print keywords:
In proposeBlock()
(LibProposing.sol line 120)In verifyBlock()
(LibVerifying.sol line 160)PS.: HH failing tests are known issues, since testing the functions first with foundry + debugging - will modify tests and add more foundry ones when calculations are aligned.
The large difference between the prover fee paid by the proposer and the reward is because the base fee is calculated based on proof_time_issued
. Because the initial value for that is set to 0
, the basefee will be wildly different from the expected value because the base fee needs some time to adjust to a correct value that will result in a reasonable fee. To get around that you can set proof_time_issued
to an initial value that will result in a fee that makes sense from the start (I also updated my other python code):
basefee_proof = 10**18/L2_BLOCK_GAS_LIMIT
proof_time_issued =
(PROOF_TIME_TARGET * PROOF_ADJUSTMENT_QUOTIENT) *
math.log(basefee_proof * (PROOF_TIME_TARGET * PROOF_ADJUSTMENT_QUOTIENT))
This will make sure that the initial proving fee for a block of L2_BLOCK_GAS_LIMIT
gas will be 1 token (10**18 decimals).
Do make sure that the part in the ln()
is >= 1 because otherwise the initial value for proof_time_issued
< 0 which doesn't make sense.
@Brechtpd @dantaik Feel free to review. There are some outstanding items (see PR desc) otherwise functional wise this is the one Brecht put together in a python script.
Some observations from today's testing. I might not like that much the 'targetTime' anymore - as much as i did - because it has the implications we need to set it very precisely.
2 scenarios.:
If proof time fluctuates then stabilizes AT proof time we get the equilibrium (long term : deposits = withdrawals)
See foundry test: test_reward_and_fee_if_proof_time_increasing_then_stabilizes_at_the_proof_time_target
If proof time increases / decreases then stabilizes below AT proof time we will not get to equilibrium (long term : deposits will be more, than withdrawals). The deposits and withdrawals will be constant, but different from each other obviously. (Withdrawal < Deposits)
Test case name: test_reward_and_fee_if_proof_time_increasing_then_stabilizes_below_the_proof_time_target
The last commit (where we implement a mechanism, (or option) if we not allow minting, just distributing what we have in treasury is the one i like the most, tho I need to write some test cases.
:exclamation: No coverage uploaded for pull request base (
major_protocol_upgrade_rebase@4f15527
). Click here to learn what that means. The diff coverage isn/a
.
@@ Coverage Diff @@
## major_protocol_upgrade_rebase #13489 +/- ##
================================================================
Coverage ? 39.36%
================================================================
Files ? 113
Lines ? 3432
Branches ? 402
================================================================
Hits ? 1351
Misses ? 1992
Partials ? 89
Flag | Coverage Δ | *Carryforward flag | |
---|---|---|---|
bridge-ui | 94.20% <0.00%> (?) |
Carriedforward from 519dca7 | |
eventindexer | ∅ <0.00%> (?) |
Carriedforward from 519dca7 | |
protocol | 0.00% <0.00%> (?) |
||
relayer | 62.55% <0.00%> (?) |
||
ui | 100.00% <0.00%> (?) |
Carriedforward from 519dca7 |
*This pull request uses carry forward flags. Click here to find out more.
:mega: We’re building smart automated test selection to slash your CI/CD build times. Learn more
@Brechtpd @adaki2004 so if allowMinting
is true, is it possible that the supply will go down? When can that happen?
I'm not sure if we should support this config, maybe we should simply allow dynamic minting and burning of tokens.
For useTimeWeightedReward
, I'd also prefer that we remove this parameter and use useTimeWeightedReward=true in our design.
@Brechtpd @adaki2004 so if
allowMinting
is true, is it possible that the supply will go down? When can that happen? I'm not sure if we should support this config, maybe we should simply allow dynamic minting and burning of tokens.
allowMinting == true
is basically the same behavior as we had previously so, burning tokens at the proposing side, minting tokens at the reward side. So pretty sure it should be roughly no change in supply.
For useTimeWeightedReward, I'd also prefer that we remove this parameter and use useTimeWeightedReward=true in our design.
I do also think the non time weighted one is very unlikely to work for us, so makes sense to me to remove it already.
@Brechtpd @adaki2004 so if
allowMinting
is true, is it possible that the supply will go down? When can that happen? I'm not sure if we should support this config, maybe we should simply allow dynamic minting and burning of tokens.
allowMinting == true
is basically the same behavior as we had previously so, burning tokens at the proposing side, minting tokens at the reward side. So pretty sure it should be roughly no change in supply.For useTimeWeightedReward, I'd also prefer that we remove this parameter and use useTimeWeightedReward=true in our design.
I do also think the non time weighted one is very unlikely to work for us, so makes sense to me to remove it already.
@Brechtpd @dantaik Daniel and I had a meeting this morning - and discussed some things, but i'd like to double check with both of you my curent blockers (point 1).
Daniel created with proposed changes this branch + PR:
https://github.com/taikoxyz/taiko-mono/pull/13540
Problem with this solution is that in verifyBlock() he uses fc.gasUsed
, while in proposeBlock() the input.gasLimit
(gasUsed not available at prroposal time).
I dont know how to resolve this ATM,
proposeBlock()
?input.gasLimit
(need to be re-added to struct Block{}
) or we use a constant ?We agreed to pick 1 algorithm - since we anyhow try one / testnet and i'd go for the time weighted treasury pool one and remove the rest.
Reason i'd choose that because the allowMinting
version requires us to be punctual with the proofTimeTarget - otherwise we end up in an unbalanced state and maybe kind of frequent updates.
Since the test results showed:
proofTimeTarget
: ever-increasing baseFee (hance fee and reward)proofTimeTarget
: there is a surplus long term because rewards are smaller than deposits. (So we would need to do something with that surplus. Burn or lower the prooTimeTarget
, etc.)proofTimeTarget
is punctual.
Is it fine with you ?Daniel created with proposed changes this branch + PR: refactor(protocol): recommend changes to Dani's PR (part1) #13540 Problem with this solution is that in verifyBlock() he uses
fc.gasUsed
, while in proposeBlock() theinput.gasLimit
(gasUsed not available at prroposal time). I dont know how to resolve this ATM,If we want to adjust basefee with the gas used (tho it depends highly on the proof time, not the demand for block space (?)) we need to have this information at
proposeBlock()
?If we don't want to adjust it according to the demand for blockspace we can use
input.gasLimit
(need to be re-added tostruct Block{}
) or we use a constant ?
Using gasUsed
for the reward calculation is a bit problematic I think because it could be 0 (empty block), while the prover obviously still has significant costs (some proof generation, but also L1 gas costs that are independent of how much gas is used in a block). For the same reason the proposer set gas limit also isn't really usable. Best we can do is probably to just use the fixed L2 block gas limit on the proposer side and the reward side.
- We agreed to pick 1 algorithm - since we anyhow try one / testnet and i'd go for the time weighted treasury pool one and remove the rest.
That's also the one I like best, if it works of course. :)
Reason i'd choose that because the
allowMinting
version requires us to be punctual with the proofTimeTarget - otherwise we end up in an unbalanced state and maybe kind of frequent updates. Since the test results showed:stable above
proofTimeTarget
: ever-increasing baseFee (hance fee and reward)
Yeah we'd definitely have to make sure that the target is more than enough for a proof to be generated, otherwise it cannot work.
stable but below
proofTimeTarget
: there is a surplus long term because rewards are smaller than deposits. (So we would need to do something with that surplus. Burn or lower theprooTimeTarget
, etc.)
In this case the basefee would going down so people would stop submitting proofs before the target no? Which would then in turn increase the basefee again because proofs are submitted too late.
Only ideal if
proofTimeTarget
is punctual.
I agree that finding a good target would be a bit tricky, though I think with limited impact even if the value isn't ideal (as long as it's not too short).
@Brechtpd @adaki2004 so if
allowMinting
is true, is it possible that the supply will go down? When can that happen? I'm not sure if we should support this config, maybe we should simply allow dynamic minting and burning of tokens.
allowMinting == true
is basically the same behavior as we had previously so, burning tokens at the proposing side, minting tokens at the reward side. So pretty sure it should be roughly no change in supply.For useTimeWeightedReward, I'd also prefer that we remove this parameter and use useTimeWeightedReward=true in our design.
I do also think the non time weighted one is very unlikely to work for us, so makes sense to me to remove it already.
@Brechtpd @dantaik Daniel and I had a meeting this morning - and discussed some things, but i'd like to double check with both of you my curent blockers (point 1).
- Daniel created with proposed changes this branch + PR: refactor(protocol): recommend changes to Dani's PR (part1) #13540 Problem with this solution is that in verifyBlock() he uses
fc.gasUsed
, while in proposeBlock() theinput.gasLimit
(gasUsed not available at prroposal time). I dont know how to resolve this ATM,
- If we want to adjust basefee with the gas used (tho it depends highly on the proof time, not the demand for block space (?)) we need to have this information at
proposeBlock()
?- If we don't want to adjust it according to the demand for blockspace we can use
input.gasLimit
(need to be re-added tostruct Block{}
) or we use a constant ?
- We agreed to pick 1 algorithm - since we anyhow try one / testnet and i'd go for the time weighted treasury pool one and remove the rest. Reason i'd choose that because the
allowMinting
version requires us to be punctual with the proofTimeTarget - otherwise we end up in an unbalanced state and maybe kind of frequent updates. Since the test results showed:
- stable above
proofTimeTarget
: ever-increasing baseFee (hance fee and reward)- stable but below
proofTimeTarget
: there is a surplus long term because rewards are smaller than deposits. (So we would need to do something with that surplus. Burn or lower theprooTimeTarget
, etc.)- Only ideal if
proofTimeTarget
is punctual. Is it fine with you ?
Lets talk about it tomorrow.
@dantaik @Brechtpd
We definitely need to be reasonable with the proofTimeTarget.
How to test possible main net scenario ? Remove the ‘x’ prefix from the function names of the TaikoL1LibTokenomicsMainnet.t.sol and use gas setting: 3000M in foundry.toml ->
@adaki2004 please also fix all the warnings except those related to block.prevrandao
.
Proposer fee /prover reward balanced algorithm
This PR introduces an implementation of the proposer fee / prover reward equilibrium calculation, aiming to balance deposits and withdrawals. The implemented (new
baseFeeProof
) calculation depends on the proving time and utilizes the following parameters:The base fee proof serves as a dynamic fee that adapts to the network conditions, aiming to keep the inflow and outflow of tokens in balance.
See issue discussion: https://github.com/taikoxyz/internal/issues/121 (Especially see Brecht's comment here, with fixed proof time target (Target 1) and 'Mint new tokens when needed' approach - in reality the deposits and withdrawals will be balanced.)
This is an experiment where the base idea is to have a simplified fee / reward calculation structure with TKO for provers and proposers and depends on proving time.
Notes:
targetProofTime
is far (above) from the actual proof time, the system will need more time to reach equilibrium when the time starts stabilizing - (and need to be stabilized below this targettest_reward_and_fee_if_proof_time_stable_but_above_time_target
) -> Setting thetargetProofTime
above the actual edge (where we expect the proof times) does not harm at all, because if proof times are below that, the equilibrium will be reached (deposits ≈ withdrawals) anyhow at some point.What remains to be done in this PR:
mintAllowed = false
mintAllowed = false
L2_1559_rebase
)