Commit 28bd76ae authored by smartcontracts's avatar smartcontracts Committed by GitHub

style(ctb): clean up hashing and encoding libs (#2983)

* style(ctb): clean up hashing and encoding libs

Cleans up Hashing and Encoding libraries. Updates natspec and cleans up
function names.

* contracts-bedrock: cover nonce decoding

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