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_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)
......@@ -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 |
|------------------------+--------------------------+------+--------+-------+----------------------------------------------------------------|
......
......@@ -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,
......
......@@ -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,
......
......@@ -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);
}
}
......@@ -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)
......
......@@ -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"
);
}
}
......@@ -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(
......
......@@ -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);
......
......@@ -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,
......
......@@ -64,7 +64,7 @@ contract L2ToL1MessagePasserTest is CommonTest {
data
);
bytes32 withdrawalHash = Hashing.withdrawalHash(
bytes32 withdrawalHash = Hashing.hashWithdrawal(
nonce,
alice,
target,
......
......@@ -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,
......
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