Skip to content

Commit

Permalink
fix(protocol): fix config.slotSmoothingFactor and getTimeAdjustedFee …
Browse files Browse the repository at this point in the history
…bug (#13293)

Co-authored-by: David <david@taiko.xyz>
  • Loading branch information
dantaik and davidtaikocha committed Mar 13, 2023
1 parent f5f4fc4 commit 18f3d9f
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 54 deletions.
1 change: 1 addition & 0 deletions packages/protocol/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ npm-debug.log*
# Hardhat files
cache
artifacts
out

# Editors
.vscode
1 change: 1 addition & 0 deletions packages/protocol/contracts/L1/TaikoCustomErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ abstract contract TaikoCustomErrors {
error L1_GAS_LIMIT();
error L1_ID();
error L1_INPUT_SIZE();
error L1_INVALID_CONFIG();
error L1_INVALID_PARAM();
error L1_METADATA_FIELD();
error L1_META_MISMATCH();
Expand Down
1 change: 1 addition & 0 deletions packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ contract TaikoL1 is
LibVerifying.init({
state: state,
genesisBlockHash: _genesisBlockHash,
config: getConfig(),
feeBase: _feeBase
});
}
Expand Down
3 changes: 2 additions & 1 deletion packages/protocol/contracts/L1/libs/LibProposing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ library LibProposing {
isProposal: true,
tNow: uint64(block.timestamp),
tLast: state.lastProposedAt,
tAvg: state.avgBlockTime
tAvg: state.avgBlockTime,
tCap: config.blockTimeCap
});
fee = LibUtils.getSlotsAdjustedFee({
state: state,
Expand Down
23 changes: 13 additions & 10 deletions packages/protocol/contracts/L1/libs/LibUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,23 @@ library LibUtils {
bool isProposal,
uint64 tNow,
uint64 tLast,
uint64 tAvg
uint64 tAvg,
uint64 tCap
) internal view returns (uint256 newFeeBase, uint256 tRelBp) {
if (tAvg == 0) {
if (
tCap == 0 ||
tAvg == 0 ||
config.feeMaxPeriodPctg <= config.feeGracePeriodPctg ||
config.rewardMultiplierPctg <= 100
) {
newFeeBase = state.feeBase;
// tRelBp = 0;
} else {
uint256 _tAvg = tAvg > config.proofTimeCap
? config.proofTimeCap
: tAvg;
uint256 tGrace = (config.feeGracePeriodPctg * _tAvg) / 100;
uint256 tMax = (config.feeMaxPeriodPctg * _tAvg) / 100;
uint256 a = tLast + tGrace;
uint256 b = tNow > a ? tNow - a : 0;
tRelBp = (b.min(tMax) * 10000) / tMax; // [0 - 10000]
uint256 _tAvg = uint256(tAvg).min(tCap);
uint256 grace = (config.feeGracePeriodPctg * _tAvg) / 100;
uint256 max = (config.feeMaxPeriodPctg * _tAvg) / 100;
uint256 t = uint256(tNow - tLast).max(grace).min(max);
tRelBp = ((t - grace) * 10000) / (max - grace); // [0 - 10000]
uint256 alpha = 10000 +
((config.rewardMultiplierPctg - 100) * tRelBp) /
100;
Expand Down
30 changes: 27 additions & 3 deletions packages/protocol/contracts/L1/libs/LibVerifying.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,34 @@ library LibVerifying {
event HeaderSynced(uint256 indexed srcHeight, bytes32 srcHash);

error L1_0_FEE_BASE();
error L1_INVALID_CONFIG();
error L1_INVALID_PARAM();

function init(
TaikoData.State storage state,
TaikoData.Config memory config,
bytes32 genesisBlockHash,
uint256 feeBase
) public {
uint feeBase
) internal {
if (
config.chainId <= 1 ||
config.maxNumBlocks <= 1 ||
config.blockHashHistory == 0 ||
config.blockMaxGasLimit == 0 ||
config.maxTransactionsPerBlock == 0 ||
config.maxBytesPerTxList == 0 ||
config.minTxGasLimit == 0 ||
config.slotSmoothingFactor == 0 ||
config.rewardBurnBips >= 10000 ||
config.feeBaseMAF == 0 ||
config.blockTimeMAF == 0 ||
config.proofTimeMAF == 0 ||
config.blockTimeCap == 0 ||
config.proofTimeCap == 0 ||
config.feeGracePeriodPctg > config.feeMaxPeriodPctg ||
config.rewardMultiplierPctg < 100
) revert L1_INVALID_CONFIG();

if (feeBase == 0) revert L1_0_FEE_BASE();

state.genesisHeight = uint64(block.number);
Expand Down Expand Up @@ -132,13 +154,15 @@ library LibVerifying {
uint64 provenAt,
uint64 proposedAt
) public view returns (uint256 newFeeBase, uint256 reward, uint256 tRelBp) {
if (proposedAt > provenAt) revert L1_INVALID_PARAM();
(newFeeBase, tRelBp) = LibUtils.getTimeAdjustedFee({
state: state,
config: config,
isProposal: false,
tNow: provenAt,
tLast: proposedAt,
tAvg: state.avgProofTime
tAvg: state.avgProofTime,
tCap: config.proofTimeCap
});
reward = LibUtils.getSlotsAdjustedFee({
state: state,
Expand Down
19 changes: 2 additions & 17 deletions packages/protocol/contracts/libs/LibSharedConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,13 @@ pragma solidity ^0.8.18;

import {TaikoData} from "../L1/TaikoData.sol";

/*
> cd taiko-mono/packages/protocol/utils/generate_config
> python3 main.py
Expected block time (seconds): 20
Expected proof time (minutes): 10
Slot availability multiplier: 20
Number of ZKPs required per block before verificaiton: 1
Extra slots (e.g, 50 means 50% more slots): 100
---------
min num slots: 30
---------
maxNumBlocks: 61
slotSmoothingFactor: 16789
*/

library LibSharedConfig {
/// Returns shared configs for both TaikoL1 and TaikoL2 for production.
function getConfig() internal pure returns (TaikoData.Config memory) {
return
TaikoData.Config({
chainId: 167,
maxNumBlocks: 2048, // owner:daniel
maxNumBlocks: 2049, // owner:daniel
blockHashHistory: 40, // owner:daniel
maxVerificationsPerTx: 10, //owner:david. Each time one more block is verified, there will be ~20k more gas cost.
commitConfirmations: 0, // owner:daniel
Expand All @@ -38,7 +23,7 @@ library LibSharedConfig {
maxBytesPerTxList: 120000, // owner:david. Set it to 120KB, since 128KB is the upper size limit of a geth transaction, so using 120KB for the proposed transactions list calldata, 8K for the remaining tx fields.
minTxGasLimit: 21000, // owner:david
anchorTxGasLimit: 250000, // owner:david
slotSmoothingFactor: 16789, // owner:daniel
slotSmoothingFactor: 946649, // owner:daniel
rewardBurnBips: 100, // owner:daniel. 100 basis points or 1%
proposerDepositPctg: 25, // owner:daniel - 25%
// Moving average factors
Expand Down
22 changes: 5 additions & 17 deletions packages/protocol/test/tokenomics/blockFee.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ describe("tokenomics: blockFee", function () {
});

it(
"proposes blocks on interval, blockFee should increase, " +
"proposer's balance for TkoToken should decrease as it pays proposer fee, " +
"proposes blocks on interval, proposer's balance for TkoToken should decrease as it pays proposer fee, " +
"proofReward should increase since more slots are used and " +
"no proofs have been submitted",
async function () {
Expand All @@ -77,19 +76,14 @@ describe("tokenomics: blockFee", function () {
await proposerSigner.getAddress()
);

// do the same for the blockFee, which should increase every block proposal
// with proofs not being submitted.
let lastProofReward = BigNumber.from(0);

// we want to wait for enough blocks until the blockFee is no longer 0, then run our
// tests.
let lastBlockFee = await taikoL1.getBlockFee();

while (lastBlockFee.eq(0)) {
while ((await taikoL1.getBlockFee()).eq(0)) {
await sleep(500);
lastBlockFee = await taikoL1.getBlockFee();
}

let lastProofReward = BigNumber.from(0);

l2Provider.on("block", blockListener(chan, genesisHeight));
/* eslint-disable-next-line */
for await (const blockNumber of chan) {
Expand All @@ -99,7 +93,7 @@ describe("tokenomics: blockFee", function () {
) {
break;
}
const { newProposerBalance, newBlockFee, newProofReward } =
const { newProposerBalance, newProofReward } =
await onNewL2Block(
l2Provider,
blockNumber,
Expand All @@ -114,16 +108,10 @@ describe("tokenomics: blockFee", function () {

expect(newProposerBalance).to.be.lt(lastProposerBalance);

console.log("lastBlockFee", lastBlockFee);
console.log("newBlockFee", newBlockFee);

expect(newBlockFee).to.be.gt(lastBlockFee);

console.log("lastProofReward", lastProofReward);
console.log("newProofReward", newProofReward);
expect(newProofReward).to.be.gt(lastProofReward);

lastBlockFee = newBlockFee;
lastProofReward = newProofReward;
lastProposerBalance = newProposerBalance;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/protocol/test/utils/onNewL2Block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async function onNewL2Block(
const { enableTokenomics } = await taikoL1.getConfig();

const newProofReward = await taikoL1.getProofReward(
new Date().getMilliseconds(),
new Date().getTime(),
meta.timestamp
);

Expand Down
10 changes: 5 additions & 5 deletions packages/protocol/utils/generate_config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
print("Expected proof time (minutes)", end=": ")
proof_time = int(input()) * 60

print("Slot availability multiplier", end=": ")
slot_availability_multiplier = int(input())
if slot_availability_multiplier <= 5:
print("error: Slot availability multiplier must be greater than 5")
print("Max baseFee upside (5 = 5x)", end=": ")
max_basefee_upside = int(input())
if max_basefee_upside < 5:
print("error: Max baseFee upside < 5")
exit(1)

min_num_slots = math.ceil(1.0 * proof_time / block_time)
Expand All @@ -24,7 +24,7 @@
print("min num slots:", min_num_slots)
max_num_slots = min_num_slots + math.ceil(min_num_slots * extra_slots / 100) + 1

k = slot_availability_multiplier
k = max_basefee_upside
n = max_num_slots

# https://www.wolframalpha.com/input?i=solve++%28n%2Bx%29%28n%2Bx-1%29%3Dk*%281%2Bx%29x+for+x
Expand Down

0 comments on commit 18f3d9f

Please sign in to comment.