From 006f2cd3aac19d4b0a43146fa6c567e45b81ba1f Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 29 Mar 2024 02:14:37 +0800 Subject: [PATCH 1/4] apply a min value for gas excess --- .../protocol/contracts/L2/Lib1559Math.sol | 3 +- .../protocol/contracts/L2/LibL2Config.sol | 22 ++++++++++ packages/protocol/contracts/L2/TaikoL2.sol | 17 +++----- .../L2/TaikoL2EIP1559Configurable.sol | 8 ++-- packages/protocol/test/L2/Lib1559Math.t.sol | 36 +++++++++++----- packages/protocol/test/L2/TaikoL2.t.sol | 43 ++----------------- .../protocol/test/L2/TaikoL2NoFeeCheck.t.sol | 4 +- 7 files changed, 65 insertions(+), 68 deletions(-) create mode 100644 packages/protocol/contracts/L2/LibL2Config.sol diff --git a/packages/protocol/contracts/L2/Lib1559Math.sol b/packages/protocol/contracts/L2/Lib1559Math.sol index 90a8208b61..8904ad8512 100644 --- a/packages/protocol/contracts/L2/Lib1559Math.sol +++ b/packages/protocol/contracts/L2/Lib1559Math.sol @@ -17,6 +17,7 @@ library Lib1559Math { function calc1559BaseFee( uint32 _gasTargetPerL1Block, uint8 _adjustmentQuotient, + uint64 _gasExcessMinValue, uint64 _gasExcess, uint64 _gasIssuance, uint32 _parentGasUsed @@ -29,7 +30,7 @@ library Lib1559Math { // value as this has already happened uint256 excess = uint256(_gasExcess) + _parentGasUsed; excess = excess > _gasIssuance ? excess - _gasIssuance : 1; - gasExcess_ = uint64(excess.min(type(uint64).max)); + gasExcess_ = uint64(excess.min(type(uint64).max).max(_gasExcessMinValue)); // The base fee per gas used by this block is the spot price at the // bonding curve, regardless the actual amount of gas used by this diff --git a/packages/protocol/contracts/L2/LibL2Config.sol b/packages/protocol/contracts/L2/LibL2Config.sol new file mode 100644 index 0000000000..990124f59d --- /dev/null +++ b/packages/protocol/contracts/L2/LibL2Config.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +/// @title LibL2Config +library LibL2Config { + struct Config { + uint32 gasTargetPerL1Block; + uint8 basefeeAdjustmentQuotient; + uint64 gasExcessMinValue; + } + + /// @notice Returns EIP1559 related configurations. + /// @return config_ struct containing configuration parameters. + function get() internal pure returns (Config memory config_) { + // Assuming we sell 3x more blockspace than Ethereum: 15_000_000 * 4 + // Note that Brecht's concern is that this value may be too large. + // We need to monitor L2 state growth and lower this value when necessary. + config_.gasTargetPerL1Block = 60_000_000; + config_.basefeeAdjustmentQuotient = 8; + config_.gasExcessMinValue = 18_000_000_000; + } +} diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index eb0c7e09f4..94b137d8ac 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -9,6 +9,7 @@ import "../libs/LibAddress.sol"; import "../signal/ISignalService.sol"; import "../signal/LibSignals.sol"; import "./Lib1559Math.sol"; +import "./LibL2Config.sol"; /// @title TaikoL2 /// @notice Taiko L2 is a smart contract that handles cross-layer message @@ -21,11 +22,6 @@ contract TaikoL2 is EssentialContract { using LibAddress for address; using SafeERC20 for IERC20; - struct Config { - uint32 gasTargetPerL1Block; - uint8 basefeeAdjustmentQuotient; - } - /// @notice Golden touch address is the only address that can do the anchor transaction. address public constant GOLDEN_TOUCH_ADDRESS = 0x0000777735367b36bC9B61C50022d9D0700dB4Ec; @@ -208,12 +204,13 @@ contract TaikoL2 is EssentialContract { view returns (uint256 basefee_, uint64 gasExcess_) { - Config memory config = getConfig(); + LibL2Config.Config memory config = getConfig(); uint64 gasIssuance = uint64(_l1BlockId - lastSyncedBlock) * config.gasTargetPerL1Block; (basefee_, gasExcess_) = Lib1559Math.calc1559BaseFee( config.gasTargetPerL1Block, config.basefeeAdjustmentQuotient, + config.gasExcessMinValue, gasExcess, gasIssuance, _parentGasUsed @@ -232,12 +229,8 @@ contract TaikoL2 is EssentialContract { /// @notice Returns EIP1559 related configurations. /// @return config_ struct containing configuration parameters. - function getConfig() public view virtual returns (Config memory config_) { - // Assuming we sell 3x more blockspace than Ethereum: 15_000_000 * 4 - // Note that Brecht's concern is that this value may be too large. - // We need to monitor L2 state growth and lower this value when necessary. - config_.gasTargetPerL1Block = 60_000_000; - config_.basefeeAdjustmentQuotient = 8; + function getConfig() public view virtual returns (LibL2Config.Config memory) { + return LibL2Config.get(); } /// @notice Tells if we need to validate basefee (for simulation). diff --git a/packages/protocol/contracts/L2/TaikoL2EIP1559Configurable.sol b/packages/protocol/contracts/L2/TaikoL2EIP1559Configurable.sol index 1ae90719fd..3159fc507e 100644 --- a/packages/protocol/contracts/L2/TaikoL2EIP1559Configurable.sol +++ b/packages/protocol/contracts/L2/TaikoL2EIP1559Configurable.sol @@ -8,14 +8,14 @@ import "./TaikoL2.sol"; /// @custom:security-contact security@taiko.xyz contract TaikoL2EIP1559Configurable is TaikoL2 { /// @notice EIP-1559 configuration. - Config public customConfig; + LibL2Config.Config public customConfig; uint256[49] private __gap; /// @notice Emits when the EIP-1559 configuration and gas excess are changed. /// @param config The new EIP-1559 config. /// @param gasExcess The new gas excess. - event ConfigAndExcessChanged(Config config, uint64 gasExcess); + event ConfigAndExcessChanged(LibL2Config.Config config, uint64 gasExcess); error L2_INVALID_CONFIG(); @@ -23,7 +23,7 @@ contract TaikoL2EIP1559Configurable is TaikoL2 { /// @param _newConfig The new EIP1559 config. /// @param _newGasExcess The new gas excess function setConfigAndExcess( - Config memory _newConfig, + LibL2Config.Config memory _newConfig, uint64 _newGasExcess ) external @@ -40,7 +40,7 @@ contract TaikoL2EIP1559Configurable is TaikoL2 { } /// @inheritdoc TaikoL2 - function getConfig() public view override returns (Config memory) { + function getConfig() public view override returns (LibL2Config.Config memory) { return customConfig; } } diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index eda7a953a3..8697e72b51 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -7,28 +7,42 @@ contract TestLib1559Math is TaikoTest { using LibMath for uint256; function test_eip1559_math() external { - uint256 gasTarget = 60_000_000; - uint256 adjustmentQuotient = 8; - uint256 adjustmentFactor = gasTarget * adjustmentQuotient; + LibL2Config.Config memory config = LibL2Config.get(); + uint256 adjustmentFactor = config.gasTargetPerL1Block * config.basefeeAdjustmentQuotient; uint256 baseFee; uint256 i; + + baseFee = Lib1559Math.basefee(config.gasExcessMinValue, adjustmentFactor); + assertEq(baseFee, 40_253_331); // about 0.04gwei + console2.log("gasExcessMinValue:", config.gasExcessMinValue); + console2.log("min base fee:", baseFee); + + for (; baseFee < 1 gwei / 10; ++i) { + baseFee = Lib1559Math.basefee(config.gasTargetPerL1Block * i, adjustmentFactor); + console2.log("base fee:", i, baseFee); + } + + // base fee will reach 1 gwei if gasExcess > 18540000000 + console2.log("base fee will reach 0.1 gwei if gasExcess >", config.gasTargetPerL1Block * i); + assertEq(i, 309); + for (; baseFee < 1 gwei; ++i) { - baseFee = Lib1559Math.basefee(gasTarget * i, adjustmentFactor); - console2.log("baseFee:", i, baseFee); + baseFee = Lib1559Math.basefee(config.gasTargetPerL1Block * i, adjustmentFactor); + console2.log("base fee:", i, baseFee); } - // basefee will reach 1 gwei if gasExcess > 19620000000 - console2.log("basefee will reach 1 gwei if gasExcess >", gasTarget * i); + // base fee will reach 1 gwei if gasExcess > 19620000000 + console2.log("base fee will reach 1 gwei if gasExcess >", config.gasTargetPerL1Block * i); assertEq(i, 327); for (; baseFee < 10 gwei; ++i) { - baseFee = Lib1559Math.basefee(gasTarget * i, adjustmentFactor); - console2.log("baseFee:", i, baseFee); + baseFee = Lib1559Math.basefee(config.gasTargetPerL1Block * i, adjustmentFactor); + console2.log("base fee:", i, baseFee); } - // basefee will reach 10 gwei if gasExcess > 20760000000 - console2.log("basefee will reach 10 gwei if gasExcess >", gasTarget * i); + // base fee will reach 10 gwei if gasExcess > 20760000000 + console2.log("base fee will reach 10 gwei if gasExcess >", config.gasTargetPerL1Block * i); assertEq(i, 346); } } diff --git a/packages/protocol/test/L2/TaikoL2.t.sol b/packages/protocol/test/L2/TaikoL2.t.sol index fe946766ae..7a3971ec92 100644 --- a/packages/protocol/test/L2/TaikoL2.t.sol +++ b/packages/protocol/test/L2/TaikoL2.t.sol @@ -55,7 +55,9 @@ contract TestTaikoL2 is TaikoTest { ) ); - L2.setConfigAndExcess(TaikoL2.Config(gasTarget, quotient), gasExcess); + L2.setConfigAndExcess( + LibL2Config.Config(gasTarget, quotient, uint64(gasTarget) * 300), gasExcess + ); ss.authorize(address(L2), true); @@ -67,46 +69,9 @@ contract TestTaikoL2 is TaikoTest { vm.deal(address(L2), 100 ether); } - function test_L2_AnchorTx_with_constant_block_time() external { - for (uint256 i; i < 100; ++i) { - vm.fee(1); - - vm.prank(L2.GOLDEN_TOUCH_ADDRESS()); - _anchor(BLOCK_GAS_LIMIT); - - vm.roll(block.number + 1); - vm.warp(block.timestamp + 30); - } - } - - function test_L2_AnchorTx_with_decreasing_block_time() external { - for (uint256 i; i < 32; ++i) { - vm.fee(1); - - vm.prank(L2.GOLDEN_TOUCH_ADDRESS()); - _anchor(BLOCK_GAS_LIMIT); - - vm.roll(block.number + 1); - vm.warp(block.timestamp + 30 - i); - } - } - - function test_L2_AnchorTx_with_increasing_block_time() external { - for (uint256 i; i < 30; ++i) { - vm.fee(1); - - vm.prank(L2.GOLDEN_TOUCH_ADDRESS()); - _anchor(BLOCK_GAS_LIMIT); - - vm.roll(block.number + 1); - - vm.warp(block.timestamp + 30 + i); - } - } - // calling anchor in the same block more than once should fail function test_L2_AnchorTx_revert_in_same_block() external { - vm.fee(1); + vm.fee(40_253_331); vm.prank(L2.GOLDEN_TOUCH_ADDRESS()); _anchor(BLOCK_GAS_LIMIT); diff --git a/packages/protocol/test/L2/TaikoL2NoFeeCheck.t.sol b/packages/protocol/test/L2/TaikoL2NoFeeCheck.t.sol index 0caba175d2..9bdd5c3b74 100644 --- a/packages/protocol/test/L2/TaikoL2NoFeeCheck.t.sol +++ b/packages/protocol/test/L2/TaikoL2NoFeeCheck.t.sol @@ -55,7 +55,9 @@ contract TestTaikoL2NoFeeCheck is TaikoTest { ) ); - L2.setConfigAndExcess(TaikoL2.Config(gasTarget, quotient), gasExcess); + L2.setConfigAndExcess( + LibL2Config.Config(gasTarget, quotient, uint64(gasTarget) * 300), gasExcess + ); ss.authorize(address(L2), true); From d54ed07c5a3598bf1ae5a09fdcf92d3c1bd0296f Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 29 Mar 2024 02:24:57 +0800 Subject: [PATCH 2/4] fix --- packages/protocol/contracts/L2/LibL2Config.sol | 4 +++- packages/protocol/test/L2/Lib1559Math.t.sol | 11 +---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/protocol/contracts/L2/LibL2Config.sol b/packages/protocol/contracts/L2/LibL2Config.sol index 990124f59d..9c1e316d88 100644 --- a/packages/protocol/contracts/L2/LibL2Config.sol +++ b/packages/protocol/contracts/L2/LibL2Config.sol @@ -17,6 +17,8 @@ library LibL2Config { // We need to monitor L2 state growth and lower this value when necessary. config_.gasTargetPerL1Block = 60_000_000; config_.basefeeAdjustmentQuotient = 8; - config_.gasExcessMinValue = 18_000_000_000; + + // We pick this value to make the min base fee 0.1gwei + config_.gasExcessMinValue = 18_440_000_000; } } diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index 8697e72b51..d474ac438c 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -14,19 +14,10 @@ contract TestLib1559Math is TaikoTest { uint256 i; baseFee = Lib1559Math.basefee(config.gasExcessMinValue, adjustmentFactor); - assertEq(baseFee, 40_253_331); // about 0.04gwei + assertEq(baseFee, 100_671_168); // about 0.1gwei console2.log("gasExcessMinValue:", config.gasExcessMinValue); console2.log("min base fee:", baseFee); - for (; baseFee < 1 gwei / 10; ++i) { - baseFee = Lib1559Math.basefee(config.gasTargetPerL1Block * i, adjustmentFactor); - console2.log("base fee:", i, baseFee); - } - - // base fee will reach 1 gwei if gasExcess > 18540000000 - console2.log("base fee will reach 0.1 gwei if gasExcess >", config.gasTargetPerL1Block * i); - assertEq(i, 309); - for (; baseFee < 1 gwei; ++i) { baseFee = Lib1559Math.basefee(config.gasTargetPerL1Block * i, adjustmentFactor); console2.log("base fee:", i, baseFee); From 8d66d6e3fa9b29b80b97d67c4ed17fc55ae8770c Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 29 Mar 2024 02:38:30 +0800 Subject: [PATCH 3/4] rename --- .../{contracts => test}/L2/TaikoL2EIP1559Configurable.sol | 2 +- packages/protocol/test/TaikoTest.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename packages/protocol/{contracts => test}/L2/TaikoL2EIP1559Configurable.sol (97%) diff --git a/packages/protocol/contracts/L2/TaikoL2EIP1559Configurable.sol b/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol similarity index 97% rename from packages/protocol/contracts/L2/TaikoL2EIP1559Configurable.sol rename to packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol index 3159fc507e..69661686af 100644 --- a/packages/protocol/contracts/L2/TaikoL2EIP1559Configurable.sol +++ b/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; -import "./TaikoL2.sol"; +import "../../contracts/L2/TaikoL2.sol"; /// @title TaikoL2EIP1559Configurable /// @notice TaikoL2 with a setter to change EIP-1559 configurations and states. diff --git a/packages/protocol/test/TaikoTest.sol b/packages/protocol/test/TaikoTest.sol index 3e98afd532..e30ada7853 100644 --- a/packages/protocol/test/TaikoTest.sol +++ b/packages/protocol/test/TaikoTest.sol @@ -31,7 +31,6 @@ import "../contracts/L1/hooks/AssignmentHook.sol"; import "../contracts/L1/provers/GuardianProver.sol"; import "../contracts/L2/Lib1559Math.sol"; -import "../contracts/L2/TaikoL2EIP1559Configurable.sol"; import "../contracts/L2/TaikoL2.sol"; import "../contracts/L2/DelegateOwner.sol"; @@ -41,6 +40,7 @@ import "../contracts/team/airdrop/ERC20Airdrop2.sol"; import "../contracts/team/airdrop/ERC721Airdrop.sol"; import "../test/common/erc20/FreeMintERC20.sol"; +import "../test/L2/TaikoL2EIP1559Configurable.sol"; import "./DeployCapability.sol"; import "./HelperContracts.sol"; From af98c663141b07ec891f682460ea3ef419a5e71b Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 29 Mar 2024 02:48:40 +0800 Subject: [PATCH 4/4] tune --- packages/protocol/contracts/L2/LibL2Config.sol | 4 ++-- packages/protocol/test/L2/Lib1559Math.t.sol | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/protocol/contracts/L2/LibL2Config.sol b/packages/protocol/contracts/L2/LibL2Config.sol index 9c1e316d88..754dfeed32 100644 --- a/packages/protocol/contracts/L2/LibL2Config.sol +++ b/packages/protocol/contracts/L2/LibL2Config.sol @@ -18,7 +18,7 @@ library LibL2Config { config_.gasTargetPerL1Block = 60_000_000; config_.basefeeAdjustmentQuotient = 8; - // We pick this value to make the min base fee 0.1gwei - config_.gasExcessMinValue = 18_440_000_000; + // This value is picked to make the min base fee close to but slightly smaller than 0.1gwei + config_.gasExcessMinValue = 18_435_000_000; } } diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index d474ac438c..3dd5743258 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -14,7 +14,7 @@ contract TestLib1559Math is TaikoTest { uint256 i; baseFee = Lib1559Math.basefee(config.gasExcessMinValue, adjustmentFactor); - assertEq(baseFee, 100_671_168); // about 0.1gwei + assertEq(baseFee, 99_627_953); // slightly smaller than 0.1gwei console2.log("gasExcessMinValue:", config.gasExcessMinValue); console2.log("min base fee:", baseFee);