Skip to content
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(protocol): fix config.slotSmoothingFactor and getTimeAdjustedFee bug #13293

Merged
merged 11 commits into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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