From a62acdcd418fdcf7705d18cb39e83cf9d5be85c6 Mon Sep 17 00:00:00 2001 From: Brechtpd Date: Tue, 1 Aug 2023 19:39:17 +0200 Subject: [PATCH 1/7] Gas limit behavior changes --- packages/protocol/contracts/L1/libs/LibProposing.sol | 4 +--- packages/protocol/docs/how_taiko_proves_blocks.md | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index ce8fd0fc4ce..604a8dc91a2 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -65,7 +65,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 = @@ -123,8 +123,6 @@ library LibProposing { input.beneficiary == address(0) // || input.gasLimit == 0 - // - || input.gasLimit > config.blockMaxGasLimit ) revert L1_INVALID_METADATA(); if ( diff --git a/packages/protocol/docs/how_taiko_proves_blocks.md b/packages/protocol/docs/how_taiko_proves_blocks.md index ca73098a700..8bbd9724ec2 100644 --- a/packages/protocol/docs/how_taiko_proves_blocks.md +++ b/packages/protocol/docs/how_taiko_proves_blocks.md @@ -14,7 +14,6 @@ A valid `txList` (until [issue #13724](https://github.com/taikoxyz/taiko-mono/is - Has a byte-size smaller than the protocol constant _`maxBytesPerTxList`_ (also enforced in contracts); - Can be RLP-decoded into a list of transactions without trailing space; - Contains no more transactions (valid and invalid) than the protocol constant _`maxTransactionsPerBlock`_; -- Has a total gas limit for all valid transactions not exceeding the protocol constant _`blockMaxGasLimit`_; ZKP must prove whether the `txList` is valid or invalid. For an invalid `txList`, the corresponding L2 block will only have an anchor transaction. @@ -25,7 +24,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 From 384afa42b9df756afd9188aa936cd6b1cb483d11 Mon Sep 17 00:00:00 2001 From: Brechtpd Date: Tue, 1 Aug 2023 19:55:35 +0200 Subject: [PATCH 2/7] Fix compile error --- packages/protocol/contracts/L1/libs/LibProposing.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index 604a8dc91a2..349553d9d3c 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -65,7 +65,7 @@ library LibProposing { meta.txListHash = input.txListHash; meta.txListByteStart = input.txListByteStart; meta.txListByteEnd = input.txListByteEnd; - meta.gasLimit = config.blockMaxGasLimit; + meta.gasLimit = uint32(config.blockMaxGasLimit); meta.beneficiary = input.beneficiary; meta.treasury = resolver.resolve(config.chainId, "treasury", false); meta.depositsProcessed = From 8598d9138f2e063c5ed887d49e22fca880075766 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Sat, 5 Aug 2023 17:36:08 +0800 Subject: [PATCH 3/7] remove gasLimit from input --- packages/protocol/contracts/L1/TaikoData.sol | 3 +-- packages/protocol/contracts/L1/libs/LibProposing.sol | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol index 0d02d7de90d..ce6dd7a3c2d 100644 --- a/packages/protocol/contracts/L1/TaikoData.sol +++ b/packages/protocol/contracts/L1/TaikoData.sol @@ -41,11 +41,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) uint8 cacheTxListInfo; // non-zero = True diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index 349553d9d3c..e179ca516ab 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -119,11 +119,7 @@ library LibProposing { view returns (uint8 cacheTxListInfo) { - if ( - input.beneficiary == address(0) - // - || input.gasLimit == 0 - ) revert L1_INVALID_METADATA(); + if (input.beneficiary == address(0)) revert L1_INVALID_METADATA(); if ( state.numBlocks From 6c89ff3785aa836e8365a623fca89ecc5322e028 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:00:29 +0800 Subject: [PATCH 4/7] small improvements --- packages/protocol/contracts/L1/libs/LibProposing.sol | 2 +- packages/protocol/contracts/L2/TaikoL2.sol | 8 ++++---- packages/protocol/docs/how_taiko_proves_blocks.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index 63379fa9656..41df72ebfde 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -103,7 +103,7 @@ library LibProposing { meta.txListHash = input.txListHash; meta.txListByteStart = input.txListByteStart; meta.txListByteEnd = input.txListByteEnd; - meta.gasLimit = uint32(config.blockMaxGasLimit); + meta.gasLimit = config.blockMaxGasLimit; meta.beneficiary = input.beneficiary; meta.treasury = resolver.resolve(config.chainId, "treasury", false); meta.depositsProcessed = diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index 3c5b89163e2..2e97f391c11 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -330,10 +330,10 @@ contract TaikoL2 is EssentialContract, TaikoL2Signer, ICrossChainSync { { // Very important to cap _gasExcess uint64 unchecked { - uint32 parentGasUsedNet = parentGasUsed - > LibL2Consts.ANCHOR_GAS_COST - ? parentGasUsed - LibL2Consts.ANCHOR_GAS_COST - : 0; + uint32 parentGasUsedNet; + if (parentGasUsed > LibL2Consts.ANCHOR_GAS_COST) { + parentGasUsedNet = parentGasUsed - LibL2Consts.ANCHOR_GAS_COST; + } uint256 a = uint256(gasExcess) + parentGasUsedNet; uint256 b = config.gasIssuedPerSecond * timeSinceParent; diff --git a/packages/protocol/docs/how_taiko_proves_blocks.md b/packages/protocol/docs/how_taiko_proves_blocks.md index 05330a07bc7..fe66f76f540 100644 --- a/packages/protocol/docs/how_taiko_proves_blocks.md +++ b/packages/protocol/docs/how_taiko_proves_blocks.md @@ -13,7 +13,7 @@ A valid `txList` (until [issue #13724](https://github.com/taikoxyz/taiko-mono/is - Has a byte-size smaller than the protocol constant _`blockMaxTxListBytes`_ (also enforced in contracts); - Can be RLP-decoded into a list of transactions without trailing space; -- Contains no more transactions (valid and invalid) than the protocol constant _`maxTransactionsPerBlock`_; +- Contains no more transactions (valid and invalid) than the protocol constant _`blockMaxTransactions`_; - Has a total gas limit for all valid transactions not exceeding the protocol constant _`blockMaxGasLimit`_; ZKP must prove whether the `txList` is valid or invalid. For an invalid `txList`, the corresponding L2 block will only have an anchor transaction. From ff23530cd89bbefcb5540f6ceb1732793ae7c404 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:01:13 +0800 Subject: [PATCH 5/7] Revert "remove gasLimit from input" This reverts commit 8598d9138f2e063c5ed887d49e22fca880075766. --- packages/protocol/contracts/L1/TaikoData.sol | 3 ++- packages/protocol/contracts/L1/libs/LibProposing.sol | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol index 3bf9db204fa..254918bcff5 100644 --- a/packages/protocol/contracts/L1/TaikoData.sol +++ b/packages/protocol/contracts/L1/TaikoData.sol @@ -52,10 +52,11 @@ library TaikoData { uint64 numEthDeposits; } - // 2 slots + // 3 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; diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index 41df72ebfde..d3116679cfd 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -183,7 +183,11 @@ library LibProposing { view returns (bool cacheTxListInfo) { - if (input.beneficiary == address(0)) revert L1_INVALID_METADATA(); + if ( + input.beneficiary == address(0) + // + || input.gasLimit == 0 + ) revert L1_INVALID_METADATA(); if ( state.numBlocks From 2f55ba26cd590ad36a2793d2b8cbf9ab960fb48d Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Sun, 6 Aug 2023 10:16:42 +0800 Subject: [PATCH 6/7] Revert "Revert "remove gasLimit from input"" This reverts commit ff23530cd89bbefcb5540f6ceb1732793ae7c404. --- packages/protocol/contracts/L1/TaikoData.sol | 3 +-- packages/protocol/contracts/L1/libs/LibProposing.sol | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol index 254918bcff5..3bf9db204fa 100644 --- a/packages/protocol/contracts/L1/TaikoData.sol +++ b/packages/protocol/contracts/L1/TaikoData.sol @@ -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; diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index d3116679cfd..41df72ebfde 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -183,11 +183,7 @@ library LibProposing { view returns (bool cacheTxListInfo) { - if ( - input.beneficiary == address(0) - // - || input.gasLimit == 0 - ) revert L1_INVALID_METADATA(); + if (input.beneficiary == address(0)) revert L1_INVALID_METADATA(); if ( state.numBlocks From 9985ae84a4a4fc68681bc734315972fb875aad14 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Mon, 7 Aug 2023 13:28:44 +0800 Subject: [PATCH 7/7] feat(protocol): L2 1559 no longer use block gas limit (#14388) --- packages/protocol/contracts/L2/TaikoL2.sol | 34 +++++++------- packages/protocol/test/TaikoL1TestBase.t.sol | 1 - packages/protocol/test/TaikoL2.t.sol | 47 ++++++------------- .../test/genesis/GenerateGenesis.g.sol | 8 +--- 4 files changed, 34 insertions(+), 56 deletions(-) diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index 2e97f391c11..3fd7c7b1c31 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -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. @@ -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) @@ -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; if (parentGasUsed > LibL2Consts.ANCHOR_GAS_COST) { parentGasUsedNet = parentGasUsed - LibL2Consts.ANCHOR_GAS_COST; } - uint256 a = uint256(gasExcess) + parentGasUsedNet; - uint256 b = config.gasIssuedPerSecond * timeSinceParent; - _gasExcess = uint64((a.max(b) - b).min(type(uint64).max)); + 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) diff --git a/packages/protocol/test/TaikoL1TestBase.t.sol b/packages/protocol/test/TaikoL1TestBase.t.sol index a27d88f748e..3a71a67a88c 100644 --- a/packages/protocol/test/TaikoL1TestBase.t.sol +++ b/packages/protocol/test/TaikoL1TestBase.t.sol @@ -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, diff --git a/packages/protocol/test/TaikoL2.t.sol b/packages/protocol/test/TaikoL2.t.sol index 2a98cc260ce..9f5205c8b68 100644 --- a/packages/protocol/test/TaikoL2.t.sol +++ b/packages/protocol/test/TaikoL2.t.sol @@ -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) { @@ -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); @@ -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) { @@ -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()); @@ -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); @@ -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 @@ -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( @@ -194,7 +178,7 @@ contract TestTaikoL2 is Test { console2.log(_msg); } - function _getBasefeeAndPrint( + function _getBasefeeAndPrint2( uint32 timeSinceNow, uint32 gasLimit ) @@ -203,7 +187,6 @@ contract TestTaikoL2 is Test { { return _getBasefeeAndPrint( uint32(timeSinceNow + block.timestamp - L2.parentTimestamp()), - gasLimit, gasLimit + ANCHOR_GAS_COST ); } diff --git a/packages/protocol/test/genesis/GenerateGenesis.g.sol b/packages/protocol/test/genesis/GenerateGenesis.g.sol index 747aa73133c..85abe572580 100644 --- a/packages/protocol/test/genesis/GenerateGenesis.g.sol +++ b/packages/protocol/test/genesis/GenerateGenesis.g.sol @@ -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); @@ -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();