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

refactor(protocol): improve on top of Dani's PR #13635

Merged
Merged
Show file tree
Hide file tree
Changes from all 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: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ taiko-mono/
│ ├── <a href="./packages/relayer">relayer</a>: Bridge backend relayer in Go
│ ├── <a href="./packages/starter-dapp">starter-dapp</a>: Template for Taiko dapps
│ ├── <a href="./packages/status-page">status-page</a>: Taiko protocol status page
│ ├── <a href="./packages/tokenomics">tokenomics</a>: Taiko tokenomics simulations
│ ├── <a href="./packages/website">website</a>: Main documentation website at taiko.xyz (https://taiko.xyz/)
│ └── <a href="./packages/whitepaper">whitepaper</a>: Whitepaper source files with automated publishing
...
Expand Down
21 changes: 12 additions & 9 deletions packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -158,20 +158,19 @@ contract TaikoL1 is EssentialContract, IXchainSync, TaikoEvents, TaikoErrors {
return state.balances[addr];
}

function getBlockFee() public view returns (uint64 fee) {
fee = LibTokenomics.getBlockFee(state);
function getBlockFee() public view returns (uint64) {
return state.basefee;
}

function getProofReward(
uint64 provenAt,
uint64 proposedAt
) public view returns (uint64 reward) {
reward = LibTokenomics.getProofReward({
state: state,
config: getConfig(),
provenAt: provenAt,
proposedAt: proposedAt
});
) public view returns (uint64) {
return
LibTokenomics.getProofReward({
state: state,
proofTime: provenAt - proposedAt
});
}

function getBlock(
Expand Down Expand Up @@ -252,4 +251,8 @@ contract TaikoL1 is EssentialContract, IXchainSync, TaikoEvents, TaikoErrors {
function getConfig() public pure virtual returns (TaikoData.Config memory) {
return TaikoConfig.getConfig();
}

function getVerifierName(uint16 id) public pure returns (string memory) {
return LibUtils.getVerifierName(id);
}
}
16 changes: 6 additions & 10 deletions packages/protocol/contracts/L1/libs/LibProposing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,13 @@ library LibProposing {
blk.metaHash = LibUtils.hashMetadata(meta);
blk.proposer = msg.sender;

if (config.proofTimeTarget != 0) {
uint64 fee = LibTokenomics.getBlockFee(state);
if (state.balances[msg.sender] < state.basefee)
revert L1_INSUFFICIENT_TOKEN();

if (state.balances[msg.sender] < fee)
revert L1_INSUFFICIENT_TOKEN();

unchecked {
state.balances[msg.sender] -= fee;
state.accBlockFees += fee;
state.accProposedAt += meta.timestamp;
}
unchecked {
state.balances[msg.sender] -= state.basefee;
state.accBlockFees += state.basefee;
state.accProposedAt += meta.timestamp;
}

emit BlockProposed(state.numBlocks, meta);
Expand Down
10 changes: 4 additions & 6 deletions packages/protocol/contracts/L1/libs/LibProving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,11 @@ library LibProving {
}
}

bytes memory verifierId = abi.encodePacked(
"verifier_",
evidence.zkproof.verifierId
);

(bool verified, bytes memory ret) = resolver
.resolve(string(verifierId), false)
.resolve(
LibUtils.getVerifierName(evidence.zkproof.verifierId),
false
)
.staticcall(bytes.concat(instance, evidence.zkproof.data));

if (
Expand Down
99 changes: 36 additions & 63 deletions packages/protocol/contracts/L1/libs/LibTokenomics.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,100 +55,73 @@ library LibTokenomics {
}
}

function getBlockFee(
TaikoData.State storage state
) internal view returns (uint64 fee) {
return state.basefee;
}

function getProofReward(
TaikoData.State storage state,
TaikoData.Config memory config,
uint64 provenAt,
uint64 proposedAt
) internal view returns (uint64 reward) {
(reward, , ) = calculateBasefee(state, config, (provenAt - proposedAt));
}

/**
* Update the baseFee for proofs
*
* @param state The actual state data
* @param config Config data
* @param proofTime The actual proof time
* @return reward Amount of reward given - if blocked is proved and verified
* @return newProofTimeIssued Accumulated proof time
* @return newBasefee New basefee
*/
function calculateBasefee(
function getProofReward(
TaikoData.State storage state,
TaikoData.Config memory config,
uint64 proofTime
)
internal
view
returns (uint64 reward, uint64 newProofTimeIssued, uint64 newBasefee)
{
newProofTimeIssued = state.proofTimeIssued;

newProofTimeIssued = (newProofTimeIssued > config.proofTimeTarget)
? newProofTimeIssued - config.proofTimeTarget
: uint64(0);
newProofTimeIssued += proofTime;

newBasefee = _calcBasefee(
newProofTimeIssued,
config.proofTimeTarget,
config.adjustmentQuotient
);

uint64 numBlocksUnpaid = state.numBlocks -
) internal view returns (uint64) {
uint64 numBlocksUnverified = state.numBlocks -
state.lastVerifiedBlockId -
1;

if (numBlocksUnpaid == 0) {
reward = uint64(0);
if (numBlocksUnverified == 0) {
return 0;
} else {
uint64 totalNumProvingSeconds = uint64(
uint256(numBlocksUnpaid) * block.timestamp - state.accProposedAt
uint256(numBlocksUnverified) *
block.timestamp -
state.accProposedAt
);
///@dev If block timestamp is equal to state.accProposedAt (not really, but theoretically possible)
///@dev there will be division by 0 error
// If block timestamp is equal to state.accProposedAt (not really, but theoretically possible)
// there will be division by 0 error
if (totalNumProvingSeconds == 0) {
totalNumProvingSeconds = 1;
}

reward = uint64(
(uint256(state.accBlockFees) * proofTime) /
totalNumProvingSeconds
);
return
uint64(
(uint256(state.accBlockFees) * proofTime) /
totalNumProvingSeconds
);
}
}

/**
* Calculating the exponential smoothened with (target/quotient)
* Calculate the newProofTimeIssued and newBasefee
*
* @param value Result of cumulativeProofTime
* @param target Target proof time
* @param quotient Quotient
* @return uint64 Calculated new basefee
* @param state The actual state data
* @param config Config data
* @param proofTime The actual proof time
* @return newProofTimeIssued Accumulated proof time
* @return newBasefee New basefee
*/
function _calcBasefee(
uint256 value,
uint256 target,
uint256 quotient
) private pure returns (uint64) {
uint256 x = (value * Math.SCALING_FACTOR_1E18) / (target * quotient);
function getNewBaseFeeandProofTimeIssued(
TaikoData.State storage state,
TaikoData.Config memory config,
uint64 proofTime
) internal view returns (uint64 newProofTimeIssued, uint64 newBasefee) {
newProofTimeIssued = (state.proofTimeIssued > config.proofTimeTarget)
? state.proofTimeIssued - config.proofTimeTarget
: uint64(0);
newProofTimeIssued += proofTime;

uint256 x = (newProofTimeIssued * Math.SCALING_FACTOR_1E18) /
(config.proofTimeTarget * config.adjustmentQuotient);

if (Math.MAX_EXP_INPUT <= x) {
x = Math.MAX_EXP_INPUT;
}

uint256 result = (uint256(Math.exp(int256(x))) /
Math.SCALING_FACTOR_1E18) / (target * quotient);

if (result > type(uint64).max) return type(uint64).max;
Math.SCALING_FACTOR_1E18) /
(config.proofTimeTarget * config.adjustmentQuotient);

return uint64(result);
newBasefee = uint64(result.min(type(uint64).max));
}
}
4 changes: 4 additions & 0 deletions packages/protocol/contracts/L1/libs/LibUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,8 @@ library LibUtils {
mstore(0x40, add(ptr, 64))
}
}

function getVerifierName(uint16 id) public pure returns (string memory) {
return string(bytes.concat(bytes("verifier_"), bytes2(id)));
}
}
21 changes: 7 additions & 14 deletions packages/protocol/contracts/L1/libs/LibVerifying.sol
Original file line number Diff line number Diff line change
Expand Up @@ -130,23 +130,16 @@ library LibVerifying {
uint24 fcId
) private {
if (config.proofTimeTarget != 0) {
uint256 proofTime;
uint64 proofTime;
unchecked {
proofTime = (fc.provenAt - blk.proposedAt);
proofTime = uint64(fc.provenAt - blk.proposedAt);
}

(
uint64 reward,
uint64 proofTimeIssued,
uint64 newBasefee
) = LibTokenomics.calculateBasefee(
state,
config,
uint64(proofTime)
);

state.basefee = newBasefee;
state.proofTimeIssued = proofTimeIssued;
uint64 reward = LibTokenomics.getProofReward(state, proofTime);

(state.proofTimeIssued, state.basefee) = LibTokenomics
.getNewBaseFeeandProofTimeIssued(state, config, proofTime);

unchecked {
state.accBlockFees -= reward;
state.accProposedAt -= blk.proposedAt;
Expand Down
8 changes: 3 additions & 5 deletions packages/protocol/script/DeployOnL1.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ contract DeployOnL1 is Script, AddressResolver {
uint256 public taikoTokenPremintAmount =
vm.envUint("TAIKO_TOKEN_PREMINT_AMOUNT");

TaikoL1 taikoL1;
address public addressManagerProxy;

// New fee/reward related variables
Expand Down Expand Up @@ -118,7 +119,7 @@ contract DeployOnL1 is Script, AddressResolver {
console.log("BullToken", bullToken);

// TaikoL1
TaikoL1 taikoL1 = new TaikoL1();
taikoL1 = new TaikoL1();

uint64 feeBase = 1 ** 8; // Taiko Token's decimals is 8, not 18

Expand Down Expand Up @@ -200,10 +201,7 @@ contract DeployOnL1 is Script, AddressResolver {
);

for (uint16 i = 0; i < plonkVerifiers.length; ++i) {
setAddress(
string(abi.encodePacked("verifier_", i)),
plonkVerifiers[i]
);
setAddress(taikoL1.getVerifierName(i), plonkVerifiers[i]);
}
}

Expand Down
10 changes: 5 additions & 5 deletions packages/protocol/test2/LibLn.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
pragma solidity ^0.8.18;

// Taken from: https://github.com/recmo/experiment-solexp/blob/main/src/FixedPointMathLib.sol
import {LibFixedPointMath} from "../contracts/thirdparty/LibFixedPointMath.sol";

library LibLn {
error Overflow();
error LnNegativeUndefined();

// Helper, common variable for 'off-chain' initProofTimeTarget generation
uint256 public constant SCALING_E18 = 1e18;

// Integer log2 (alternative implementation)
// @returns floor(log2(x)) if x is nonzero, otherwise 0.
// Consumes 317 gas. This could have been an 3 gas EVM opcode though.
Expand Down Expand Up @@ -216,11 +215,12 @@ library LibLn {
) public pure returns (uint64 initProofTimeIssued) {
uint256 scale = uint256(proofTimeTarget) * adjustmentQuotient;
// ln_pub() expects 1e18 fixed format
uint256 lnReq = scale * basefee * SCALING_E18;
uint256 lnReq = scale * basefee * LibFixedPointMath.SCALING_FACTOR_1E18;
require(lnReq <= uint256(type(int256).max));
int256 log_result = ln_pub(int256(lnReq));
initProofTimeIssued = uint64(
((scale * (uint256(log_result))) / (SCALING_E18))
((scale * (uint256(log_result))) /
(LibFixedPointMath.SCALING_FACTOR_1E18))
);
}
}
10 changes: 3 additions & 7 deletions packages/protocol/test2/TaikoL1.sim.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,14 @@ contract TaikoL1Simulation is TaikoL1TestBase, FoundryRandom {
);

TaikoL1TestBase.setUp();
// TODO(daniel): update string key generation using bytes.concat
_registerAddress(
string(abi.encodePacked("verifier_", uint16(100))),
address(new Verifier())
);
registerAddress(L1.getVerifierName(100), address(new Verifier()));
}

function testGeneratingManyRandomBlocks() external {
uint256 time = block.timestamp;
assertEq(time, 1);

_depositTaikoToken(Alice, 1E6 * 1E8, 10000 ether);
depositTaikoToken(Alice, 1E6 * 1E8, 10000 ether);

bytes32 parentHash = GENESIS_BLOCK_HASH;
uint32 parentGasUsed;
Expand Down Expand Up @@ -165,7 +161,7 @@ contract TaikoL1Simulation is TaikoL1TestBase, FoundryRandom {

function pickRandomProveTime(
uint256 randomNum
) internal view returns (uint8) {
) internal pure returns (uint8) {
// Result shall be between 8-12 (inclusive)
// so that it will result in a 160-240s proof time
// while the proof time target is 200s
Expand Down
10 changes: 5 additions & 5 deletions packages/protocol/test2/TaikoL1.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ contract TaikoL1Test is TaikoL1TestBase {

/// @dev Test we can propose, prove, then verify more blocks than 'maxNumProposedBlocks'
function test_more_blocks_than_ring_buffer_size() external {
_depositTaikoToken(Alice, 1E6 * 1E8, 100 ether);
_depositTaikoToken(Bob, 1E6 * 1E8, 100 ether);
_depositTaikoToken(Carol, 1E6 * 1E8, 100 ether);
depositTaikoToken(Alice, 1E6 * 1E8, 100 ether);
depositTaikoToken(Bob, 1E6 * 1E8, 100 ether);
depositTaikoToken(Carol, 1E6 * 1E8, 100 ether);

bytes32 parentHash = GENESIS_BLOCK_HASH;
uint32 parentGasUsed = 0;
Expand Down Expand Up @@ -87,7 +87,7 @@ contract TaikoL1Test is TaikoL1TestBase {
/// @dev Test more than one block can be proposed, proven, & verified in the
/// same L1 block.
function test_multiple_blocks_in_one_L1_block() external {
_depositTaikoToken(Alice, 1000 * 1E8, 1000 ether);
depositTaikoToken(Alice, 1000 * 1E8, 1000 ether);

bytes32 parentHash = GENESIS_BLOCK_HASH;
uint32 parentGasUsed = 0;
Expand Down Expand Up @@ -122,7 +122,7 @@ contract TaikoL1Test is TaikoL1TestBase {

/// @dev Test verifying multiple blocks in one transaction
function test_verifying_multiple_blocks_once() external {
_depositTaikoToken(Alice, 1E6 * 1E8, 1000 ether);
depositTaikoToken(Alice, 1E6 * 1E8, 1000 ether);

bytes32 parentHash = GENESIS_BLOCK_HASH;
uint32 parentGasUsed = 0;
Expand Down
Loading