Skip to content

Commit

Permalink
feat(protocol): Gas limit behavior changes (#14339)
Browse files Browse the repository at this point in the history
Co-authored-by: David <david@taiko.xyz>
Co-authored-by: Daniel Wang <99078276+dantaik@users.noreply.github.com>
  • Loading branch information
3 people authored Aug 7, 2023
1 parent a82fecb commit 06710eb
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 72 deletions.
3 changes: 1 addition & 2 deletions packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,10 @@ library TaikoData {
uint64 numEthDeposits;
}

// 3 slots
// 2 slots
struct BlockMetadataInput {
bytes32 txListHash;
address beneficiary;
uint32 gasLimit;
uint24 txListByteStart; // byte-wise start index (inclusive)
uint24 txListByteEnd; // byte-wise end index (exclusive)
bool cacheTxListInfo;
Expand Down
10 changes: 2 additions & 8 deletions packages/protocol/contracts/L1/libs/LibProposing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ library LibProposing {
meta.txListHash = input.txListHash;
meta.txListByteStart = input.txListByteStart;
meta.txListByteEnd = input.txListByteEnd;
meta.gasLimit = input.gasLimit;
meta.gasLimit = config.blockMaxGasLimit;
meta.beneficiary = input.beneficiary;
meta.treasury = resolver.resolve(config.chainId, "treasury", false);
meta.depositsProcessed =
Expand Down Expand Up @@ -183,13 +183,7 @@ library LibProposing {
view
returns (bool cacheTxListInfo)
{
if (
input.beneficiary == address(0)
//
|| input.gasLimit == 0
//
|| input.gasLimit > config.blockMaxGasLimit
) revert L1_INVALID_METADATA();
if (input.beneficiary == address(0)) revert L1_INVALID_METADATA();

if (
state.numBlocks
Expand Down
44 changes: 22 additions & 22 deletions packages/protocol/contracts/L2/TaikoL2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,11 @@ contract TaikoL2 is EssentialContract, TaikoL2Signer, ICrossChainSync {
uint256 basefee;
EIP1559Config memory config = getEIP1559Config();
if (config.gasIssuedPerSecond != 0) {
(basefee, gasExcess) = _calcBasefee(
config,
block.timestamp - parentTimestamp,
uint32(block.gaslimit),
parentGasUsed
);
(basefee, gasExcess) = _calcBasefee({
config: config,
timeSinceParent: block.timestamp - parentTimestamp,
parentGasUsed: parentGasUsed
});
}

// On L2, basefee is not burnt, but sent to a treasury instead.
Expand Down Expand Up @@ -233,17 +232,18 @@ contract TaikoL2 is EssentialContract, TaikoL2Signer, ICrossChainSync {
}

function getBasefee(
uint32 timeSinceParent,
uint32 gasLimit,
uint64 timeSinceParent,
uint32 parentGasUsed
)
public
view
returns (uint256 _basefee)
{
(_basefee,) = _calcBasefee(
getEIP1559Config(), timeSinceParent, gasLimit, parentGasUsed
);
(_basefee,) = _calcBasefee({
config: getEIP1559Config(),
timeSinceParent: timeSinceParent,
parentGasUsed: parentGasUsed
});
}

function getCrossChainBlockHash(uint256 number)
Expand Down Expand Up @@ -321,31 +321,31 @@ contract TaikoL2 is EssentialContract, TaikoL2Signer, ICrossChainSync {
function _calcBasefee(
EIP1559Config memory config,
uint256 timeSinceParent,
uint32 gasLimit,
uint32 parentGasUsed
)
private
view
returns (uint256 _basefee, uint64 _gasExcess)
{
// Very important to cap _gasExcess uint64
unchecked {
uint32 parentGasUsedNet = parentGasUsed
> LibL2Consts.ANCHOR_GAS_COST
? parentGasUsed - LibL2Consts.ANCHOR_GAS_COST
: 0;

uint256 a = uint256(gasExcess) + parentGasUsedNet;
uint256 b = config.gasIssuedPerSecond * timeSinceParent;
_gasExcess = uint64((a.max(b) - b).min(type(uint64).max));
uint32 parentGasUsedNet;
if (parentGasUsed > LibL2Consts.ANCHOR_GAS_COST) {
parentGasUsedNet = parentGasUsed - LibL2Consts.ANCHOR_GAS_COST;
}

uint256 issued = timeSinceParent * config.gasIssuedPerSecond;
uint256 excess = (uint256(gasExcess) + parentGasUsedNet).max(issued);
// Very important to cap _gasExcess uint64
_gasExcess = uint64((excess - issued).min(type(uint64).max));
}

_basefee = Lib1559Math.calculatePrice({
xscale: config.xscale,
yscale: config.yscale,
xExcess: _gasExcess,
xPurchase: gasLimit
xPurchase: 0
});

if (_basefee == 0) {
// To make sure when 1559 is enabled, the basefee is non-zero
// (geth never use 0 values for basefee)
Expand Down
5 changes: 4 additions & 1 deletion packages/protocol/docs/how_taiko_proves_blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ A valid transaction (defined in the Ethereum Yellow Paper):
- Has a valid transaction signature.
- Has a valid transaction nonce (equivalent to the sender account's current nonce).
- Has no contract code deployed on the sender account (see EIP-3607 by Feist et al. [2021]).
- Has a gas limit no smaller than the intrinsic gas, _`g0`_, used by the transaction; and the sender account balance contains at least the cost, _`v0`_, required in up-front payment.
- Has a gas limit no smaller than the intrinsic gas, _`g0`_, used by the transaction.
- The sender account balance contains at least the cost, _`v0`_, required in up-front payment.
- The transaction has a gas limit that is smaller or equal to the amount of gas left in the block (with the block gas limit being the protocol constant _`blockMaxGasLimit`_).
- The transaction has a basefee that is greater than or equal the basefee of the block.

#### Slicing and Consistency

Expand Down
1 change: 0 additions & 1 deletion packages/protocol/test/TaikoL1TestBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ abstract contract TaikoL1TestBase is Test {
bytes memory txList = new bytes(txListSize);
TaikoData.BlockMetadataInput memory input = TaikoData.BlockMetadataInput({
beneficiary: proposer,
gasLimit: gasLimit,
txListHash: keccak256(txList),
txListByteStart: 0,
txListByteEnd: txListSize,
Expand Down
47 changes: 15 additions & 32 deletions packages/protocol/test/TaikoL2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ contract TestTaikoL2 is Test {
function testAnchorTxsBlocktimeConstant() external {
uint256 firstBasefee;
for (uint256 i = 0; i < 100; i++) {
uint256 basefee = _getBasefeeAndPrint(0, BLOCK_GAS_LIMIT);
uint256 basefee = _getBasefeeAndPrint2(0, BLOCK_GAS_LIMIT);
vm.fee(basefee);

if (firstBasefee == 0) {
Expand All @@ -60,7 +60,7 @@ contract TestTaikoL2 is Test {
uint256 prevBasefee;

for (uint256 i = 0; i < 32; i++) {
uint256 basefee = _getBasefeeAndPrint(0, BLOCK_GAS_LIMIT);
uint256 basefee = _getBasefeeAndPrint2(0, BLOCK_GAS_LIMIT);
vm.fee(basefee);

assertGe(basefee, prevBasefee);
Expand All @@ -78,7 +78,7 @@ contract TestTaikoL2 is Test {
uint256 prevBasefee;

for (uint256 i = 0; i < 30; i++) {
uint256 basefee = _getBasefeeAndPrint(0, BLOCK_GAS_LIMIT);
uint256 basefee = _getBasefeeAndPrint2(0, BLOCK_GAS_LIMIT);
vm.fee(basefee);

if (prevBasefee != 0) {
Expand All @@ -97,7 +97,7 @@ contract TestTaikoL2 is Test {

// calling anchor in the same block more than once should fail
function testAnchorTxsFailInTheSameBlock() external {
uint256 expectedBasefee = _getBasefeeAndPrint(0, BLOCK_GAS_LIMIT);
uint256 expectedBasefee = _getBasefeeAndPrint2(0, BLOCK_GAS_LIMIT);
vm.fee(expectedBasefee);

vm.prank(L2.GOLDEN_TOUCH_ADDRESS());
Expand All @@ -110,7 +110,7 @@ contract TestTaikoL2 is Test {

// calling anchor in the same block more than once should fail
function testAnchorTxsFailByNonTaikoL2Signer() external {
uint256 expectedBasefee = _getBasefeeAndPrint(0, BLOCK_GAS_LIMIT);
uint256 expectedBasefee = _getBasefeeAndPrint2(0, BLOCK_GAS_LIMIT);
vm.fee(expectedBasefee);
vm.expectRevert();
_anchor(BLOCK_GAS_LIMIT);
Expand All @@ -133,32 +133,18 @@ contract TestTaikoL2 is Test {
}

function testGetBasefee() external {
uint32 timeSinceParent = uint32(block.timestamp - L2.parentTimestamp());
assertEq(_getBasefeeAndPrint(timeSinceParent, 0, 0), 317_609_019);
assertEq(_getBasefeeAndPrint(timeSinceParent, 1, 0), 317_609_019);
assertEq(
_getBasefeeAndPrint(timeSinceParent, 1_000_000, 0), 320_423_332
);
assertEq(
_getBasefeeAndPrint(timeSinceParent, 5_000_000, 0), 332_018_053
);
assertEq(
_getBasefeeAndPrint(timeSinceParent, 10_000_000, 0), 347_305_199
);
uint64 timeSinceParent = uint64(block.timestamp - L2.parentTimestamp());
assertEq(_getBasefeeAndPrint(timeSinceParent, 0), 317_609_019);

timeSinceParent = uint32(100 + block.timestamp - L2.parentTimestamp());
assertEq(_getBasefeeAndPrint(timeSinceParent, 0, 0), 54_544_902);
assertEq(_getBasefeeAndPrint(timeSinceParent, 1, 0), 54_544_902);
assertEq(_getBasefeeAndPrint(timeSinceParent, 1_000_000, 0), 55_028_221);
assertEq(_getBasefeeAndPrint(timeSinceParent, 5_000_000, 0), 57_019_452);
assertEq(
_getBasefeeAndPrint(timeSinceParent, 10_000_000, 0), 59_644_805
);
timeSinceParent += 100;
assertEq(_getBasefeeAndPrint(timeSinceParent, 0), 54_544_902);

timeSinceParent += 10_000;
assertEq(_getBasefeeAndPrint(timeSinceParent, 0), 1);
}

function _getBasefeeAndPrint(
uint32 timeSinceParent,
uint32 gasLimit,
uint64 timeSinceParent,
uint32 parentGasUsed
)
private
Expand All @@ -175,12 +161,10 @@ contract TestTaikoL2 is Test {
Strings.toString(timeSinceParent),
", gasIssued=",
Strings.toString(gasIssued),
", gasLimit=",
Strings.toString(gasLimit),
", parentGasUsed=",
Strings.toString(parentGasUsed)
);
_basefee = L2.getBasefee(timeSinceParent, gasLimit, parentGasUsed);
_basefee = L2.getBasefee(timeSinceParent, parentGasUsed);
assertTrue(_basefee != 0);

_msg = string.concat(
Expand All @@ -194,7 +178,7 @@ contract TestTaikoL2 is Test {
console2.log(_msg);
}

function _getBasefeeAndPrint(
function _getBasefeeAndPrint2(
uint32 timeSinceNow,
uint32 gasLimit
)
Expand All @@ -203,7 +187,6 @@ contract TestTaikoL2 is Test {
{
return _getBasefeeAndPrint(
uint32(timeSinceNow + block.timestamp - L2.parentTimestamp()),
gasLimit,
gasLimit + ANCHOR_GAS_COST
);
}
Expand Down
8 changes: 2 additions & 6 deletions packages/protocol/test/genesis/GenerateGenesis.g.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ contract TestGenerateGenesis is Test, AddressResolver {
address private owner = configJSON.readAddress(".contractOwner");
address private admin = configJSON.readAddress(".contractAdmin");

uint32 public constant BLOCK_GAS_LIMIT = 30_000_000;
// uint32 public constant BLOCK_GAS_LIMIT = 30_000_000;

function testContractDeployment() public {
assertEq(block.chainid, 167);
Expand Down Expand Up @@ -107,11 +107,7 @@ contract TestGenerateGenesis is Test, AddressResolver {
for (uint32 i = 0; i < 300; i++) {
vm.roll(block.number + 1);
vm.warp(taikoL2.parentTimestamp() + 12);
vm.fee(
taikoL2.getBasefee(
12, BLOCK_GAS_LIMIT, i + LibL2Consts.ANCHOR_GAS_COST
)
);
vm.fee(taikoL2.getBasefee(12, i + LibL2Consts.ANCHOR_GAS_COST));

uint256 gasLeftBefore = gasleft();

Expand Down

0 comments on commit 06710eb

Please sign in to comment.