Skip to content

Commit 4088a35

Browse files
committed
feat: unpredictable messageHash and data location considerations
1 parent 52f54bb commit 4088a35

File tree

3 files changed

+48
-15
lines changed

3 files changed

+48
-15
lines changed

contracts/src/bridge/FastBridgeReceiverOnEthereum.sol

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,17 @@ contract FastBridgeReceiverOnEthereum is SafeBridgeReceiverOnEthereum, IFastBrid
108108
emit ClaimChallenged(_ticketID, ticket.claim.messageHash, block.timestamp);
109109
}
110110

111-
function verifyAndRelay(uint256 _ticketID, bytes memory _messageData) external override {
111+
function verifyAndRelay(
112+
uint256 _ticketID,
113+
uint256 blockNumber,
114+
bytes calldata _messageData
115+
) external override {
112116
Ticket storage ticket = tickets[_ticketID];
113117
require(ticket.claim.bridger != address(0), "Claim does not exist");
114-
require(ticket.claim.messageHash == keccak256(abi.encode(_ticketID, _messageData)), "Invalid hash");
118+
require(
119+
ticket.claim.messageHash == keccak256(abi.encode(_ticketID, blockNumber, _messageData)),
120+
"Invalid hash"
121+
);
115122
require(ticket.claim.claimedAt + challengeDuration < block.timestamp, "Challenge period not over");
116123
require(ticket.challenge.challenger == address(0), "Claim is challenged");
117124
require(ticket.relayed == false, "Message already relayed");
@@ -121,14 +128,18 @@ contract FastBridgeReceiverOnEthereum is SafeBridgeReceiverOnEthereum, IFastBrid
121128
require(_relay(_messageData), "Failed to call contract"); // Checks-Effects-Interaction
122129
}
123130

124-
function verifyAndRelaySafe(uint256 _ticketID, bytes memory _messageData) external override {
131+
function verifyAndRelaySafe(
132+
uint256 _ticketID,
133+
uint256 blockNumber,
134+
bytes calldata _messageData
135+
) external override {
125136
require(isSentBySafeBridge(), "Access not allowed: SafeBridgeSender only.");
126137

127138
Ticket storage ticket = tickets[_ticketID];
128139
require(ticket.relayed == false, "Message already relayed");
129140

130141
// Claim assessment if any
131-
bytes32 messageHash = keccak256(abi.encode(_ticketID, _messageData));
142+
bytes32 messageHash = keccak256(abi.encode(_ticketID, blockNumber, _messageData));
132143
if (ticket.claim.bridger != address(0) && ticket.claim.messageHash == messageHash) {
133144
ticket.claim.verified = true;
134145
}
@@ -196,7 +207,7 @@ contract FastBridgeReceiverOnEthereum is SafeBridgeReceiverOnEthereum, IFastBrid
196207
// * Internal * //
197208
// ************************ //
198209

199-
function _relay(bytes memory _messageData) internal returns (bool success) {
210+
function _relay(bytes calldata _messageData) internal returns (bool success) {
200211
// Decode the receiver address from the data encoded by the IFastBridgeSender
201212
(address receiver, bytes memory data) = abi.decode(_messageData, (address, bytes));
202213
(success, ) = address(receiver).call(data);

contracts/src/bridge/FastBridgeSenderToEthereum.sol

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
2525

2626
struct Ticket {
2727
bytes32 messageHash;
28+
uint256 blockNumber;
2829
bool sentSafe;
2930
}
3031

@@ -46,7 +47,13 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
4647
* The bridgers need to watch for these events and
4748
* relay the messageHash on the FastBridgeReceiverOnEthereum.
4849
*/
49-
event OutgoingMessage(uint256 indexed ticketID, address indexed target, bytes32 indexed messageHash, bytes message);
50+
event OutgoingMessage(
51+
uint256 indexed ticketID,
52+
uint256 blockNumber,
53+
address target,
54+
bytes32 indexed messageHash,
55+
bytes message
56+
);
5057

5158
// ************************************* //
5259
// * Function Modifiers * //
@@ -80,9 +87,9 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
8087
ticketID = currentTicketID++;
8188

8289
(bytes32 messageHash, bytes memory messageData) = _encode(ticketID, _receiver, _calldata);
83-
emit OutgoingMessage(ticketID, _receiver, messageHash, messageData);
90+
emit OutgoingMessage(ticketID, block.number, _receiver, messageHash, messageData);
8491

85-
tickets[ticketID] = Ticket({messageHash: messageHash, sentSafe: false});
92+
tickets[ticketID] = Ticket({messageHash: messageHash, blockNumber: block.number, sentSafe: false});
8693
}
8794

8895
/**
@@ -94,6 +101,8 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
94101
* It may require some ETH (or whichever native token) to pay for the bridging cost,
95102
* depending on the underlying safe bridge.
96103
*
104+
* TODO: check if keeping _calldata in storage in sendFast() is cheaper than passing it again as a parameter here
105+
*
97106
* @param _ticketID The ticketID as provided by `sendFast()` if any.
98107
* @param _receiver The L1 contract address who will receive the calldata
99108
* @param _calldata The receiving domain encoded message data.
@@ -112,7 +121,12 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
112121

113122
// Safe Bridge message envelope
114123
bytes4 methodSelector = IFastBridgeReceiver.verifyAndRelaySafe.selector;
115-
bytes memory safeMessageData = abi.encodeWithSelector(methodSelector, _ticketID, messageData);
124+
bytes memory safeMessageData = abi.encodeWithSelector(
125+
methodSelector,
126+
_ticketID,
127+
ticket.blockNumber,
128+
messageData
129+
);
116130

117131
// TODO: how much ETH should be provided for bridging? add an ISafeBridgeSender.bridgingCost() if needed
118132
_sendSafe(address(fastBridgeReceiver), safeMessageData);
@@ -135,11 +149,11 @@ contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSe
135149
uint256 _ticketID,
136150
address _receiver,
137151
bytes memory _calldata
138-
) internal pure returns (bytes32 messageHash, bytes memory messageData) {
152+
) internal view returns (bytes32 messageHash, bytes memory messageData) {
139153
// Encode the receiver address with the function signature + arguments i.e calldata
140154
messageData = abi.encode(_receiver, _calldata);
141155

142-
// Compute the hash over the message header (ticketID) and body (data).
143-
messageHash = keccak256(abi.encode(_ticketID, messageData));
156+
// Compute the hash over the message header (ticketID, blockNumber) and body (data).
157+
messageHash = keccak256(abi.encode(_ticketID, block.number, messageData));
144158
}
145159
}

contracts/src/bridge/interfaces/IFastBridgeReceiver.sol

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,17 @@ interface IFastBridgeReceiver {
77

88
function challenge(uint256 _ticketID) external payable;
99

10-
function verifyAndRelay(uint256 _ticketID, bytes memory _messageData) external;
11-
12-
function verifyAndRelaySafe(uint256 _ticketID, bytes memory _messageData) external;
10+
function verifyAndRelay(
11+
uint256 _ticketID,
12+
uint256 blockNumber,
13+
bytes calldata _messageData
14+
) external;
15+
16+
function verifyAndRelaySafe(
17+
uint256 _ticketID,
18+
uint256 blockNumber,
19+
bytes calldata _messageData
20+
) external;
1321

1422
function withdrawClaimDeposit(uint256 _ticketID) external;
1523

0 commit comments

Comments
 (0)