From 76806676383a8bbbbb61accc44576213322f1665 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 1 Aug 2024 14:56:57 +0800 Subject: [PATCH 01/17] more --- .../protocol/contracts/L2/Lib1559Math.sol | 32 +++++------------- packages/protocol/test/L2/Lib1559Math.t.sol | 33 +++++++++++++++++++ 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/packages/protocol/contracts/L2/Lib1559Math.sol b/packages/protocol/contracts/L2/Lib1559Math.sol index 1ee53ef118d..ae4c19d2b3e 100644 --- a/packages/protocol/contracts/L2/Lib1559Math.sol +++ b/packages/protocol/contracts/L2/Lib1559Math.sol @@ -43,34 +43,18 @@ library Lib1559Math { /// @dev eth_qty(excess_gas_issued) / (TARGET * ADJUSTMENT_QUOTIENT) /// @param _gasExcess The gas excess value - /// @param _adjustmentFactor The product of gasTarget and adjustmentQuotient - function basefee( - uint256 _gasExcess, - uint256 _adjustmentFactor - ) - internal - pure - returns (uint256) - { - if (_adjustmentFactor == 0) { - revert EIP1559_INVALID_PARAMS(); - } - return _ethQty(_gasExcess, _adjustmentFactor) / LibFixedPointMath.SCALING_FACTOR; + /// @param _target The product of gasTarget and adjustmentQuotient + function basefee(uint256 _gasExcess, uint256 _target) internal pure returns (uint256) { + if (_target == 0) revert EIP1559_INVALID_PARAMS(); + return ethQty(_gasExcess, _target) / _target; } - /// @dev exp(gas_qty / TARGET / ADJUSTMENT_QUOTIENT) - function _ethQty( - uint256 _gasExcess, - uint256 _adjustmentFactor - ) - private - pure - returns (uint256) - { - uint256 input = _gasExcess * LibFixedPointMath.SCALING_FACTOR / _adjustmentFactor; + /// @dev exp(_gasExcess / _target) + function ethQty(uint256 _gasExcess, uint256 _target) internal pure returns (uint256) { + uint256 input = _gasExcess * LibFixedPointMath.SCALING_FACTOR / _target; if (input > LibFixedPointMath.MAX_EXP_INPUT) { input = LibFixedPointMath.MAX_EXP_INPUT; } - return uint256(LibFixedPointMath.exp(int256(input))); + return uint256(LibFixedPointMath.exp(int256(input))) / LibFixedPointMath.SCALING_FACTOR; } } diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index a4d275d26be..b471ac9a5d8 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -6,8 +6,41 @@ import "../TaikoTest.sol"; contract TestLib1559Math is TaikoTest { using LibMath for uint256; + uint256 public constant gips = 2_000_000; // gas issuance per second + uint256 public constant quotient = 4; + uint256 public constant target = gips * quotient; + + function test_ethQty() external { + assertEq(Lib1559Math.ethQty(0, 60_000_000 / 8), 1); + assertEq(Lib1559Math.ethQty(60_000_000, 60_000_000 / 8), 2980); + assertEq(Lib1559Math.ethQty(60_000_000 * 2, 60_000_000 / 8), 8_886_110); + assertEq(Lib1559Math.ethQty(60_000_000 * 3, 60_000_000 / 8), 26_489_122_129); + assertEq(Lib1559Math.ethQty(60_000_000 * 4, 60_000_000 / 8), 78_962_960_182_680); + assertEq( + Lib1559Math.ethQty(60_000_000 * 10, 60_000_000 / 8), + 55_406_223_843_935_100_525_863_115_942_268_902 + ); + assertEq( + Lib1559Math.ethQty(60_000_000 * 100, 60_000_000 / 8), + 57_896_044_618_658_097_650_144_101_621_524_338_577_433_870_140_581_303_254_786 + ); + } + + function test_basefee() external { + uint256 basefee; + for (uint256 i; basefee <= 5000;) { + // uint 0.01 gwei + basefee = Lib1559Math.basefee(i * gips, target) / 10_000_000; + if (basefee != 0) { + console2.log("basefee (uint 0.01gwei) after", i, "seconds:", basefee); + } + i += 12; + } + } + function test_eip1559_math() external pure { LibL2Config.Config memory config = LibL2Config.get(); + uint256 adjustmentFactor = config.gasTargetPerL1Block * config.basefeeAdjustmentQuotient; uint256 baseFee; From d207123345fc6eb3a53f785e85cd97e8cc0f2253 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 1 Aug 2024 15:37:10 +0800 Subject: [PATCH 02/17] improve basefee impl --- packages/protocol/contracts/L1/TaikoData.sol | 4 +- packages/protocol/contracts/L1/TaikoL1.sol | 2 +- .../protocol/contracts/L1/libs/LibData.sol | 2 +- .../contracts/L1/libs/LibProposing.sol | 2 +- .../protocol/contracts/L2/Lib1559Math.sol | 6 +- packages/protocol/contracts/L2/TaikoL2.sol | 68 +++++++++++-------- .../protocol/contracts/hekla/HeklaTaikoL1.sol | 2 +- .../contracts/mainnet/MainnetTaikoL1.sol | 2 +- packages/protocol/test/L2/Lib1559Math.t.sol | 68 +++++++------------ .../test/L2/TaikoL2EIP1559Configurable.sol | 2 +- 10 files changed, 75 insertions(+), 83 deletions(-) diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol index e2cae944c1a..8b08b699a14 100644 --- a/packages/protocol/contracts/L1/TaikoData.sol +++ b/packages/protocol/contracts/L1/TaikoData.sol @@ -41,7 +41,7 @@ library TaikoData { // --------------------------------------------------------------------- uint8 basefeeAdjustmentQuotient; uint8 basefeeSharingPctg; - uint32 gasTargetPerL1Block; + uint32 gasIssuancePerSecond; // --------------------------------------------------------------------- // Group 6: Others // --------------------------------------------------------------------- @@ -126,7 +126,7 @@ library TaikoData { uint8 blobIndex; uint8 basefeeAdjustmentQuotient; uint8 basefeeSharingPctg; - uint32 gasTargetPerL1Block; + uint32 gasIssuancePerSecond; } /// @dev Struct representing transition to be proven. diff --git a/packages/protocol/contracts/L1/TaikoL1.sol b/packages/protocol/contracts/L1/TaikoL1.sol index e4d70136e6c..e590bb1851b 100644 --- a/packages/protocol/contracts/L1/TaikoL1.sol +++ b/packages/protocol/contracts/L1/TaikoL1.sol @@ -287,7 +287,7 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { maxAnchorHeightOffset: 64, basefeeAdjustmentQuotient: 8, basefeeSharingPctg: 75, - gasTargetPerL1Block: 60_000_000, + gasIssuancePerSecond: 2_000_000, ontakeForkHeight: 374_400 // = 7200 * 52 }); } diff --git a/packages/protocol/contracts/L1/libs/LibData.sol b/packages/protocol/contracts/L1/libs/LibData.sol index d8ea53b7432..f497b7fa0ac 100644 --- a/packages/protocol/contracts/L1/libs/LibData.sol +++ b/packages/protocol/contracts/L1/libs/LibData.sol @@ -78,7 +78,7 @@ library LibData { blobIndex: 0, basefeeAdjustmentQuotient: 0, basefeeSharingPctg: 0, - gasTargetPerL1Block: 0 + gasIssuancePerSecond: 0 }); } } diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index 0e8b2c893cd..14afcf4f5cd 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -176,7 +176,7 @@ library LibProposing { blobIndex: local.params.blobIndex, basefeeAdjustmentQuotient: _config.basefeeAdjustmentQuotient, basefeeSharingPctg: _config.basefeeSharingPctg, - gasTargetPerL1Block: _config.gasTargetPerL1Block + gasIssuancePerSecond: _config.gasIssuancePerSecond }); } diff --git a/packages/protocol/contracts/L2/Lib1559Math.sol b/packages/protocol/contracts/L2/Lib1559Math.sol index ae4c19d2b3e..6504b759617 100644 --- a/packages/protocol/contracts/L2/Lib1559Math.sol +++ b/packages/protocol/contracts/L2/Lib1559Math.sol @@ -36,9 +36,6 @@ library Lib1559Math { // block, however, this block's gas used will affect the next // block's base fee. basefee_ = basefee(gasExcess_, uint256(_adjustmentQuotient) * _gasTarget); - - // Always make sure basefee is nonzero, this is required by the node. - if (basefee_ == 0) basefee_ = 1; } /// @dev eth_qty(excess_gas_issued) / (TARGET * ADJUSTMENT_QUOTIENT) @@ -46,7 +43,8 @@ library Lib1559Math { /// @param _target The product of gasTarget and adjustmentQuotient function basefee(uint256 _gasExcess, uint256 _target) internal pure returns (uint256) { if (_target == 0) revert EIP1559_INVALID_PARAMS(); - return ethQty(_gasExcess, _target) / _target; + uint256 fee = ethQty(_gasExcess, _target) / _target; + return fee == 0 ? 1 : fee; } /// @dev exp(_gasExcess / _target) diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index 1fcfe68709c..b8cc1015b05 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -35,12 +35,12 @@ contract TaikoL2 is EssentialContract { /// @notice The gas excess value used to calculate the base fee. /// @dev Slot 3. - uint64 public gasExcess; + uint64 public parentGasExcess; /// @notice The last synced L1 block height. uint64 public lastSyncedBlock; uint64 private parentTimestamp; - uint64 private __deprecated2; // was __currentBlockTimestamp + uint64 private parentGasTarget; /// @notice The L1's chain ID. uint64 public l1ChainId; @@ -49,8 +49,8 @@ contract TaikoL2 is EssentialContract { /// @notice Emitted when the latest L1 block details are anchored to L2. /// @param parentHash The hash of the parent block. - /// @param gasExcess The gas excess value used to calculate the base fee. - event Anchored(bytes32 parentHash, uint64 gasExcess); + /// @param parentGasExcess The gas excess value used to calculate the base fee. + event Anchored(bytes32 parentHash, uint64 parentGasExcess); error L2_BASEFEE_MISMATCH(); error L2_FORK_ERROR(); @@ -65,12 +65,12 @@ contract TaikoL2 is EssentialContract { /// @param _owner The owner of this contract. msg.sender will be used if this value is zero. /// @param _rollupAddressManager The address of the {AddressManager} contract. /// @param _l1ChainId The ID of the base layer. - /// @param _gasExcess The initial gasExcess. + /// @param _parentGasExcess The initial parentGasExcess. function init( address _owner, address _rollupAddressManager, uint64 _l1ChainId, - uint64 _gasExcess + uint64 _parentGasExcess ) external initializer @@ -95,11 +95,16 @@ contract TaikoL2 is EssentialContract { } l1ChainId = _l1ChainId; - gasExcess = _gasExcess; - parentTimestamp = uint64(block.timestamp); + parentGasExcess = _parentGasExcess; (publicInputHash,) = _calcPublicInputHash(block.number); } + function init2() external reinitializer(2) { + parentGasExcess = 0; + parentTimestamp = uint64(block.timestamp); + parentGasTarget = 0; + } + /// @notice Anchors the latest L1 block details to L2 for cross-layer /// message verification. /// @dev This function can be called freely as the golden touch private key is publicly known, @@ -134,7 +139,7 @@ contract TaikoL2 is EssentialContract { uint64 _anchorBlockId, bytes32 _anchorStateRoot, uint32 _parentGasUsed, - uint32 _gasTargetPerL1Block, + uint32 _gasIssuancePerSecond, uint8 _basefeeAdjustmentQuotient ) external @@ -145,7 +150,7 @@ contract TaikoL2 is EssentialContract { _anchorBlockId, _anchorStateRoot, _parentGasUsed, - _gasTargetPerL1Block, + _gasIssuancePerSecond, _basefeeAdjustmentQuotient ); } @@ -177,21 +182,21 @@ contract TaikoL2 is EssentialContract { /// @param _anchorBlockId The synced L1 height in the next Taiko block /// @param _parentGasUsed Gas used in the parent block. /// @return basefee_ The calculated EIP-1559 base fee per gas. - /// @return gasExcess_ The new gasExcess value. + /// @return parentGasExcess_ The new parentGasExcess value. function getBasefee( uint64 _anchorBlockId, uint32 _parentGasUsed ) public view - returns (uint256 basefee_, uint64 gasExcess_) + returns (uint256 basefee_, uint64 parentGasExcess_) { LibL2Config.Config memory config = getConfig(); - (basefee_, gasExcess_) = Lib1559Math.calc1559BaseFee( + (basefee_, parentGasExcess_) = Lib1559Math.calc1559BaseFee( config.gasTargetPerL1Block, config.basefeeAdjustmentQuotient, - gasExcess, + parentGasExcess, uint64(_anchorBlockId - lastSyncedBlock) * config.gasTargetPerL1Block, _parentGasUsed ); @@ -225,29 +230,29 @@ contract TaikoL2 is EssentialContract { /// @notice Calculates the basefee and the new gas excess value based on parent gas used and gas /// excess. - /// @param _gasTargetPerL1Block The gas target for L2 based on each L1 block. + /// @param _gasIssuancePerSecond The gas target for L2 per second. /// @param _blocktime The time between this block and the parent block. /// @param _adjustmentQuotient The gas adjustment quotient. - /// @param _gasExcess The current gas excess value. + /// @param _parentGasExcess The current gas excess value. /// @param _parentGasUsed Total gas used by the parent block. /// @return basefee_ Next block's base fee. - /// @return gasExcess_ The new gas excess value. + /// @return parentGasExcess_ The new gas excess value. function calculateBaseFee( - uint32 _gasTargetPerL1Block, + uint32 _gasIssuancePerSecond, uint64 _blocktime, uint8 _adjustmentQuotient, - uint64 _gasExcess, + uint64 _parentGasExcess, uint32 _parentGasUsed ) public pure - returns (uint256 basefee_, uint64 gasExcess_) + returns (uint256 basefee_, uint64 parentGasExcess_) { return Lib1559Math.calc1559BaseFee( - _gasTargetPerL1Block, + _gasIssuancePerSecond, _adjustmentQuotient, - _gasExcess, - _blocktime * _gasTargetPerL1Block / 12, + _parentGasExcess, + _blocktime * _gasIssuancePerSecond, _parentGasUsed ); } @@ -256,7 +261,7 @@ contract TaikoL2 is EssentialContract { uint64 _anchorBlockId, bytes32 _anchorStateRoot, uint32 _parentGasUsed, - uint32 _gasTargetPerL1Block, + uint32 _gasIssuancePerSecond, uint8 _basefeeAdjustmentQuotient ) private @@ -276,14 +281,22 @@ contract TaikoL2 is EssentialContract { _calcPublicInputHash(parentId); if (publicInputHash != currentPublicInputHash) revert L2_PUBLIC_INPUT_HASH_MISMATCH(); + // Check if the gas settings has changed + uint64 newGasTarget = uint64(_gasIssuancePerSecond) * _basefeeAdjustmentQuotient; + if (newGasTarget < parentGasTarget) { + // Reset parentGasExcess to avoid sudden increase of basefee. See + // test_change_of_quotient_and_gips in Lib1559Math.t.sol. + parentGasExcess = 0; + } + // Verify the base fee per gas is correct (uint256 basefee, uint64 newGasExcess) = block.number < ontakeForkHeight() ? getBasefee(_anchorBlockId, _parentGasUsed) : calculateBaseFee( - _gasTargetPerL1Block, + _gasIssuancePerSecond, uint64(block.timestamp - parentTimestamp), _basefeeAdjustmentQuotient, - gasExcess, + parentGasExcess, _parentGasUsed ); @@ -305,8 +318,9 @@ contract TaikoL2 is EssentialContract { l2Hashes[parentId] = parentHash; publicInputHash = newPublicInputHash; - gasExcess = newGasExcess; + parentGasExcess = newGasExcess; parentTimestamp = uint64(block.timestamp); + parentGasTarget = newGasExcess; emit Anchored(parentHash, newGasExcess); } diff --git a/packages/protocol/contracts/hekla/HeklaTaikoL1.sol b/packages/protocol/contracts/hekla/HeklaTaikoL1.sol index 1e8e8c01361..eb2ce129066 100644 --- a/packages/protocol/contracts/hekla/HeklaTaikoL1.sol +++ b/packages/protocol/contracts/hekla/HeklaTaikoL1.sol @@ -22,7 +22,7 @@ contract HeklaTaikoL1 is TaikoL1 { maxAnchorHeightOffset: 64, basefeeAdjustmentQuotient: 8, basefeeSharingPctg: 75, - gasTargetPerL1Block: 60_000_000, + gasIssuancePerSecond: 2_000_000, ontakeForkHeight: 720_000 // = 7200 * 100 }); } diff --git a/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol b/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol index fb09b4b3853..6e8600d3613 100644 --- a/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol +++ b/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol @@ -32,7 +32,7 @@ contract MainnetTaikoL1 is TaikoL1 { maxAnchorHeightOffset: 64, basefeeAdjustmentQuotient: 8, basefeeSharingPctg: 75, - gasTargetPerL1Block: 60_000_000, + gasIssuancePerSecond: 2_000_000, ontakeForkHeight: 374_400 // = 7200 * 52 }); } diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index b471ac9a5d8..fbdd0af7015 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -6,66 +6,46 @@ import "../TaikoTest.sol"; contract TestLib1559Math is TaikoTest { using LibMath for uint256; - uint256 public constant gips = 2_000_000; // gas issuance per second - uint256 public constant quotient = 4; - uint256 public constant target = gips * quotient; - function test_ethQty() external { - assertEq(Lib1559Math.ethQty(0, 60_000_000 / 8), 1); - assertEq(Lib1559Math.ethQty(60_000_000, 60_000_000 / 8), 2980); - assertEq(Lib1559Math.ethQty(60_000_000 * 2, 60_000_000 / 8), 8_886_110); - assertEq(Lib1559Math.ethQty(60_000_000 * 3, 60_000_000 / 8), 26_489_122_129); - assertEq(Lib1559Math.ethQty(60_000_000 * 4, 60_000_000 / 8), 78_962_960_182_680); - assertEq( - Lib1559Math.ethQty(60_000_000 * 10, 60_000_000 / 8), - 55_406_223_843_935_100_525_863_115_942_268_902 - ); - assertEq( - Lib1559Math.ethQty(60_000_000 * 100, 60_000_000 / 8), - 57_896_044_618_658_097_650_144_101_621_524_338_577_433_870_140_581_303_254_786 - ); + assertEq(Lib1559Math.ethQty(0, 60_000_000 * 8), 1); + assertEq(Lib1559Math.ethQty(60_000_000, 60_000_000 * 8), 1); + assertEq(Lib1559Math.ethQty(60_000_000 * 100, 60_000_000 * 8), 268_337); + assertEq(Lib1559Math.ethQty(60_000_000 * 200, 60_000_000 * 8), 72_004_899_337); } function test_basefee() external { uint256 basefee; for (uint256 i; basefee <= 5000;) { // uint 0.01 gwei - basefee = Lib1559Math.basefee(i * gips, target) / 10_000_000; + basefee = Lib1559Math.basefee(i * 2_000_000, 2_000_000 * 4) / 10_000_000; if (basefee != 0) { console2.log("basefee (uint 0.01gwei) after", i, "seconds:", basefee); } - i += 12; + i += 1; } } - function test_eip1559_math() external pure { - LibL2Config.Config memory config = LibL2Config.get(); - - uint256 adjustmentFactor = config.gasTargetPerL1Block * config.basefeeAdjustmentQuotient; - - uint256 baseFee; - uint256 i; - uint256 target = 0.01 gwei; + function test_change_of_quotient_and_gips() public { + uint256 excess = 150 * 2_000_000; - for (uint256 k; k < 5; ++k) { - for (; baseFee < target; ++i) { - baseFee = Lib1559Math.basefee(config.gasTargetPerL1Block * i, adjustmentFactor); - } - console2.log("base fee:", baseFee); - console2.log(" gasExcess:", config.gasTargetPerL1Block * i); - console2.log(" i:", i); - target *= 10; - } - } + // uint 0.01 gwei + uint256 basefee = Lib1559Math.basefee(excess, 2_000_000 * 4) / 10_000_000; + console2.log("basefee (uint 0.01gwei) with quotient = 4: ", basefee); - function test_eip1559_math_max() external pure { - LibL2Config.Config memory config = LibL2Config.get(); - uint256 adjustmentFactor = config.gasTargetPerL1Block * config.basefeeAdjustmentQuotient; + // basefee will decrease if gas issued per second or quotient increased. + basefee = Lib1559Math.basefee(excess, 2_000_000 * 8) / 10_000_000; + console2.log("basefee (uint 0.01gwei) with quotient = 8: ", basefee); + basefee = Lib1559Math.basefee(excess, 4_000_000 * 4) / 10_000_000; + console2.log("basefee (uint 0.01gwei) with gips = 4_000_000: ", basefee); - uint256 gasExcess = type(uint64).max; - uint256 baseFee = Lib1559Math.basefee(gasExcess, adjustmentFactor); + // basefee will increase if gas issued per second or quotient decreased. + basefee = Lib1559Math.basefee(excess, 2_000_000 * 2) / 10_000_000; + console2.log("basefee (uint 0.01gwei) with quotient = 2: ", basefee); + basefee = Lib1559Math.basefee(excess, 1_000_000 * 4) / 10_000_000; + console2.log("basefee (uint 0.01gwei) with gips = 1_000_000: ", basefee); - console2.log("base fee (gwei):", baseFee / 1 gwei); - console2.log(" gasExcess:", gasExcess); + // basefee will be the same if gas issued per second * quotient decreased remains same + basefee = Lib1559Math.basefee(excess, 4_000_000 * 2) / 10_000_000; + console2.log("basefee (uint 0.01gwei) ", basefee); } } diff --git a/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol b/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol index e8402ce58f4..75b2cc0529d 100644 --- a/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol +++ b/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol @@ -34,7 +34,7 @@ contract TaikoL2EIP1559Configurable is TaikoL2 { if (_newConfig.basefeeAdjustmentQuotient == 0) revert L2_INVALID_CONFIG(); customConfig = _newConfig; - gasExcess = _newGasExcess; + parentGasExcess = _newGasExcess; emit ConfigAndExcessChanged(_newConfig, _newGasExcess); } From 219602f30019e9041db0d2740364121b2537c519 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 1 Aug 2024 15:37:50 +0800 Subject: [PATCH 03/17] Update Lib1559Math.t.sol --- packages/protocol/test/L2/Lib1559Math.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index fbdd0af7015..cfa55a0a74d 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -13,7 +13,7 @@ contract TestLib1559Math is TaikoTest { assertEq(Lib1559Math.ethQty(60_000_000 * 200, 60_000_000 * 8), 72_004_899_337); } - function test_basefee() external { + function test_basefee() external pure { uint256 basefee; for (uint256 i; basefee <= 5000;) { // uint 0.01 gwei @@ -25,7 +25,7 @@ contract TestLib1559Math is TaikoTest { } } - function test_change_of_quotient_and_gips() public { + function test_change_of_quotient_and_gips() public pure { uint256 excess = 150 * 2_000_000; // uint 0.01 gwei From f1a6cd9629ef3229b3e3ca81ddbdfbca16cf0c1a Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 1 Aug 2024 15:49:54 +0800 Subject: [PATCH 04/17] more --- packages/protocol/contracts/L1/TaikoL1.sol | 2 +- packages/protocol/contracts/hekla/HeklaTaikoL1.sol | 2 +- packages/protocol/contracts/mainnet/MainnetTaikoL1.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/protocol/contracts/L1/TaikoL1.sol b/packages/protocol/contracts/L1/TaikoL1.sol index e590bb1851b..96a5651eddb 100644 --- a/packages/protocol/contracts/L1/TaikoL1.sol +++ b/packages/protocol/contracts/L1/TaikoL1.sol @@ -287,7 +287,7 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { maxAnchorHeightOffset: 64, basefeeAdjustmentQuotient: 8, basefeeSharingPctg: 75, - gasIssuancePerSecond: 2_000_000, + gasIssuancePerSecond: 5_000_000, ontakeForkHeight: 374_400 // = 7200 * 52 }); } diff --git a/packages/protocol/contracts/hekla/HeklaTaikoL1.sol b/packages/protocol/contracts/hekla/HeklaTaikoL1.sol index eb2ce129066..32299e5d74d 100644 --- a/packages/protocol/contracts/hekla/HeklaTaikoL1.sol +++ b/packages/protocol/contracts/hekla/HeklaTaikoL1.sol @@ -22,7 +22,7 @@ contract HeklaTaikoL1 is TaikoL1 { maxAnchorHeightOffset: 64, basefeeAdjustmentQuotient: 8, basefeeSharingPctg: 75, - gasIssuancePerSecond: 2_000_000, + gasIssuancePerSecond: 5_000_000, ontakeForkHeight: 720_000 // = 7200 * 100 }); } diff --git a/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol b/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol index 6e8600d3613..c2ff8c232c8 100644 --- a/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol +++ b/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol @@ -32,7 +32,7 @@ contract MainnetTaikoL1 is TaikoL1 { maxAnchorHeightOffset: 64, basefeeAdjustmentQuotient: 8, basefeeSharingPctg: 75, - gasIssuancePerSecond: 2_000_000, + gasIssuancePerSecond: 5_000_000, ontakeForkHeight: 374_400 // = 7200 * 52 }); } From f5849109be82037217fa930999cc477bd1dbf1e9 Mon Sep 17 00:00:00 2001 From: dantaik Date: Thu, 1 Aug 2024 07:51:23 +0000 Subject: [PATCH 05/17] forge fmt & update contract layout table --- packages/protocol/contract_layout.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/protocol/contract_layout.md b/packages/protocol/contract_layout.md index 26860eabd3a..bec4136538e 100644 --- a/packages/protocol/contract_layout.md +++ b/packages/protocol/contract_layout.md @@ -35,10 +35,10 @@ | __gap | uint256[49] | 202 | 0 | 1568 | contracts/L2/TaikoL2.sol:TaikoL2 | | l2Hashes | mapping(uint256 => bytes32) | 251 | 0 | 32 | contracts/L2/TaikoL2.sol:TaikoL2 | | publicInputHash | bytes32 | 252 | 0 | 32 | contracts/L2/TaikoL2.sol:TaikoL2 | -| gasExcess | uint64 | 253 | 0 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | +| parentGasExcess | uint64 | 253 | 0 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | | lastSyncedBlock | uint64 | 253 | 8 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | | parentTimestamp | uint64 | 253 | 16 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | -| __deprecated2 | uint64 | 253 | 24 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | +| parentGasTarget | uint64 | 253 | 24 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | | l1ChainId | uint64 | 254 | 0 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | | __gap | uint256[46] | 255 | 0 | 1472 | contracts/L2/TaikoL2.sol:TaikoL2 | From 53770a703925edb39d872ef098b800b166de9ebd Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 1 Aug 2024 15:57:07 +0800 Subject: [PATCH 06/17] Update Lib1559Math.t.sol --- packages/protocol/test/L2/Lib1559Math.t.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index cfa55a0a74d..83e5ae4f7f9 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -32,19 +32,19 @@ contract TestLib1559Math is TaikoTest { uint256 basefee = Lib1559Math.basefee(excess, 2_000_000 * 4) / 10_000_000; console2.log("basefee (uint 0.01gwei) with quotient = 4: ", basefee); - // basefee will decrease if gas issued per second or quotient increased. + /// basefee will decrease if (gas_issued_per_second * quotient) increases. basefee = Lib1559Math.basefee(excess, 2_000_000 * 8) / 10_000_000; console2.log("basefee (uint 0.01gwei) with quotient = 8: ", basefee); basefee = Lib1559Math.basefee(excess, 4_000_000 * 4) / 10_000_000; console2.log("basefee (uint 0.01gwei) with gips = 4_000_000: ", basefee); - // basefee will increase if gas issued per second or quotient decreased. + // basefee will increase if (gas_issued_per_second * quotient) decreases. basefee = Lib1559Math.basefee(excess, 2_000_000 * 2) / 10_000_000; console2.log("basefee (uint 0.01gwei) with quotient = 2: ", basefee); basefee = Lib1559Math.basefee(excess, 1_000_000 * 4) / 10_000_000; console2.log("basefee (uint 0.01gwei) with gips = 1_000_000: ", basefee); - // basefee will be the same if gas issued per second * quotient decreased remains same + /// basefee will remain the same if (gas_issued_per_second * quotient) remains the same. basefee = Lib1559Math.basefee(excess, 4_000_000 * 2) / 10_000_000; console2.log("basefee (uint 0.01gwei) ", basefee); } From 75f6c4f9822555c77f0c79ce1f92984eae916ed8 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 1 Aug 2024 16:03:51 +0800 Subject: [PATCH 07/17] Update TaikoL2.sol --- packages/protocol/contracts/L2/TaikoL2.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index b8cc1015b05..74afe2b22c5 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -65,12 +65,12 @@ contract TaikoL2 is EssentialContract { /// @param _owner The owner of this contract. msg.sender will be used if this value is zero. /// @param _rollupAddressManager The address of the {AddressManager} contract. /// @param _l1ChainId The ID of the base layer. - /// @param _parentGasExcess The initial parentGasExcess. + /// @param _initialGasExcess The initial parentGasExcess. function init( address _owner, address _rollupAddressManager, uint64 _l1ChainId, - uint64 _parentGasExcess + uint64 _initialGasExcess ) external initializer @@ -95,12 +95,12 @@ contract TaikoL2 is EssentialContract { } l1ChainId = _l1ChainId; - parentGasExcess = _parentGasExcess; + parentGasExcess = _initialGasExcess; (publicInputHash,) = _calcPublicInputHash(block.number); } - function init2() external reinitializer(2) { - parentGasExcess = 0; + function init2(uint64 _initialGasExcess) external reinitializer(2) { + parentGasExcess = _initialGasExcess; parentTimestamp = uint64(block.timestamp); parentGasTarget = 0; } From c2c21b8b0185cc0235666ec36135a6becb004ce3 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 1 Aug 2024 16:11:00 +0800 Subject: [PATCH 08/17] more --- packages/protocol/contracts/L2/TaikoL2.sol | 5 +++++ packages/protocol/test/L2/Lib1559Math.t.sol | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index 74afe2b22c5..68c10a446a9 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -99,6 +99,11 @@ contract TaikoL2 is EssentialContract { (publicInputHash,) = _calcPublicInputHash(block.number); } + /// @dev Reinitialize some state variables. + /// We may want to init the basefee to a default value using one of the following values. + /// - _initialGasExcess = 274*5_000_000 => basefee =0.01 gwei + /// - _initialGasExcess = 282*5_000_000 => basefee =0.05 gwei + /// - _initialGasExcess = 288*5_000_000 => basefee =0.1 gwei function init2(uint64 _initialGasExcess) external reinitializer(2) { parentGasExcess = _initialGasExcess; parentTimestamp = uint64(block.timestamp); diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index 83e5ae4f7f9..b845726d9a2 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -17,7 +17,7 @@ contract TestLib1559Math is TaikoTest { uint256 basefee; for (uint256 i; basefee <= 5000;) { // uint 0.01 gwei - basefee = Lib1559Math.basefee(i * 2_000_000, 2_000_000 * 4) / 10_000_000; + basefee = Lib1559Math.basefee(i * 5_000_000, 5_000_000 * 8) / 10_000_000; if (basefee != 0) { console2.log("basefee (uint 0.01gwei) after", i, "seconds:", basefee); } From e3f75f87f8b3bb91afef346943db7dd0738cfca8 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 1 Aug 2024 16:11:28 +0800 Subject: [PATCH 09/17] Update TaikoL2.sol --- packages/protocol/contracts/L2/TaikoL2.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index 68c10a446a9..409208477ef 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -104,7 +104,7 @@ contract TaikoL2 is EssentialContract { /// - _initialGasExcess = 274*5_000_000 => basefee =0.01 gwei /// - _initialGasExcess = 282*5_000_000 => basefee =0.05 gwei /// - _initialGasExcess = 288*5_000_000 => basefee =0.1 gwei - function init2(uint64 _initialGasExcess) external reinitializer(2) { + function init2(uint64 _initialGasExcess) external onlyOwner reinitializer(2) { parentGasExcess = _initialGasExcess; parentTimestamp = uint64(block.timestamp); parentGasTarget = 0; From 8fe29e0f349dc3d4014d13345fdc444510998e56 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 1 Aug 2024 16:21:51 +0800 Subject: [PATCH 10/17] Update taikoL2.ts --- packages/protocol/utils/generate_genesis/taikoL2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/utils/generate_genesis/taikoL2.ts b/packages/protocol/utils/generate_genesis/taikoL2.ts index 9e631d35f6c..30d33fedd4f 100644 --- a/packages/protocol/utils/generate_genesis/taikoL2.ts +++ b/packages/protocol/utils/generate_genesis/taikoL2.ts @@ -515,7 +515,7 @@ async function generateContractConfigs( // TaikoL2 => CrossChainOwned l1ChainId, // TaikoL2 - gasExcess: param1559.gasExcess, + parentGasExcess: param1559.gasExcess, publicInputHash: `${ethers.utils.solidityKeccak256( ["bytes32[256]"], [ From 51bf4df8c36b4d484427a278626a30d5af7b0881 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:42:24 +0800 Subject: [PATCH 11/17] Update packages/protocol/contracts/L2/TaikoL2.sol Co-authored-by: Brecht Devos --- packages/protocol/contracts/L2/TaikoL2.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index 409208477ef..8080297d68b 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -325,7 +325,7 @@ contract TaikoL2 is EssentialContract { publicInputHash = newPublicInputHash; parentGasExcess = newGasExcess; parentTimestamp = uint64(block.timestamp); - parentGasTarget = newGasExcess; + parentGasTarget = newGasTarget; emit Anchored(parentHash, newGasExcess); } From 2fb9aa13d67a87d515cf67bea2768871f7a18a54 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 2 Aug 2024 12:22:43 +0800 Subject: [PATCH 12/17] more --- .../protocol/contracts/L2/Lib1559Math.sol | 21 ++++- packages/protocol/contracts/L2/TaikoL2.sol | 7 +- .../thirdparty/solmate/LibFixedPointMath.sol | 78 +++++++++++++++++++ packages/protocol/test/L2/Lib1559Math.t.sol | 52 ++++++++----- 4 files changed, 134 insertions(+), 24 deletions(-) diff --git a/packages/protocol/contracts/L2/Lib1559Math.sol b/packages/protocol/contracts/L2/Lib1559Math.sol index 6504b759617..d901dd24072 100644 --- a/packages/protocol/contracts/L2/Lib1559Math.sol +++ b/packages/protocol/contracts/L2/Lib1559Math.sol @@ -38,6 +38,25 @@ library Lib1559Math { basefee_ = basefee(gasExcess_, uint256(_adjustmentQuotient) * _gasTarget); } + function adjustExcess( + uint64 _gasExcess, + uint64 _gasTarget, + uint64 _newGasTarget + ) + internal + pure + returns (uint64) + { + int256 ratio = int256(LibFixedPointMath.SCALING_FACTOR * _newGasTarget / _gasTarget); + int256 newGasExcess = ( + LibFixedPointMath.ln(ratio) * int256(uint256(_newGasTarget)) + + ratio * int256(uint256(_gasExcess)) + ) / int256(LibFixedPointMath.SCALING_FACTOR); + + if (newGasExcess < 0) newGasExcess = 0; + return uint64(uint256(newGasExcess).min(type(uint64).max)); + } + /// @dev eth_qty(excess_gas_issued) / (TARGET * ADJUSTMENT_QUOTIENT) /// @param _gasExcess The gas excess value /// @param _target The product of gasTarget and adjustmentQuotient @@ -49,7 +68,7 @@ library Lib1559Math { /// @dev exp(_gasExcess / _target) function ethQty(uint256 _gasExcess, uint256 _target) internal pure returns (uint256) { - uint256 input = _gasExcess * LibFixedPointMath.SCALING_FACTOR / _target; + uint256 input = LibFixedPointMath.SCALING_FACTOR * _gasExcess / _target; if (input > LibFixedPointMath.MAX_EXP_INPUT) { input = LibFixedPointMath.MAX_EXP_INPUT; } diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index 8080297d68b..ebb9562a74f 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -289,9 +289,10 @@ contract TaikoL2 is EssentialContract { // Check if the gas settings has changed uint64 newGasTarget = uint64(_gasIssuancePerSecond) * _basefeeAdjustmentQuotient; if (newGasTarget < parentGasTarget) { - // Reset parentGasExcess to avoid sudden increase of basefee. See - // test_change_of_quotient_and_gips in Lib1559Math.t.sol. - parentGasExcess = 0; + // adjust parentGasExcess to keep the basefee unchanged. Note that due to math + // calculation precision, the basefee may change slightly. + parentGasExcess = + Lib1559Math.adjustExcess(parentGasExcess, parentGasTarget, newGasTarget); } // Verify the base fee per gas is correct diff --git a/packages/protocol/contracts/thirdparty/solmate/LibFixedPointMath.sol b/packages/protocol/contracts/thirdparty/solmate/LibFixedPointMath.sol index 2ad599363c2..df7fd59d005 100644 --- a/packages/protocol/contracts/thirdparty/solmate/LibFixedPointMath.sol +++ b/packages/protocol/contracts/thirdparty/solmate/LibFixedPointMath.sol @@ -79,4 +79,82 @@ library LibFixedPointMath { ); } } + + function ln(int256 x) internal pure returns (int256 r) { + unchecked { + require(x > 0, "UNDEFINED"); + + // We want to convert x from 10**18 fixed point to 2**96 fixed point. + // We do this by multiplying by 2**96 / 10**18. But since + // ln(x * C) = ln(x) + ln(C), we can simply do nothing here + // and add ln(2**96 / 10**18) at the end. + + // Reduce range of x to (1, 2) * 2**96 + // ln(2^k * x) = k * ln(2) + ln(x) + int256 k = int256(log2(uint256(x))) - 96; + x <<= uint256(159 - k); + x = int256(uint256(x) >> 159); + + // Evaluate using a (8, 8)-term rational approximation. + // p is made monic, we will multiply by a scale factor later. + int256 p = x + 3_273_285_459_638_523_848_632_254_066_296; + p = ((p * x) >> 96) + 24_828_157_081_833_163_892_658_089_445_524; + p = ((p * x) >> 96) + 43_456_485_725_739_037_958_740_375_743_393; + p = ((p * x) >> 96) - 11_111_509_109_440_967_052_023_855_526_967; + p = ((p * x) >> 96) - 45_023_709_667_254_063_763_336_534_515_857; + p = ((p * x) >> 96) - 14_706_773_417_378_608_786_704_636_184_526; + p = p * x - (795_164_235_651_350_426_258_249_787_498 << 96); + + // We leave p in 2**192 basis so we don't need to scale it back up for the division. + // q is monic by convention. + int256 q = x + 5_573_035_233_440_673_466_300_451_813_936; + q = ((q * x) >> 96) + 71_694_874_799_317_883_764_090_561_454_958; + q = ((q * x) >> 96) + 283_447_036_172_924_575_727_196_451_306_956; + q = ((q * x) >> 96) + 401_686_690_394_027_663_651_624_208_769_553; + q = ((q * x) >> 96) + 204_048_457_590_392_012_362_485_061_816_622; + q = ((q * x) >> 96) + 31_853_899_698_501_571_402_653_359_427_138; + q = ((q * x) >> 96) + 909_429_971_244_387_300_277_376_558_375; + assembly { + // Div in assembly because solidity adds a zero check despite the unchecked. + // The q polynomial is known not to have zeros in the domain. + // No scaling required because p is already 2**96 too large. + r := sdiv(p, q) + } + + // r is in the range (0, 0.125) * 2**96 + + // Finalization, we need to: + // * multiply by the scale factor s = 5.549… + // * add ln(2**96 / 10**18) + // * add k * ln(2) + // * multiply by 10**18 / 2**96 = 5**18 >> 78 + + // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 + r *= 1_677_202_110_996_718_588_342_820_967_067_443_963_516_166; + // add ln(2) * k * 5e18 * 2**192 + r += + 16_597_577_552_685_614_221_487_285_958_193_947_469_193_820_559_219_878_177_908_093_499_208_371 + * k; + // add ln(2**96 / 10**18) * 5e18 * 2**192 + r += + 600_920_179_829_731_861_736_702_779_321_621_459_595_472_258_049_074_101_567_377_883_020_018_308; + // base conversion: mul 2**18 / 2**192 + r >>= 174; + } + } + + function log2(uint256 x) internal pure returns (uint256 r) { + require(x > 0, "UNDEFINED"); + + assembly { + r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) + r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(r, shl(3, lt(0xff, shr(r, x)))) + r := or(r, shl(2, lt(0xf, shr(r, x)))) + r := or(r, shl(1, lt(0x3, shr(r, x)))) + r := or(r, lt(0x1, shr(r, x))) + } + } } diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index b845726d9a2..89db181b7ab 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -25,27 +25,39 @@ contract TestLib1559Math is TaikoTest { } } - function test_change_of_quotient_and_gips() public pure { - uint256 excess = 150 * 2_000_000; + function test_change_of_quotient_and_gips() public { + uint64 excess = 150 * 2_000_000; + uint64 target = 4 * 2_000_000; + uint256 unit = 10_000_000; // 0.01 gwei // uint 0.01 gwei - uint256 basefee = Lib1559Math.basefee(excess, 2_000_000 * 4) / 10_000_000; - console2.log("basefee (uint 0.01gwei) with quotient = 4: ", basefee); - - /// basefee will decrease if (gas_issued_per_second * quotient) increases. - basefee = Lib1559Math.basefee(excess, 2_000_000 * 8) / 10_000_000; - console2.log("basefee (uint 0.01gwei) with quotient = 8: ", basefee); - basefee = Lib1559Math.basefee(excess, 4_000_000 * 4) / 10_000_000; - console2.log("basefee (uint 0.01gwei) with gips = 4_000_000: ", basefee); - - // basefee will increase if (gas_issued_per_second * quotient) decreases. - basefee = Lib1559Math.basefee(excess, 2_000_000 * 2) / 10_000_000; - console2.log("basefee (uint 0.01gwei) with quotient = 2: ", basefee); - basefee = Lib1559Math.basefee(excess, 1_000_000 * 4) / 10_000_000; - console2.log("basefee (uint 0.01gwei) with gips = 1_000_000: ", basefee); - - /// basefee will remain the same if (gas_issued_per_second * quotient) remains the same. - basefee = Lib1559Math.basefee(excess, 4_000_000 * 2) / 10_000_000; - console2.log("basefee (uint 0.01gwei) ", basefee); + uint256 baselineBasefee = Lib1559Math.basefee(excess, target) / unit; + console2.log("baseline basefee: ", baselineBasefee); + + uint256 basefee = Lib1559Math.basefee(excess, target * 2) / unit; + console2.log("basefee will decrease if target increases:", basefee); + + basefee = Lib1559Math.basefee(excess, target / 2) / unit; + console2.log("basefee will increase if target decreases:", basefee); + + console2.log("maintain basefee when target increases"); + { + uint64 newTarget = 5 * 2_000_000; + uint64 newExcess = Lib1559Math.adjustExcess(excess, target, newTarget); + basefee = Lib1559Math.basefee(newExcess, newTarget) / unit; + console2.log("new gas excess: ", newExcess); + console2.log("basefee: ", basefee); + assertEq(baselineBasefee, basefee); + } + + console2.log("maintain basefee when target decreases"); + { + uint64 newTarget = 3 * 2_000_000; + uint64 newExcess = Lib1559Math.adjustExcess(excess, target, newTarget); + basefee = Lib1559Math.basefee(newExcess, newTarget) / unit; + console2.log("new gas excess: ", newExcess); + console2.log("basefee: ", basefee); + assertEq(baselineBasefee, basefee); + } } } From 7b56994c04a67d7d3d05522715573a9a564b2fc2 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 2 Aug 2024 12:40:36 +0800 Subject: [PATCH 13/17] Update Lib1559Math.sol --- .../protocol/contracts/L2/Lib1559Math.sol | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/protocol/contracts/L2/Lib1559Math.sol b/packages/protocol/contracts/L2/Lib1559Math.sol index d901dd24072..d646e555ca1 100644 --- a/packages/protocol/contracts/L2/Lib1559Math.sol +++ b/packages/protocol/contracts/L2/Lib1559Math.sol @@ -38,6 +38,8 @@ library Lib1559Math { basefee_ = basefee(gasExcess_, uint256(_adjustmentQuotient) * _gasTarget); } + /// @dev Returns the new gas excess that will keep the basefee the same. + /// `_newGasTarget * ln(_newGasTarget / _target) + _gasExcess * _newGasTarget / _target` function adjustExcess( uint64 _gasExcess, uint64 _gasTarget, @@ -47,14 +49,27 @@ library Lib1559Math { pure returns (uint64) { - int256 ratio = int256(LibFixedPointMath.SCALING_FACTOR * _newGasTarget / _gasTarget); - int256 newGasExcess = ( - LibFixedPointMath.ln(ratio) * int256(uint256(_newGasTarget)) - + ratio * int256(uint256(_gasExcess)) - ) / int256(LibFixedPointMath.SCALING_FACTOR); + if (_gasTarget == 0) revert EIP1559_INVALID_PARAMS(); - if (newGasExcess < 0) newGasExcess = 0; - return uint64(uint256(newGasExcess).min(type(uint64).max)); + uint256 f = LibFixedPointMath.SCALING_FACTOR; + uint256 ratio; + unchecked { + ratio = f * _newGasTarget / _gasTarget; + } + + if (ratio > type(int256).max) revert EIP1559_INVALID_PARAMS(); + + int256 lnRatio = LibFixedPointMath.ln(int256(ratio)); + + uint256 newGasExcess; + assembly { + newGasExcess := sdiv(add(mul(lnRatio, _newGasTarget), mul(ratio, _gasExcess)), f) + switch gt(newGasExcess, 0) + case 1 { newGasExcess := shr(192, shl(192, newGasExcess)) } + default { newGasExcess := 0 } + } + + return uint64(newGasExcess); } /// @dev eth_qty(excess_gas_issued) / (TARGET * ADJUSTMENT_QUOTIENT) From 679f8a316be4ec8591558f5acbe0e4cd6dcf388f Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 2 Aug 2024 12:45:31 +0800 Subject: [PATCH 14/17] Update TaikoL2.sol --- packages/protocol/contracts/L2/TaikoL2.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index ebb9562a74f..009c7824dd1 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -288,7 +288,7 @@ contract TaikoL2 is EssentialContract { // Check if the gas settings has changed uint64 newGasTarget = uint64(_gasIssuancePerSecond) * _basefeeAdjustmentQuotient; - if (newGasTarget < parentGasTarget) { + if (newGasTarget != parentGasTarget) { // adjust parentGasExcess to keep the basefee unchanged. Note that due to math // calculation precision, the basefee may change slightly. parentGasExcess = From 55dbace871209bfdb2a5f6a1bf8d786bc1d59f53 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 2 Aug 2024 14:37:17 +0800 Subject: [PATCH 15/17] Update Lib1559Math.sol --- packages/protocol/contracts/L2/Lib1559Math.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/contracts/L2/Lib1559Math.sol b/packages/protocol/contracts/L2/Lib1559Math.sol index d646e555ca1..51165a2df72 100644 --- a/packages/protocol/contracts/L2/Lib1559Math.sol +++ b/packages/protocol/contracts/L2/Lib1559Math.sol @@ -57,7 +57,7 @@ library Lib1559Math { ratio = f * _newGasTarget / _gasTarget; } - if (ratio > type(int256).max) revert EIP1559_INVALID_PARAMS(); + if (ratio > uint256(type(int256).max)) revert EIP1559_INVALID_PARAMS(); int256 lnRatio = LibFixedPointMath.ln(int256(ratio)); From baf39b10ab95440a9dfad1cac98a6b6fe66db146 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 2 Aug 2024 14:41:06 +0800 Subject: [PATCH 16/17] Update TaikoL2.sol --- packages/protocol/contracts/L2/TaikoL2.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index 009c7824dd1..e20782887e3 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -287,8 +287,9 @@ contract TaikoL2 is EssentialContract { if (publicInputHash != currentPublicInputHash) revert L2_PUBLIC_INPUT_HASH_MISMATCH(); // Check if the gas settings has changed + bool postFork = block.number >= ontakeForkHeight(); uint64 newGasTarget = uint64(_gasIssuancePerSecond) * _basefeeAdjustmentQuotient; - if (newGasTarget != parentGasTarget) { + if (postFork && newGasTarget != parentGasTarget) { // adjust parentGasExcess to keep the basefee unchanged. Note that due to math // calculation precision, the basefee may change slightly. parentGasExcess = @@ -296,15 +297,15 @@ contract TaikoL2 is EssentialContract { } // Verify the base fee per gas is correct - (uint256 basefee, uint64 newGasExcess) = block.number < ontakeForkHeight() - ? getBasefee(_anchorBlockId, _parentGasUsed) - : calculateBaseFee( + (uint256 basefee, uint64 newGasExcess) = postFork + ? calculateBaseFee( _gasIssuancePerSecond, uint64(block.timestamp - parentTimestamp), _basefeeAdjustmentQuotient, parentGasExcess, _parentGasUsed - ); + ) + : getBasefee(_anchorBlockId, _parentGasUsed); if (!skipFeeCheck() && block.basefee != basefee) revert L2_BASEFEE_MISMATCH(); @@ -319,7 +320,6 @@ contract TaikoL2 is EssentialContract { } // Update state variables - bytes32 parentHash = blockhash(parentId); l2Hashes[parentId] = parentHash; From 585e5fee9b83ed64039783dbca0e8453ea807996 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Mon, 5 Aug 2024 12:27:46 +0800 Subject: [PATCH 17/17] improve --- .../protocol/contracts/L2/Lib1559Math.sol | 35 +++++++------------ packages/protocol/contracts/L2/TaikoL2.sol | 6 ++-- packages/protocol/test/L2/Lib1559Math.t.sol | 2 ++ 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/packages/protocol/contracts/L2/Lib1559Math.sol b/packages/protocol/contracts/L2/Lib1559Math.sol index 51165a2df72..aac64054f24 100644 --- a/packages/protocol/contracts/L2/Lib1559Math.sol +++ b/packages/protocol/contracts/L2/Lib1559Math.sol @@ -15,8 +15,7 @@ library Lib1559Math { error EIP1559_INVALID_PARAMS(); function calc1559BaseFee( - uint32 _gasTarget, - uint8 _adjustmentQuotient, + uint256 _gasTarget, uint64 _gasExcess, uint64 _gasIssuance, uint32 _parentGasUsed @@ -35,7 +34,7 @@ library Lib1559Math { // bonding curve, regardless the actual amount of gas used by this // block, however, this block's gas used will affect the next // block's base fee. - basefee_ = basefee(gasExcess_, uint256(_adjustmentQuotient) * _gasTarget); + basefee_ = basefee(gasExcess_, _gasTarget); } /// @dev Returns the new gas excess that will keep the basefee the same. @@ -52,38 +51,30 @@ library Lib1559Math { if (_gasTarget == 0) revert EIP1559_INVALID_PARAMS(); uint256 f = LibFixedPointMath.SCALING_FACTOR; - uint256 ratio; - unchecked { - ratio = f * _newGasTarget / _gasTarget; - } - + uint256 ratio = f * _newGasTarget / _gasTarget; if (ratio > uint256(type(int256).max)) revert EIP1559_INVALID_PARAMS(); - int256 lnRatio = LibFixedPointMath.ln(int256(ratio)); + int256 lnRatio = LibFixedPointMath.ln(int256(ratio)); // may be negative uint256 newGasExcess; assembly { newGasExcess := sdiv(add(mul(lnRatio, _newGasTarget), mul(ratio, _gasExcess)), f) - switch gt(newGasExcess, 0) - case 1 { newGasExcess := shr(192, shl(192, newGasExcess)) } - default { newGasExcess := 0 } } - return uint64(newGasExcess); + return uint64(newGasExcess.min(type(uint64).max)); } - /// @dev eth_qty(excess_gas_issued) / (TARGET * ADJUSTMENT_QUOTIENT) - /// @param _gasExcess The gas excess value - /// @param _target The product of gasTarget and adjustmentQuotient - function basefee(uint256 _gasExcess, uint256 _target) internal pure returns (uint256) { - if (_target == 0) revert EIP1559_INVALID_PARAMS(); - uint256 fee = ethQty(_gasExcess, _target) / _target; + /// @dev exp(_gasExcess / _gasTarget) / _gasTarget + function basefee(uint256 _gasExcess, uint256 _gasTarget) internal pure returns (uint256) { + uint256 fee = ethQty(_gasExcess, _gasTarget) / _gasTarget; return fee == 0 ? 1 : fee; } - /// @dev exp(_gasExcess / _target) - function ethQty(uint256 _gasExcess, uint256 _target) internal pure returns (uint256) { - uint256 input = LibFixedPointMath.SCALING_FACTOR * _gasExcess / _target; + /// @dev exp(_gasExcess / _gasTarget) + function ethQty(uint256 _gasExcess, uint256 _gasTarget) internal pure returns (uint256) { + if (_gasTarget == 0) revert EIP1559_INVALID_PARAMS(); + + uint256 input = LibFixedPointMath.SCALING_FACTOR * _gasExcess / _gasTarget; if (input > LibFixedPointMath.MAX_EXP_INPUT) { input = LibFixedPointMath.MAX_EXP_INPUT; } diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index e20782887e3..68b73e48733 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -199,8 +199,7 @@ contract TaikoL2 is EssentialContract { LibL2Config.Config memory config = getConfig(); (basefee_, parentGasExcess_) = Lib1559Math.calc1559BaseFee( - config.gasTargetPerL1Block, - config.basefeeAdjustmentQuotient, + uint256(config.gasTargetPerL1Block) * config.basefeeAdjustmentQuotient, parentGasExcess, uint64(_anchorBlockId - lastSyncedBlock) * config.gasTargetPerL1Block, _parentGasUsed @@ -254,8 +253,7 @@ contract TaikoL2 is EssentialContract { returns (uint256 basefee_, uint64 parentGasExcess_) { return Lib1559Math.calc1559BaseFee( - _gasIssuancePerSecond, - _adjustmentQuotient, + uint256(_gasIssuancePerSecond) * _adjustmentQuotient, _parentGasExcess, _blocktime * _gasIssuancePerSecond, _parentGasUsed diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index 89db181b7ab..e05e9ddf104 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -45,6 +45,7 @@ contract TestLib1559Math is TaikoTest { uint64 newTarget = 5 * 2_000_000; uint64 newExcess = Lib1559Math.adjustExcess(excess, target, newTarget); basefee = Lib1559Math.basefee(newExcess, newTarget) / unit; + console2.log("old gas excess: ", excess); console2.log("new gas excess: ", newExcess); console2.log("basefee: ", basefee); assertEq(baselineBasefee, basefee); @@ -55,6 +56,7 @@ contract TestLib1559Math is TaikoTest { uint64 newTarget = 3 * 2_000_000; uint64 newExcess = Lib1559Math.adjustExcess(excess, target, newTarget); basefee = Lib1559Math.basefee(newExcess, newTarget) / unit; + console2.log("old gas excess: ", excess); console2.log("new gas excess: ", newExcess); console2.log("basefee: ", basefee); assertEq(baselineBasefee, basefee);