diff --git a/.changeset/curvy-numbers-shake.md b/.changeset/curvy-numbers-shake.md new file mode 100644 index 0000000000000..bccebdebe69f0 --- /dev/null +++ b/.changeset/curvy-numbers-shake.md @@ -0,0 +1,5 @@ +--- +'@eth-optimism/contracts-bedrock': patch +--- + +Cleans up hashing and encoding library natspec and function names diff --git a/packages/contracts-bedrock/.gas-snapshot b/packages/contracts-bedrock/.gas-snapshot index 29f866134b5c5..635e4aba8de76 100644 --- a/packages/contracts-bedrock/.gas-snapshot +++ b/packages/contracts-bedrock/.gas-snapshot @@ -1,15 +1,16 @@ -GasBenchMark_L1CrossDomainMessenger:test_L1MessengerSendMessage_benchmark_0() (gas: 158608) -GasBenchMark_L1CrossDomainMessenger:test_L1MessengerSendMessage_benchmark_1() (gas: 75017) -GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 249829) -GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 116083) -GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 249851) -GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 116058) +GasBenchMark_L1CrossDomainMessenger:test_L1MessengerSendMessage_benchmark_0() (gas: 158650) +GasBenchMark_L1CrossDomainMessenger:test_L1MessengerSendMessage_benchmark_1() (gas: 75059) +GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 249871) +GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 116125) +GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 249893) +GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 116100) GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 45413) GasBenchMark_L2OutputOracle:test_appendL2Output_benchmark() (gas: 68673) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 75069) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 35373) DeployerWhitelist_Test:test_owner() (gas: 7658) DeployerWhitelist_Test:test_storageSlots() (gas: 33494) +Encoding_Test:test_encodeDepositTransaction() (gas: 64610) GasPriceOracle_Test:test_baseFee() (gas: 8370) GasPriceOracle_Test:test_gasPrice() (gas: 8381) GasPriceOracle_Test:test_l1BaseFee() (gas: 10582) @@ -23,7 +24,8 @@ GasPriceOracle_Test:test_setL1BaseFeeReverts() (gas: 11717) GasPriceOracle_Test:test_setOverhead() (gas: 36767) GasPriceOracle_Test:test_setScalar() (gas: 36818) GasPriceOracle_Test:test_storageLayout() (gas: 86683) -Hashing_Test:test_l2TransactionHash() (gas: 104047) +Hashing_Test:test_hashDepositSource() (gas: 673) +Hashing_Test:test_hashDepositTransaction() (gas: 39129) L1BlockTest:test_basefee() (gas: 7531) L1BlockTest:test_hash() (gas: 7575) L1BlockTest:test_number() (gas: 7630) @@ -35,20 +37,20 @@ L1BlockNumberTest:test_getL1BlockNumber() (gas: 10657) L1BlockNumberTest:test_receive() (gas: 25437) L1CrossDomainMessenger_Test:testCannot_L1MessengerPause() (gas: 24517) L1CrossDomainMessenger_Test:testCannot_L1MessengerUnpause() (gas: 24509) -L1CrossDomainMessenger_Test:test_L1MessengerMessageVersion() (gas: 24671) +L1CrossDomainMessenger_Test:test_L1MessengerMessageVersion() (gas: 24716) L1CrossDomainMessenger_Test:test_L1MessengerPause() (gas: 47995) -L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageSucceeds() (gas: 77935) -L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageToSystemContract() (gas: 67946) +L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageSucceeds() (gas: 77773) +L1CrossDomainMessenger_Test:test_L1MessengerRelayMessageToSystemContract() (gas: 67784) L1CrossDomainMessenger_Test:test_L1MessengerRelayShouldRevertIfPaused() (gas: 60472) -L1CrossDomainMessenger_Test:test_L1MessengerSendMessage() (gas: 196861) -L1CrossDomainMessenger_Test:test_L1MessengerTwiceSendMessage() (gas: 1273524) +L1CrossDomainMessenger_Test:test_L1MessengerSendMessage() (gas: 196878) +L1CrossDomainMessenger_Test:test_L1MessengerTwiceSendMessage() (gas: 1273626) L1CrossDomainMessenger_Test:test_L1MessengerUnpause() (gas: 40890) L1CrossDomainMessenger_Test:test_L1MessengerXDomainSenderReverts() (gas: 24272) -L1CrossDomainMessenger_Test:test_L1MessengerxDomainMessageSenderResets() (gas: 86782) -L1StandardBridge_Test:test_depositERC20() (gas: 474966) -L1StandardBridge_Test:test_depositERC20To() (gas: 477147) -L1StandardBridge_Test:test_depositETH() (gas: 268899) -L1StandardBridge_Test:test_depositETHTo() (gas: 226721) +L1CrossDomainMessenger_Test:test_L1MessengerxDomainMessageSenderResets() (gas: 86701) +L1StandardBridge_Test:test_depositERC20() (gas: 475008) +L1StandardBridge_Test:test_depositERC20To() (gas: 477189) +L1StandardBridge_Test:test_depositETH() (gas: 268941) +L1StandardBridge_Test:test_depositETHTo() (gas: 226763) L1StandardBridge_Test:test_finalizeERC20Withdrawal() (gas: 490759) L1StandardBridge_Test:test_finalizeETHWithdrawal() (gas: 64409) L1StandardBridge_Test:test_initialize() (gas: 26336) @@ -56,17 +58,17 @@ L1StandardBridge_Test:test_onlyEOADepositERC20() (gas: 22363) L1StandardBridge_Test:test_onlyEOADepositETH() (gas: 40882) L1StandardBridge_Test:test_onlyL2BridgeFinalizeERC20Withdrawal() (gas: 36271) L1StandardBridge_Test:test_onlyPortalFinalizeERC20Withdrawal() (gas: 35600) -L1StandardBridge_Test:test_receive() (gas: 413479) +L1StandardBridge_Test:test_receive() (gas: 413521) L2CrossDomainMessenger_Test:testCannot_L2MessengerPause() (gas: 10821) -L2CrossDomainMessenger_Test:test_L2MessengerMessageVersion() (gas: 8400) +L2CrossDomainMessenger_Test:test_L2MessengerMessageVersion() (gas: 8445) L2CrossDomainMessenger_Test:test_L2MessengerPause() (gas: 31815) -L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageSucceeds() (gas: 57494) -L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageToSystemContract() (gas: 36221) +L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageSucceeds() (gas: 57332) +L2CrossDomainMessenger_Test:test_L2MessengerRelayMessageToSystemContract() (gas: 36140) L2CrossDomainMessenger_Test:test_L2MessengerRelayShouldRevertIfPaused() (gas: 41664) -L2CrossDomainMessenger_Test:test_L2MessengerSendMessage() (gas: 119619) -L2CrossDomainMessenger_Test:test_L2MessengerTwiceSendMessage() (gas: 133146) +L2CrossDomainMessenger_Test:test_L2MessengerSendMessage() (gas: 119627) +L2CrossDomainMessenger_Test:test_L2MessengerTwiceSendMessage() (gas: 133248) L2CrossDomainMessenger_Test:test_L2MessengerXDomainSenderReverts() (gas: 10599) -L2CrossDomainMessenger_Test:test_L2MessengerxDomainMessageSenderResets() (gas: 54925) +L2CrossDomainMessenger_Test:test_L2MessengerxDomainMessageSenderResets() (gas: 54844) L2OutputOracleTest:testCannot_AppendWithUnmatchedBlockhash() (gas: 26811) L2OutputOracleTest:testCannot_appendEmptyOutput() (gas: 24086) L2OutputOracleTest:testCannot_appendFutureTimetamp() (gas: 26075) @@ -90,14 +92,14 @@ L2OutputOracleUpgradeable_Test:test_cannotInitImpl() (gas: 8476) L2OutputOracleUpgradeable_Test:test_cannotInitProxy() (gas: 13497) L2OutputOracleUpgradeable_Test:test_initValuesOnProxy() (gas: 38865) L2OutputOracleUpgradeable_Test:test_upgrading() (gas: 230843) -L2StandardBridge_Test:test_ERC20BridgeFailed_whenLocalTokenIsBridge() (gas: 133158) +L2StandardBridge_Test:test_ERC20BridgeFailed_whenLocalTokenIsBridge() (gas: 133200) L2StandardBridge_Test:test_cannotWithdrawEthWithoutSendingIt() (gas: 21656) L2StandardBridge_Test:test_finalizeDeposit() (gas: 93203) -L2StandardBridge_Test:test_finalizeDeposit_failsToCompleteOutboundTransfer() (gas: 140168) +L2StandardBridge_Test:test_finalizeDeposit_failsToCompleteOutboundTransfer() (gas: 140210) L2StandardBridge_Test:test_initialize() (gas: 14802) -L2StandardBridge_Test:test_receive() (gas: 136483) -L2StandardBridge_Test:test_withdraw() (gas: 352780) -L2StandardBridge_Test:test_withdrawTo() (gas: 353464) +L2StandardBridge_Test:test_receive() (gas: 136525) +L2StandardBridge_Test:test_withdraw() (gas: 352813) +L2StandardBridge_Test:test_withdrawTo() (gas: 353498) L2StandardBridge_Test:test_withdraw_onlyEOA() (gas: 252006) L2ToL1MessagePasserTest:test_burn() (gas: 112037) L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract() (gas: 67892) @@ -267,4 +269,4 @@ SequencerFeeVault_Test:test_constructor() (gas: 7656) SequencerFeeVault_Test:test_minWithdrawalAmount() (gas: 5407) SequencerFeeVault_Test:test_receive() (gas: 17258) SequencerFeeVault_Test:test_revertWithdraw() (gas: 9332) -SequencerFeeVault_Test:test_withdraw() (gas: 147281) +SequencerFeeVault_Test:test_withdraw() (gas: 147323) diff --git a/packages/contracts-bedrock/.storage-layout b/packages/contracts-bedrock/.storage-layout index 6a8b592370a59..1fbb5bc5f08c9 100644 --- a/packages/contracts-bedrock/.storage-layout +++ b/packages/contracts-bedrock/.storage-layout @@ -31,7 +31,7 @@ |------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------| | xDomainMsgSender | address | 202 | 0 | 20 | contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger | |------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------| -| msgNonce | uint256 | 203 | 0 | 32 | contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger | +| msgNonce | uint240 | 203 | 0 | 30 | contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger | |------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------| | otherMessenger | address | 204 | 0 | 20 | contracts/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger | |------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------| @@ -192,7 +192,7 @@ |------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------| | xDomainMsgSender | address | 202 | 0 | 20 | contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger | |------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------| -| msgNonce | uint256 | 203 | 0 | 32 | contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger | +| msgNonce | uint240 | 203 | 0 | 30 | contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger | |------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------| | otherMessenger | address | 204 | 0 | 20 | contracts/L2/L2CrossDomainMessenger.sol:L2CrossDomainMessenger | |------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------| diff --git a/packages/contracts-bedrock/contracts/L1/OptimismPortal.sol b/packages/contracts-bedrock/contracts/L1/OptimismPortal.sol index fc92099a06789..10f8a0c494bcf 100644 --- a/packages/contracts-bedrock/contracts/L1/OptimismPortal.sol +++ b/packages/contracts-bedrock/contracts/L1/OptimismPortal.sol @@ -242,13 +242,13 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { // Verify that the output root can be generated with the elements in the proof. require( - proposal.outputRoot == Hashing._deriveOutputRoot(_outputRootProof), + proposal.outputRoot == Hashing.hashOutputRootProof(_outputRootProof), "OptimismPortal: invalid output root proof" ); // All withdrawals have a unique hash, we'll use this as the identifier for the withdrawal // and to prevent replay attacks. - bytes32 withdrawalHash = Hashing.withdrawalHash( + bytes32 withdrawalHash = Hashing.hashWithdrawal( _nonce, _sender, _target, diff --git a/packages/contracts-bedrock/contracts/L2/L2ToL1MessagePasser.sol b/packages/contracts-bedrock/contracts/L2/L2ToL1MessagePasser.sol index 2a929d2da295b..77b5c5c3665e4 100644 --- a/packages/contracts-bedrock/contracts/L2/L2ToL1MessagePasser.sol +++ b/packages/contracts-bedrock/contracts/L2/L2ToL1MessagePasser.sol @@ -79,7 +79,7 @@ contract L2ToL1MessagePasser is Semver { uint256 _gasLimit, bytes memory _data ) public payable { - bytes32 withdrawalHash = Hashing.withdrawalHash( + bytes32 withdrawalHash = Hashing.hashWithdrawal( nonce, msg.sender, _target, diff --git a/packages/contracts-bedrock/contracts/libraries/Encoding.sol b/packages/contracts-bedrock/contracts/libraries/Encoding.sol index 761614d423f46..c05f8702818ad 100644 --- a/packages/contracts-bedrock/contracts/libraries/Encoding.sol +++ b/packages/contracts-bedrock/contracts/libraries/Encoding.sol @@ -10,73 +10,58 @@ import { RLPWriter } from "./rlp/RLPWriter.sol"; */ library Encoding { /** - * Generates the correct cross domain calldata for a message. - * @param _target Target contract address. - * @param _sender Message sender address. - * @param _message Message to send to the target. - * @param _messageNonce Nonce for the provided message. - * @return ABI encoded cross domain calldata. + * @notice RLP encodes the L2 transaction that would be generated when a given deposit is sent + * to the L2 system. Useful for searching for a deposit in the L2 system. + * + * @param _from Address of the sender of the deposit. + * @param _to Address of the receiver of the deposit. + * @param _value ETH value to send to the receiver. + * @param _mint ETH value to mint on L2. + * @param _gasLimit Gas limit to use for the transaction. + * @param _isCreation Whether or not the transaction is a contract creation. + * @param _data Data to send with the transaction. + * @param _l1BlockHash Hash of the L1 block where the deposit was included. + * @param _logIndex Index of the deposit event in the L1 block. + * + * @return RLP encoded L2 deposit transaction. */ - function encodeXDomainCalldata( - address _target, - address _sender, - bytes memory _message, - uint256 _messageNonce - ) internal pure returns (bytes memory) { - return - abi.encodeWithSignature( - "relayMessage(address,address,bytes,uint256)", - _target, - _sender, - _message, - _messageNonce - ); - } - - /** - * @notice RLP encode a deposit transaction - * This only works for user deposits, not system deposits - * TODO: better name + rearrange the input param ordering? - */ - function L2Transaction( - bytes32 _l1BlockHash, - uint256 _logIndex, + function encodeDepositTransaction( address _from, address _to, - bool _isCreate, - uint256 _mint, uint256 _value, - uint256 _gas, - bytes memory _data + uint256 _mint, + uint64 _gasLimit, + bool _isCreation, + bytes memory _data, + bytes32 _l1BlockHash, + uint256 _logIndex ) internal pure returns (bytes memory) { - bytes32 source = Hashing.sourceHash(_l1BlockHash, _logIndex); - + bytes32 source = Hashing.hashDepositSource(_l1BlockHash, _logIndex); bytes[] memory raw = new bytes[](7); - raw[0] = RLPWriter.writeBytes(abi.encodePacked(source)); raw[1] = RLPWriter.writeAddress(_from); - - if (_isCreate == true) { - require(_to == address(0)); - raw[2] = RLPWriter.writeBytes(""); - } else { - raw[2] = RLPWriter.writeAddress(_to); - } - + raw[2] = _isCreation ? RLPWriter.writeBytes("") : RLPWriter.writeAddress(_to); raw[3] = RLPWriter.writeUint(_mint); raw[4] = RLPWriter.writeUint(_value); - raw[5] = RLPWriter.writeUint(_gas); + raw[5] = RLPWriter.writeUint(uint256(_gasLimit)); raw[6] = RLPWriter.writeBytes(_data); - - bytes memory encoded = RLPWriter.writeList(raw); - return abi.encodePacked(uint8(0x7e), uint8(0x0), encoded); + return abi.encodePacked(uint8(0x7e), uint8(0x0), RLPWriter.writeList(raw)); } /** - * @notice Encodes the cross domain message based on the version that - * is encoded in the nonce + * @notice Encodes the cross domain message based on the version that is encoded into the + * message nonce. + * + * @param _nonce Message nonce with version encoded into the first two bytes. + * @param _sender Address of the sender of the message. + * @param _target Address of the target of the message. + * @param _value ETH value to send to the target. + * @param _gasLimit Gas limit to use for the message. + * @param _data Data to send with the message. + * + * @return Encoded cross domain message. */ - function getVersionedEncoding( + function encodeCrossDomainMessage( uint256 _nonce, address _sender, address _target, @@ -84,32 +69,55 @@ library Encoding { uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes memory) { - uint16 version = getVersionFromNonce(_nonce); + (, uint16 version) = decodeVersionedNonce(_nonce); if (version == 0) { - return getEncodingV0(_target, _sender, _data, _nonce); + return encodeCrossDomainMessageV0(_target, _sender, _data, _nonce); } else if (version == 1) { - return getEncodingV1(_nonce, _sender, _target, _value, _gasLimit, _data); + return encodeCrossDomainMessageV1(_nonce, _sender, _target, _value, _gasLimit, _data); + } else { + revert("Encoding: unknown cross domain message version"); } - - revert("Unknown version."); } /** - * @notice Compute the legacy cross domain serialization + * @notice Encodes a cross domain message based on the V0 (legacy) encoding. + * + * @param _target Address of the target of the message. + * @param _sender Address of the sender of the message. + * @param _data Data to send with the message. + * @param _nonce Message nonce. + * + * @return Encoded cross domain message. */ - function getEncodingV0( + function encodeCrossDomainMessageV0( address _target, address _sender, bytes memory _data, uint256 _nonce ) internal pure returns (bytes memory) { - return encodeXDomainCalldata(_target, _sender, _data, _nonce); + return + abi.encodeWithSignature( + "relayMessage(address,address,bytes,uint256)", + _target, + _sender, + _data, + _nonce + ); } /** - * @notice Compute the V1 cross domain serialization + * @notice Encodes a cross domain message based on the V1 (current) encoding. + * + * @param _nonce Message nonce. + * @param _sender Address of the sender of the message. + * @param _target Address of the target of the message. + * @param _value ETH value to send to the target. + * @param _gasLimit Gas limit to use for the message. + * @param _data Data to send with the message. + * + * @return Encoded cross domain message. */ - function getEncodingV1( + function encodeCrossDomainMessageV1( uint256 _nonce, address _sender, address _target, @@ -130,24 +138,36 @@ library Encoding { } /** - * @notice Adds the version to the nonce + * @notice Adds a version number into the first two bytes of a message nonce. + * + * @param _nonce Message nonce to encode into. + * @param _version Version number to encode into the message nonce. + * + * @return Message nonce with version encoded into the first two bytes. */ - function addVersionToNonce(uint256 _nonce, uint16 _version) - internal - pure - returns (uint256 nonce) - { + function encodeVersionedNonce(uint240 _nonce, uint16 _version) internal pure returns (uint256) { + uint256 nonce; assembly { nonce := or(shl(240, _version), _nonce) } + return nonce; } /** - * @notice Gets the version out of the nonce + * @notice Pulls the version out of a version-encoded nonce. + * + * @param _nonce Message nonce with version encoded into the first two bytes. + * + * @return Nonce without encoded version. + * @return Version of the message. */ - function getVersionFromNonce(uint256 _nonce) internal pure returns (uint16 version) { + function decodeVersionedNonce(uint256 _nonce) internal pure returns (uint240, uint16) { + uint240 nonce; + uint16 version; assembly { + nonce := and(_nonce, 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) version := shr(240, _nonce) } + return (nonce, version); } } diff --git a/packages/contracts-bedrock/contracts/libraries/Hashing.sol b/packages/contracts-bedrock/contracts/libraries/Hashing.sol index 38234a7267585..dfc51d1751083 100644 --- a/packages/contracts-bedrock/contracts/libraries/Hashing.sol +++ b/packages/contracts-bedrock/contracts/libraries/Hashing.sol @@ -8,7 +8,10 @@ import { Encoding } from "./Encoding.sol"; * @notice Hashing handles Optimism's various different hashing schemes. */ library Hashing { - /// @notice A struct containing the elements hashed together to generate the output root. + /** + * @notice Struct representing the elements that are hashed together to generate an output root + * which itself represents a snapshot of the L2 state. + */ struct OutputRootProof { bytes32 version; bytes32 stateRoot; @@ -17,66 +20,81 @@ library Hashing { } /** - * @notice Compute the L2 transaction hash given - * data about an L1 deposit transaction. This is useful for - * environments that do not have access to arbitrary - * RLP encoding functionality but have access to the - * standard web3 API - * TODO: rearrange args in a sane way - * @param _l1BlockHash The L1 block hash corresponding to the block - * the deposit was included in - * @param _logIndex The log index of the event that the deposit was - * created from. This can be found on the transaction receipt - * @param _from The sender of the deposit - * @param _to The L2 contract to be called by the deposit transaction - * @param _isCreate Indicates if the deposit creates a contract - * @param _mint The amount of ETH being minted by the transaction - * @param _value The amount of ETH send in the L2 call - * @param _gas The gas limit for the L2 call + * @notice Computes the hash of the RLP encoded L2 transaction that would be generated when a + * given deposit is sent to the L2 system. Useful for searching for a deposit in the L2 + * system. + * + * @param _from Address of the sender of the deposit. + * @param _to Address of the receiver of the deposit. + * @param _value ETH value to send to the receiver. + * @param _mint ETH value to mint on L2. + * @param _gasLimit Gas limit to use for the transaction. + * @param _isCreation Whether or not the transaction is a contract creation. + * @param _data Data to send with the transaction. + * @param _l1BlockHash Hash of the L1 block where the deposit was included. + * @param _logIndex Index of the deposit event in the L1 block. + * + * @return Hash of the RLP encoded L2 deposit transaction. */ - function L2TransactionHash( - bytes32 _l1BlockHash, - uint256 _logIndex, + function hashDepositTransaction( address _from, address _to, - bool _isCreate, - uint256 _mint, uint256 _value, - uint256 _gas, - bytes memory _data + uint256 _mint, + uint64 _gasLimit, + bool _isCreation, + bytes memory _data, + bytes32 _l1BlockHash, + uint256 _logIndex ) internal pure returns (bytes32) { - bytes memory raw = Encoding.L2Transaction( - _l1BlockHash, - _logIndex, + bytes memory raw = Encoding.encodeDepositTransaction( _from, _to, - _isCreate, - _mint, _value, - _gas, - _data + _mint, + _gasLimit, + _isCreation, + _data, + _l1BlockHash, + _logIndex ); return keccak256(raw); } /** - * @notice Compute the deposit transaction source hash. - * This value ensures that the L2 transaction hash is unique - * and deterministic based on L1 execution - * @param l1BlockHash The L1 blockhash corresponding to the block including - * the deposit - * @param logIndex The index of the log that created the deposit transaction + * @notice Computes the deposit transaction's "source hash", a value that guarantees the hash + * of the L2 transaction that corresponds to a deposit is unique and is + * deterministically generated from L1 transaction data. + * + * @param _l1BlockHash Hash of the L1 block where the deposit was included. + * @param _logIndex The index of the log that created the deposit transaction. + * + * @return Hash of the deposit transaction's "source hash". */ - function sourceHash(bytes32 l1BlockHash, uint256 logIndex) internal pure returns (bytes32) { - bytes32 depositId = keccak256(abi.encode(l1BlockHash, logIndex)); + function hashDepositSource(bytes32 _l1BlockHash, uint256 _logIndex) + internal + pure + returns (bytes32) + { + bytes32 depositId = keccak256(abi.encode(_l1BlockHash, _logIndex)); return keccak256(abi.encode(bytes32(0), depositId)); } /** - * @notice Compute the cross domain hash based on the versioned nonce + * @notice Hashes the cross domain message based on the version that is encoded into the + * message nonce. + * + * @param _nonce Message nonce with version encoded into the first two bytes. + * @param _sender Address of the sender of the message. + * @param _target Address of the target of the message. + * @param _value ETH value to send to the target. + * @param _gasLimit Gas limit to use for the message. + * @param _data Data to send with the message. + * + * @return Hashed cross domain message. */ - function getVersionedHash( + function hashCrossDomainMessage( uint256 _nonce, address _sender, address _target, @@ -84,32 +102,48 @@ library Hashing { uint256 _gasLimit, bytes memory _data ) internal pure returns (bytes32) { - uint16 version = Encoding.getVersionFromNonce(_nonce); + (, uint16 version) = Encoding.decodeVersionedNonce(_nonce); if (version == 0) { - return getHashV0(_target, _sender, _data, _nonce); + return hashCrossDomainMessageV0(_target, _sender, _data, _nonce); } else if (version == 1) { - return getHashV1(_nonce, _sender, _target, _value, _gasLimit, _data); + return hashCrossDomainMessageV1(_nonce, _sender, _target, _value, _gasLimit, _data); + } else { + revert("Hashing: unknown cross domain message version"); } - - revert("Unknown version."); } /** - * @notice Compute the legacy hash of a cross domain message + * @notice Hashes a cross domain message based on the V0 (legacy) encoding. + * + * @param _target Address of the target of the message. + * @param _sender Address of the sender of the message. + * @param _data Data to send with the message. + * @param _nonce Message nonce. + * + * @return Hashed cross domain message. */ - function getHashV0( + function hashCrossDomainMessageV0( address _target, address _sender, bytes memory _data, uint256 _nonce ) internal pure returns (bytes32) { - return keccak256(Encoding.getEncodingV0(_target, _sender, _data, _nonce)); + return keccak256(Encoding.encodeCrossDomainMessageV0(_target, _sender, _data, _nonce)); } /** - * @notice Compute the V1 hash of a cross domain message + * @notice Hashes a cross domain message based on the V1 (current) encoding. + * + * @param _nonce Message nonce. + * @param _sender Address of the sender of the message. + * @param _target Address of the target of the message. + * @param _value ETH value to send to the target. + * @param _gasLimit Gas limit to use for the message. + * @param _data Data to send with the message. + * + * @return Hashed cross domain message. */ - function getHashV1( + function hashCrossDomainMessageV1( uint256 _nonce, address _sender, address _target, @@ -118,7 +152,16 @@ library Hashing { bytes memory _data ) internal pure returns (bytes32) { return - keccak256(Encoding.getEncodingV1(_nonce, _sender, _target, _value, _gasLimit, _data)); + keccak256( + Encoding.encodeCrossDomainMessageV1( + _nonce, + _sender, + _target, + _value, + _gasLimit, + _data + ) + ); } /** @@ -130,7 +173,7 @@ library Hashing { * @param _gasLimit Gas to be forwarded to the target. * @param _data Data to send to the target. */ - function withdrawalHash( + function hashWithdrawal( uint256 _nonce, address _sender, address _target, @@ -142,11 +185,14 @@ library Hashing { } /** - * @notice Derives the output root corresponding to the elements provided in the proof. - * @param _outputRootProof The elements which were hashed together to generate the output root. - * @return Whether or not the output root matches the hashed output of the proof. + * @notice Hashes the various elements of an output root proof into an output root hash which + * can be used to check if the proof is valid. + * + * @param _outputRootProof Output root proof which should hash to an output root. + * + * @return Hashed output root proof. */ - function _deriveOutputRoot(OutputRootProof memory _outputRootProof) + function hashOutputRootProof(OutputRootProof memory _outputRootProof) internal pure returns (bytes32) diff --git a/packages/contracts-bedrock/contracts/test/Encoding.t.sol b/packages/contracts-bedrock/contracts/test/Encoding.t.sol index 9b71fb76eae25..1ffabd55793c9 100644 --- a/packages/contracts-bedrock/contracts/test/Encoding.t.sol +++ b/packages/contracts-bedrock/contracts/test/Encoding.t.sol @@ -6,8 +6,29 @@ import { Encoding } from "../libraries/Encoding.sol"; contract Encoding_Test is CommonTest { function test_nonceVersioning(uint240 _nonce, uint16 _version) external { - uint256 nonce = Encoding.addVersionToNonce(uint256(_nonce), _version); - uint16 version = Encoding.getVersionFromNonce(nonce); + (uint240 nonce, uint16 version) = Encoding.decodeVersionedNonce( + Encoding.encodeVersionedNonce(_nonce, _version) + ); assertEq(version, _version); + assertEq(nonce, _nonce); + } + + function test_encodeDepositTransaction() external { + bytes memory raw = Encoding.encodeDepositTransaction( + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, + 0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244, + 0xde0b6b3a7640000, + 0xe043da617250000, + 0x2dc6c0, + false, + hex"", + 0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959, + 0x1 + ); + + assertEq( + raw, + hex"7e00f862a0f923fb07134d7d287cb52c770cc619e17e82606c21a875c92f4c63b65280a5cc94f39fd6e51aad88f6f4ce6ab8827279cfffb9226694b79f76ef2c5f0286176833e7b2eee103b1cc3244880e043da617250000880de0b6b3a7640000832dc6c080" + ); } } diff --git a/packages/contracts-bedrock/contracts/test/Hashing.t.sol b/packages/contracts-bedrock/contracts/test/Hashing.t.sol index dfcbd0e9fb7df..6e3460b12a95d 100644 --- a/packages/contracts-bedrock/contracts/test/Hashing.t.sol +++ b/packages/contracts-bedrock/contracts/test/Hashing.t.sol @@ -8,54 +8,29 @@ import { Encoding } from "../libraries/Encoding.sol"; contract Hashing_Test is CommonTest { // TODO(tynes): turn this into differential fuzzing // it is very easy to do so with the typescript - function test_l2TransactionHash() external { - bytes32 l1BlockHash = 0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959; - uint256 logIndex = 0x1; - address from = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; - address to = 0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244; - bool isCreate = false; - uint256 mint = 0xe043da617250000; - uint256 value = 0xde0b6b3a7640000; - uint256 gas = 0x2dc6c0; - bytes memory data = hex""; - - bytes32 sourceHash = Hashing.sourceHash( - l1BlockHash, - logIndex + function test_hashDepositSource() external { + bytes32 sourceHash = Hashing.hashDepositSource( + 0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959, + 0x1 ); assertEq( sourceHash, 0xf923fb07134d7d287cb52c770cc619e17e82606c21a875c92f4c63b65280a5cc ); + } - bytes memory raw = Encoding.L2Transaction( - l1BlockHash, - logIndex, - from, - to, - isCreate, - mint, - value, - gas, - data - ); - - assertEq( - raw, - hex"7e00f862a0f923fb07134d7d287cb52c770cc619e17e82606c21a875c92f4c63b65280a5cc94f39fd6e51aad88f6f4ce6ab8827279cfffb9226694b79f76ef2c5f0286176833e7b2eee103b1cc3244880e043da617250000880de0b6b3a7640000832dc6c080" - ); - - bytes32 digest = Hashing.L2TransactionHash( - l1BlockHash, - logIndex, - from, - to, - isCreate, - mint, - value, - gas, - data + function test_hashDepositTransaction() external { + bytes32 digest = Hashing.hashDepositTransaction( + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, + 0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244, + 0xde0b6b3a7640000, + 0xe043da617250000, + 0x2dc6c0, + false, + hex"", + 0xd25df7858efc1778118fb133ac561b138845361626dfb976699c5287ed0f4959, + 0x1 ); assertEq( diff --git a/packages/contracts-bedrock/contracts/test/L1CrossDomainMessenger.t.sol b/packages/contracts-bedrock/contracts/test/L1CrossDomainMessenger.t.sol index 9f746386edf10..fc404de3472a6 100644 --- a/packages/contracts-bedrock/contracts/test/L1CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/contracts/test/L1CrossDomainMessenger.t.sol @@ -56,8 +56,9 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { // the version is encoded in the nonce function test_L1MessengerMessageVersion() external { + (,uint16 version) = Encoding.decodeVersionedNonce(L1Messenger.messageNonce()); assertEq( - Encoding.getVersionFromNonce(L1Messenger.messageNonce()), + version, L1Messenger.MESSAGE_VERSION() ); } @@ -75,7 +76,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { 0, 100 + L1Messenger.baseGas(hex"ff"), false, - Encoding.getVersionedEncoding( + Encoding.encodeCrossDomainMessage( L1Messenger.messageNonce(), alice, recipient, @@ -95,7 +96,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { 0, 100 + L1Messenger.baseGas(hex"ff"), false, - Encoding.getVersionedEncoding( + Encoding.encodeCrossDomainMessage( L1Messenger.messageNonce(), alice, recipient, @@ -145,7 +146,7 @@ contract L1CrossDomainMessenger_Test is Messenger_Initializer { vm.expectEmit(true, true, true, true); - bytes32 hash = Hashing.getVersionedHash(0, sender, target, 0, 0, hex"1111"); + bytes32 hash = Hashing.hashCrossDomainMessage(0, sender, target, 0, 0, hex"1111"); emit RelayedMessage(hash); diff --git a/packages/contracts-bedrock/contracts/test/L2CrossDomainMessenger.t.sol b/packages/contracts-bedrock/contracts/test/L2CrossDomainMessenger.t.sol index f493df6d26bc7..3064792d6d601 100644 --- a/packages/contracts-bedrock/contracts/test/L2CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/contracts/test/L2CrossDomainMessenger.t.sol @@ -31,8 +31,9 @@ contract L2CrossDomainMessenger_Test is Messenger_Initializer { } function test_L2MessengerMessageVersion() external { + (, uint16 version) = Encoding.decodeVersionedNonce(L2Messenger.messageNonce()); assertEq( - Encoding.getVersionFromNonce(L2Messenger.messageNonce()), + version, L2Messenger.MESSAGE_VERSION() ); } @@ -44,7 +45,7 @@ contract L2CrossDomainMessenger_Test is Messenger_Initializer { L2ToL1MessagePasser.initiateWithdrawal.selector, address(L1Messenger), 100 + L2Messenger.baseGas(hex"ff"), - Encoding.getVersionedEncoding( + Encoding.encodeCrossDomainMessage( L2Messenger.messageNonce(), alice, recipient, @@ -63,7 +64,7 @@ contract L2CrossDomainMessenger_Test is Messenger_Initializer { address(L1Messenger), 0, 100 + L2Messenger.baseGas(hex"ff"), - Encoding.getVersionedEncoding( + Encoding.encodeCrossDomainMessage( L2Messenger.messageNonce(), alice, recipient, @@ -104,7 +105,7 @@ contract L2CrossDomainMessenger_Test is Messenger_Initializer { vm.expectEmit(true, true, true, true); - bytes32 hash = Hashing.getVersionedHash( + bytes32 hash = Hashing.hashCrossDomainMessage( 0, sender, target, diff --git a/packages/contracts-bedrock/contracts/test/L2ToL1MessagePasser.t.sol b/packages/contracts-bedrock/contracts/test/L2ToL1MessagePasser.t.sol index 39d891189335c..f1147277e09b1 100644 --- a/packages/contracts-bedrock/contracts/test/L2ToL1MessagePasser.t.sol +++ b/packages/contracts-bedrock/contracts/test/L2ToL1MessagePasser.t.sol @@ -64,7 +64,7 @@ contract L2ToL1MessagePasserTest is CommonTest { data ); - bytes32 withdrawalHash = Hashing.withdrawalHash( + bytes32 withdrawalHash = Hashing.hashWithdrawal( nonce, alice, target, diff --git a/packages/contracts-bedrock/contracts/universal/CrossDomainMessenger.sol b/packages/contracts-bedrock/contracts/universal/CrossDomainMessenger.sol index 7c0aadb7705bc..911b792640dba 100644 --- a/packages/contracts-bedrock/contracts/universal/CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/contracts/universal/CrossDomainMessenger.sol @@ -111,7 +111,7 @@ abstract contract CrossDomainMessenger is * messageNonce getter which will insert the message version into the nonce to give you * the actual nonce to be used for the message. */ - uint256 internal msgNonce; + uint240 internal msgNonce; /** * @notice Address of the paired CrossDomainMessenger contract on the other chain. @@ -172,7 +172,7 @@ abstract contract CrossDomainMessenger is * @return Nonce of the next message to be sent, with added message version. */ function messageNonce() public view returns (uint256) { - return Encoding.addVersionToNonce(msgNonce, MESSAGE_VERSION); + return Encoding.encodeVersionedNonce(msgNonce, MESSAGE_VERSION); } /** @@ -250,7 +250,7 @@ abstract contract CrossDomainMessenger is uint256 _minGasLimit, bytes calldata _message ) external payable nonReentrant whenNotPaused { - bytes32 versionedHash = Hashing.getVersionedHash( + bytes32 versionedHash = Hashing.hashCrossDomainMessage( _nonce, _sender, _target,