Commit 5bd72f69 authored by Roberto Bayardo's avatar Roberto Bayardo Committed by GitHub

Holocene extensions to L1Block.sol (#12096)

parent 909d7fd2
GasBenchMark_L1BlockInterop_DepositsComplete:test_depositsComplete_benchmark() (gas: 7567) GasBenchMark_L1BlockInterop_DepositsComplete:test_depositsComplete_benchmark() (gas: 7589)
GasBenchMark_L1BlockInterop_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5567) GasBenchMark_L1BlockInterop_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5589)
GasBenchMark_L1BlockInterop_SetValuesInterop:test_setL1BlockValuesInterop_benchmark() (gas: 175677) GasBenchMark_L1BlockInterop_SetValuesInterop:test_setL1BlockValuesInterop_benchmark() (gas: 175655)
GasBenchMark_L1BlockInterop_SetValuesInterop_Warm:test_setL1BlockValuesInterop_benchmark() (gas: 5099) GasBenchMark_L1BlockInterop_SetValuesInterop_Warm:test_setL1BlockValuesInterop_benchmark() (gas: 5099)
GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158531) GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158531)
GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597) GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597)
......
...@@ -80,12 +80,12 @@ ...@@ -80,12 +80,12 @@
"sourceCodeHash": "0x4f21025d4b5c9c74cf7040db6f8e9ce605b82931e3012fee51d3f5d9fbd7b73f" "sourceCodeHash": "0x4f21025d4b5c9c74cf7040db6f8e9ce605b82931e3012fee51d3f5d9fbd7b73f"
}, },
"src/L2/L1Block.sol": { "src/L2/L1Block.sol": {
"initCodeHash": "0xd12353c5bf71c6765cc9292eecf262f216e67f117f4ba6287796a5207dbca00f", "initCodeHash": "0x48d118de2a69fb0fbf6a8da4603025e12da1360da8fb70a5e56342ba64b3ff5f",
"sourceCodeHash": "0xfe3a9585d9bfca8428e12759cab68a3114374e5c37371cfe08bb1976a9a5a041" "sourceCodeHash": "0x04d25cbf0c4ea5025b0dd3f79f0a32f6623ddb869cff35649072ab3ad964b310"
}, },
"src/L2/L1BlockInterop.sol": { "src/L2/L1BlockInterop.sol": {
"initCodeHash": "0x77b3b2151fe14ea36a640469115a5e4de27f7654a9606a9d0701522c6a4ad887", "initCodeHash": "0x7f87e0b8be9801cb242c469ec7999eb80221f65063aedd4ca4923a5e0fb0e5a7",
"sourceCodeHash": "0x7417677643e1df1ae1782513b94c7821097b9529d3f8626c3bcb8b3a9ae0d180" "sourceCodeHash": "0x722071a9d08dcbeda9cdaadeb2dd679a8bc192563e4a0439f4cd74439fa75581"
}, },
"src/L2/L1FeeVault.sol": { "src/L2/L1FeeVault.sol": {
"initCodeHash": "0x3bfcd57e25ad54b66c374f63e24e33a6cf107044aa8f5f69ef21202c380b5c5b", "initCodeHash": "0x3bfcd57e25ad54b66c374f63e24e33a6cf107044aa8f5f69ef21202c380b5c5b",
......
...@@ -77,6 +77,32 @@ ...@@ -77,6 +77,32 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "eip1559Denominator",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "eip1559Elasticity",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "gasPayingToken", "name": "gasPayingToken",
...@@ -282,6 +308,13 @@ ...@@ -282,6 +308,13 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "setL1BlockValuesHolocene",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "timestamp", "name": "timestamp",
......
...@@ -97,6 +97,32 @@ ...@@ -97,6 +97,32 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "eip1559Denominator",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "eip1559Elasticity",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "gasPayingToken", "name": "gasPayingToken",
...@@ -352,6 +378,13 @@ ...@@ -352,6 +378,13 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [],
"name": "setL1BlockValuesHolocene",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "setL1BlockValuesInterop", "name": "setL1BlockValuesInterop",
......
...@@ -75,5 +75,19 @@ ...@@ -75,5 +75,19 @@
"offset": 0, "offset": 0,
"slot": "7", "slot": "7",
"type": "uint256" "type": "uint256"
},
{
"bytes": "8",
"label": "eip1559Denominator",
"offset": 0,
"slot": "8",
"type": "uint64"
},
{
"bytes": "8",
"label": "eip1559Elasticity",
"offset": 8,
"slot": "8",
"type": "uint64"
} }
] ]
\ No newline at end of file
...@@ -76,11 +76,25 @@ ...@@ -76,11 +76,25 @@
"slot": "7", "slot": "7",
"type": "uint256" "type": "uint256"
}, },
{
"bytes": "8",
"label": "eip1559Denominator",
"offset": 0,
"slot": "8",
"type": "uint64"
},
{
"bytes": "8",
"label": "eip1559Elasticity",
"offset": 8,
"slot": "8",
"type": "uint64"
},
{ {
"bytes": "64", "bytes": "64",
"label": "dependencySet", "label": "dependencySet",
"offset": 0, "offset": 0,
"slot": "8", "slot": "9",
"type": "struct EnumerableSet.UintSet" "type": "struct EnumerableSet.UintSet"
} }
] ]
\ No newline at end of file
...@@ -57,9 +57,15 @@ contract L1Block is ISemver, IGasToken { ...@@ -57,9 +57,15 @@ contract L1Block is ISemver, IGasToken {
/// @notice The latest L1 blob base fee. /// @notice The latest L1 blob base fee.
uint256 public blobBaseFee; uint256 public blobBaseFee;
/// @custom:semver 1.5.1-beta.2 /// @notice The eip-1550 base fee change denominator value.
uint64 public eip1559Denominator;
/// @notice The eip-1550 base fee change elasticity value.
uint64 public eip1559Elasticity;
/// @custom:semver 1.5.1-beta.3
function version() public pure virtual returns (string memory) { function version() public pure virtual returns (string memory) {
return "1.5.1-beta.2"; return "1.5.1-beta.3";
} }
/// @notice Returns the gas paying token, its decimals, name and symbol. /// @notice Returns the gas paying token, its decimals, name and symbol.
...@@ -168,6 +174,59 @@ contract L1Block is ISemver, IGasToken { ...@@ -168,6 +174,59 @@ contract L1Block is ISemver, IGasToken {
} }
} }
/// @notice Updates the L1 block values for a Holocene upgraded chain.
/// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size.
/// Params are expected to be in the following order:
/// 1. _baseFeeScalar L1 base fee scalar
/// 2. _blobBaseFeeScalar L1 blob base fee scalar
/// 3. _sequenceNumber Number of L2 blocks since epoch start.
/// 4. _timestamp L1 timestamp.
/// 5. _number L1 blocknumber.
/// 6. _basefee L1 base fee.
/// 7. _blobBaseFee L1 blob base fee.
/// 8. _hash L1 blockhash.
/// 9. _batcherHash Versioned hash to authenticate batcher by.
/// 10. _eip1559Elasticity EIP-1559 elasticity multiplier value.
/// 11. _eip1559Denominator EIP-1559 base fee change denominator value.
function setL1BlockValuesHolocene() public {
_setL1BlockValuesHolocene();
}
/// @notice Updates the L1 block values for a Holocene upgraded chain.
/// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size.
/// Params are expected to be in the following order:
/// 1. _baseFeeScalar L1 base fee scalar
/// 2. _blobBaseFeeScalar L1 blob base fee scalar
/// 3. _sequenceNumber Number of L2 blocks since epoch start.
/// 4. _timestamp L1 timestamp.
/// 5. _number L1 blocknumber.
/// 6. _basefee L1 base fee.
/// 7. _blobBaseFee L1 blob base fee.
/// 8. _hash L1 blockhash.
/// 9. _batcherHash Versioned hash to authenticate batcher by.
/// 10. _eip1559Elasticity EIP-1559 elasticity multiplier value.
/// 11. _eip1559Denominator EIP-1559 base fee change denominator value.
function _setL1BlockValuesHolocene() internal {
address depositor = DEPOSITOR_ACCOUNT();
assembly {
// Revert if the caller is not the depositor account.
if xor(caller(), depositor) {
mstore(0x00, 0x3cc50b45) // 0x3cc50b45 is the 4-byte selector of "NotDepositor()"
revert(0x1C, 0x04) // returns the stored 4-byte selector from above
}
// sequencenum (uint64), blobBaseFeeScalar (uint32), baseFeeScalar (uint32)
sstore(sequenceNumber.slot, shr(128, calldataload(4)))
// number (uint64) and timestamp (uint64)
sstore(number.slot, shr(128, calldataload(20)))
sstore(basefee.slot, calldataload(36)) // uint256
sstore(blobBaseFee.slot, calldataload(68)) // uint256
sstore(hash.slot, calldataload(100)) // bytes32
sstore(batcherHash.slot, calldataload(132)) // bytes32
// eip1559Denominator (uint64) and eip1559Elasticity (uint64)
sstore(eip1559Denominator.slot, shr(128, calldataload(164))) // uint64
}
}
/// @notice Sets the gas paying token for the L2 system. Can only be called by the special /// @notice Sets the gas paying token for the L2 system. Can only be called by the special
/// depositor account. This function is not called on every L2 block but instead /// depositor account. This function is not called on every L2 block but instead
/// only called by specially crafted L1 deposit transactions. /// only called by specially crafted L1 deposit transactions.
......
...@@ -42,9 +42,9 @@ contract L1BlockInterop is L1Block { ...@@ -42,9 +42,9 @@ contract L1BlockInterop is L1Block {
/// keccak256(abi.encode(uint256(keccak256("l1Block.identifier.isDeposit")) - 1)) & ~bytes32(uint256(0xff)) /// keccak256(abi.encode(uint256(keccak256("l1Block.identifier.isDeposit")) - 1)) & ~bytes32(uint256(0xff))
uint256 internal constant IS_DEPOSIT_SLOT = 0x921bd3a089295c6e5540e8fba8195448d253efd6f2e3e495b499b627dc36a300; uint256 internal constant IS_DEPOSIT_SLOT = 0x921bd3a089295c6e5540e8fba8195448d253efd6f2e3e495b499b627dc36a300;
/// @custom:semver +interop /// @custom:semver +interop-beta.1
function version() public pure override returns (string memory) { function version() public pure override returns (string memory) {
return string.concat(super.version(), "+interop"); return string.concat(super.version(), "+interop-beta.1");
} }
/// @notice Returns whether the call was triggered from a a deposit or not. /// @notice Returns whether the call was triggered from a a deposit or not.
......
...@@ -34,8 +34,11 @@ interface IL1Block { ...@@ -34,8 +34,11 @@ interface IL1Block {
) )
external; external;
function setL1BlockValuesEcotone() external; function setL1BlockValuesEcotone() external;
function setL1BlockValuesHolocene() external;
function timestamp() external view returns (uint64); function timestamp() external view returns (uint64);
function version() external pure returns (string memory); function version() external pure returns (string memory);
function eip1559Denominator() external view returns (uint64);
function eip1559Elasticity() external view returns (uint64);
function __constructor__() external; function __constructor__() external;
} }
...@@ -52,9 +52,12 @@ interface IL1BlockInterop { ...@@ -52,9 +52,12 @@ interface IL1BlockInterop {
) )
external; external;
function setL1BlockValuesEcotone() external; function setL1BlockValuesEcotone() external;
function setL1BlockValuesHolocene() external;
function setL1BlockValuesInterop() external; function setL1BlockValuesInterop() external;
function timestamp() external view returns (uint64); function timestamp() external view returns (uint64);
function version() external pure returns (string memory); function version() external pure returns (string memory);
function eip1559Denominator() external view returns (uint64);
function eip1559Elasticity() external view returns (uint64);
function __constructor__() external; function __constructor__() external;
} }
...@@ -213,4 +213,50 @@ library Encoding { ...@@ -213,4 +213,50 @@ library Encoding {
_batcherHash _batcherHash
); );
} }
/// @notice Returns an appropriately encoded call to L1Block.setL1BlockValuesHolocene
/// @param baseFeeScalar L1 base fee Scalar
/// @param blobBaseFeeScalar L1 blob base fee Scalar
/// @param sequenceNumber Number of L2 blocks since epoch start.
/// @param timestamp L1 timestamp.
/// @param number L1 blocknumber.
/// @param baseFee L1 base fee.
/// @param blobBaseFee L1 blob base fee.
/// @param hash L1 blockhash.
/// @param batcherHash Versioned hash to authenticate batcher by.
/// @param eip1559Elasticity EIP-1559 elasticity parameter
/// @param eip1559Denominator EIP-1559 denominator parameter
function encodeSetL1BlockValuesHolocene(
uint32 baseFeeScalar,
uint32 blobBaseFeeScalar,
uint64 sequenceNumber,
uint64 timestamp,
uint64 number,
uint256 baseFee,
uint256 blobBaseFee,
bytes32 hash,
bytes32 batcherHash,
uint64 eip1559Elasticity,
uint64 eip1559Denominator
)
internal
pure
returns (bytes memory)
{
bytes4 functionSignature = bytes4(keccak256("setL1BlockValuesHolocene()"));
return abi.encodePacked(
functionSignature,
baseFeeScalar,
blobBaseFeeScalar,
sequenceNumber,
timestamp,
number,
baseFee,
blobBaseFee,
hash,
batcherHash,
eip1559Elasticity,
eip1559Denominator
);
}
} }
...@@ -165,6 +165,116 @@ contract L1BlockEcotone_Test is L1BlockTest { ...@@ -165,6 +165,116 @@ contract L1BlockEcotone_Test is L1BlockTest {
} }
} }
contract L1BlockHolocene_Test is L1BlockTest {
/// @dev Tests that setL1BlockValuesHolocene updates the values appropriately.
function testFuzz_setL1BlockValuesHolocene_succeeds(
uint32 baseFeeScalar,
uint32 blobBaseFeeScalar,
uint64 sequenceNumber,
uint64 timestamp,
uint64 number,
uint256 baseFee,
uint256 blobBaseFee,
bytes32 hash,
bytes32 batcherHash,
uint64 eip1559Elasticity,
uint64 eip1559Denominator
)
external
{
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesHolocene(
baseFeeScalar,
blobBaseFeeScalar,
sequenceNumber,
timestamp,
number,
baseFee,
blobBaseFee,
hash,
batcherHash,
eip1559Elasticity,
eip1559Denominator
);
vm.prank(depositor);
(bool success,) = address(l1Block).call(functionCallDataPacked);
assertTrue(success, "Function call failed");
assertEq(l1Block.baseFeeScalar(), baseFeeScalar);
assertEq(l1Block.blobBaseFeeScalar(), blobBaseFeeScalar);
assertEq(l1Block.sequenceNumber(), sequenceNumber);
assertEq(l1Block.timestamp(), timestamp);
assertEq(l1Block.number(), number);
assertEq(l1Block.basefee(), baseFee);
assertEq(l1Block.blobBaseFee(), blobBaseFee);
assertEq(l1Block.hash(), hash);
assertEq(l1Block.batcherHash(), batcherHash);
assertEq(l1Block.eip1559Denominator(), eip1559Denominator);
assertEq(l1Block.eip1559Elasticity(), eip1559Elasticity);
// ensure we didn't accidentally pollute the 128 bits of the sequencenum+scalars slot that
// should be empty
bytes32 scalarsSlot = vm.load(address(l1Block), bytes32(uint256(3)));
bytes32 mask128 = hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000";
assertEq(0, scalarsSlot & mask128);
// ensure we didn't accidentally pollute the 128 bits of the number & timestamp slot that
// should be empty
bytes32 numberTimestampSlot = vm.load(address(l1Block), bytes32(uint256(0)));
assertEq(0, numberTimestampSlot & mask128);
// ensure we didn't accidentally pollute the 128 bits of the eip-1559 parameters slot that
// should be empty
bytes32 eip1559ParamsSlot = vm.load(address(l1Block), bytes32(uint256(9)));
assertEq(0, eip1559ParamsSlot & mask128);
}
/// @dev Tests that `setL1BlockValuesHolocene` succeeds if sender address is the depositor
function test_setL1BlockValuesHolocene_isDepositor_succeeds() external {
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesHolocene(
type(uint32).max,
type(uint32).max,
type(uint64).max,
type(uint64).max,
type(uint64).max,
type(uint256).max,
type(uint256).max,
bytes32(type(uint256).max),
bytes32(type(uint256).max),
type(uint64).max,
type(uint64).max
);
vm.prank(depositor);
(bool success,) = address(l1Block).call(functionCallDataPacked);
assertTrue(success, "function call failed");
}
/// @dev Tests that `setL1BlockValuesEcotone` reverts if sender address is not the depositor
function test_setL1BlockValuesHolocene_notDepositor_reverts() external {
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesHolocene(
type(uint32).max,
type(uint32).max,
type(uint64).max,
type(uint64).max,
type(uint64).max,
type(uint256).max,
type(uint256).max,
bytes32(type(uint256).max),
bytes32(type(uint256).max),
type(uint64).max,
type(uint64).max
);
(bool success, bytes memory data) = address(l1Block).call(functionCallDataPacked);
assertTrue(!success, "function call should have failed");
// make sure return value is the expected function selector for "NotDepositor()"
bytes memory expReturn = hex"3cc50b45";
assertEq(data, expReturn);
}
}
contract L1BlockCustomGasToken_Test is L1BlockTest { contract L1BlockCustomGasToken_Test is L1BlockTest {
function testFuzz_setGasPayingToken_succeeds( function testFuzz_setGasPayingToken_succeeds(
address _token, address _token,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment