Skip to content
This repository was archived by the owner on Jun 24, 2025. It is now read-only.

Commit 074c2ad

Browse files
authored
Fix message (#46)
1 parent b8b5d47 commit 074c2ad

File tree

9 files changed

+116
-198
lines changed

9 files changed

+116
-198
lines changed

src/Gateway.sol

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ abstract contract GatewayEIP712 {
5050
contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
5151
using PrimitiveUtils for UpdateKeysMessage;
5252
using PrimitiveUtils for GmpMessage;
53+
using PrimitiveUtils for GmpCallback;
5354
using PrimitiveUtils for address;
5455
using BranchlessMath for uint256;
5556
using UFloatMath for UFloat9x56;
@@ -202,7 +203,7 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
202203
// Convert the `GmpMessage` into `GmpCallback`, which is a more efficient representation.
203204
// see `src/Primitives.sol` for more details.
204205
GmpCallback memory callback = gmp.intoCallback();
205-
operationHash = callback.eip712hash;
206+
operationHash = callback.opHash;
206207
_execute(callback);
207208
}
208209

@@ -371,7 +372,8 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
371372

372373
function _execute(GmpCallback memory callback) private returns (GmpStatus, bytes32) {
373374
// Verify if this GMP message was already executed
374-
GmpInfo storage gmp = _messages[callback.eip712hash];
375+
bytes32 msgId = callback.messageId();
376+
GmpInfo storage gmp = _messages[msgId];
375377
require(gmp.status == GmpStatus.NOT_FOUND, "message already executed");
376378

377379
// Update status to `pending` to prevent reentrancy attacks.
@@ -425,7 +427,7 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
425427
gmp.status = status;
426428

427429
// Emit event
428-
emit GmpExecuted(callback.eip712hash, callback.source, callback.dest, status, result);
430+
emit GmpExecuted(msgId, callback.source, callback.dest, status, result);
429431

430432
return (status, result);
431433
}
@@ -464,7 +466,7 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
464466
GmpCallback memory callback = message.intoCallback();
465467

466468
// Verify the TSS Schnorr Signature
467-
_verifySignature(signature, callback.eip712hash);
469+
_verifySignature(signature, callback.opHash);
468470

469471
// Execute GMP message
470472
(status, result) = _execute(callback);
@@ -521,7 +523,7 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
521523

522524
// Emit `GmpCreated` event without copy the data, to simplify the gas estimation.
523525
_emitGmpCreated(
524-
message.eip712hash(),
526+
message.messageId(),
525527
source,
526528
destinationAddress,
527529
routeId,

src/Primitives.sol

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ enum GmpStatus {
165165
* @param callback encoded callback of `IGmpRecipient` interface, see `IGateway.sol` for more details.
166166
*/
167167
struct GmpCallback {
168-
bytes32 eip712hash;
168+
bytes32 opHash;
169169
GmpSender source;
170170
uint16 srcNetwork;
171171
address dest;
@@ -221,26 +221,35 @@ library PrimitiveUtils {
221221
);
222222
}
223223

224-
function eip712hash(GmpMessage memory message) internal pure returns (bytes32 id) {
225-
bytes memory data = message.data;
224+
function messageId(GmpMessage memory message) internal pure returns (bytes32 id) {
226225
assembly ("memory-safe") {
227-
// keccak256(message.data)
228-
id := keccak256(add(data, 32), mload(data))
226+
// now compute the GmpMessage Type Hash without memory copying
227+
let offset1 := sub(message, 32)
228+
let backup1 := mload(offset1)
229229

230+
mstore(offset1, GMP_VERSION)
231+
id := keccak256(offset1, 0xe0)
232+
mstore(offset1, backup1)
233+
}
234+
}
235+
236+
function opHash(GmpMessage memory message) internal pure returns (bytes32 id) {
237+
bytes32 dataHash = keccak256(message.data);
238+
assembly ("memory-safe") {
230239
// now compute the GmpMessage Type Hash without memory copying
231-
let offset := sub(message, 32)
232-
let backup := mload(offset)
233-
{
234-
mstore(offset, GMP_VERSION)
235-
{
236-
let offset2 := add(offset, 0xe0)
237-
let backup2 := mload(offset2)
238-
mstore(offset2, id)
239-
id := keccak256(offset, 0x100)
240-
mstore(offset2, backup2)
241-
}
242-
}
243-
mstore(offset, backup)
240+
let offset1 := sub(message, 32)
241+
let backup1 := mload(offset1)
242+
let backup2 := mload(message)
243+
244+
mstore(offset1, GMP_VERSION)
245+
id := keccak256(offset1, 0xe0)
246+
247+
mstore(offset1, id)
248+
mstore(message, dataHash)
249+
id := keccak256(offset1, 64)
250+
251+
mstore(offset1, backup1)
252+
mstore(message, backup2)
244253
}
245254
}
246255

@@ -279,26 +288,37 @@ library PrimitiveUtils {
279288
*/
280289
function _computeMessageID(GmpCallback memory callback) private pure {
281290
bytes memory onGmpReceived = callback.callback;
282-
bytes32 dataHash;
291+
callback.opHash = bytes32(GMP_VERSION);
292+
293+
bytes32 msgId;
283294
assembly ("memory-safe") {
284-
let offset := add(onGmpReceived, 0xc4)
285-
dataHash := keccak256(add(offset, 0x20), mload(offset))
295+
// Compute `keccak256(abi.encode(GMP_VERSION, message.source, ...))`
296+
msgId := keccak256(callback, 0x00e0)
297+
// Replace the `id` in `onGmpReceived(uint256 id,...)` in the callback.
298+
mstore(add(onGmpReceived, 0x24), msgId)
286299
}
287-
callback.eip712hash = bytes32(GMP_VERSION);
288-
assembly ("memory-safe") {
289-
// temporarily store the result at `0x00e0..0x0100`, which is the `GmpCallback.callback.offset` field.
290-
mstore(add(callback, 0xe0), dataHash)
291300

292-
// Compute `keccak256(abi.encode(GMP_VERSION, message.source, ..., keccak256(message.data)))`
293-
dataHash := keccak256(callback, 0x0100)
301+
bytes memory data;
302+
assembly ("memory-safe") {
303+
data := add(onGmpReceived, 0xc4)
304+
}
305+
bytes32 dataHash = keccak256(data);
294306

295-
// Replace the `eip712hash` by the `callback.data.offset`.
296-
mstore(add(callback, 0xe0), onGmpReceived)
307+
callback.opHash = msgId;
308+
GmpSender backup = callback.source;
309+
callback.source = GmpSender.wrap(dataHash);
310+
assembly ("memory-safe") {
311+
dataHash := keccak256(callback, 0x40)
312+
}
313+
callback.opHash = dataHash;
314+
callback.source = backup;
315+
}
297316

298-
// Replace the `id` in `onGmpReceived(uint256 id,...)` in the callback.
299-
mstore(add(onGmpReceived, 0x24), dataHash)
317+
function messageId(GmpCallback memory callback) internal pure returns (bytes32 msgId) {
318+
bytes memory onGmpReceived = callback.callback;
319+
assembly ("memory-safe") {
320+
msgId := mload(add(onGmpReceived, 0x24))
300321
}
301-
callback.eip712hash = dataHash;
302322
}
303323

304324
/**
@@ -319,7 +339,7 @@ library PrimitiveUtils {
319339
*/
320340
function _intoCallback(MessagePtr message, bool isCalldata, GmpCallback memory callback) private pure {
321341
// | MEMORY OFFSET | RESERVED FIELD |
322-
// | 0x0000..0x0020 <- GmpCallback.eip712hash
342+
// | 0x0000..0x0020 <- GmpCallback.opHash
323343
// | 0x0020..0x0040 <- GmpCallback.source
324344
// | 0x0040..0x0060 <- GmpCallback.srcNetwork
325345
// | 0x0060..0x0080 <- GmpCallback.dest
@@ -347,7 +367,7 @@ library PrimitiveUtils {
347367
bytes calldata data = m.data;
348368
callback.callback = abi.encodeWithSignature(
349369
"onGmpReceived(bytes32,uint128,bytes32,uint64,bytes)",
350-
callback.eip712hash,
370+
callback.opHash,
351371
callback.srcNetwork,
352372
callback.source,
353373
callback.nonce,
@@ -363,7 +383,7 @@ library PrimitiveUtils {
363383
callback.nonce = m.nonce;
364384
callback.callback = abi.encodeWithSignature(
365385
"onGmpReceived(bytes32,uint128,bytes32,uint64,bytes)",
366-
callback.eip712hash,
386+
callback.opHash,
367387
callback.srcNetwork,
368388
callback.source,
369389
callback.nonce,

src/interfaces/IExecutor.sol

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,4 @@ interface IExecutor {
8989
* @param message GMP message
9090
*/
9191
function batchExecute(Signature calldata signature, InboundMessage calldata message) external;
92-
93-
/**
94-
* Execute GMP message
95-
* @param signature Schnorr signature
96-
* @param message GMP message
97-
*/
98-
function execute(Signature calldata signature, GmpMessage calldata message)
99-
external
100-
returns (GmpStatus status, bytes32 result);
101-
102-
/**
103-
* Deposit funds to the gateway contract
104-
*/
105-
function deposit() external payable;
10692
}

src/utils/GasUtils.sol

Lines changed: 5 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ library GasUtils {
4343
/**
4444
* @dev Base cost of the `IExecutor.execute` method.
4545
*/
46-
uint256 internal constant EXECUTION_BASE_COST = EXECUTION_SELECTOR_OVERHEAD + 46960 + 38;
46+
uint256 internal constant EXECUTION_BASE_COST = EXECUTION_SELECTOR_OVERHEAD + 46960 + 144;
4747

4848
/**
4949
* @dev Base cost of the `IGateway.submitMessage` method.
5050
*/
51-
uint256 internal constant SUBMIT_BASE_COST = 24138;
51+
uint256 internal constant SUBMIT_BASE_COST = 24138 - 96;
5252

5353
/**
5454
* @dev Extra gas cost that any account `Contract or EOA` must pay when calling `IGateway.submitMessage` method.
@@ -136,9 +136,6 @@ library GasUtils {
136136
// CALLDATACOPY
137137
gasCost += words * 3;
138138

139-
// keccak256 (6 gas per word)
140-
gasCost += words * 6;
141-
142139
// emit GmpCreated() gas cost (8 gas per byte)
143140
gasCost += words << 8;
144141

@@ -242,112 +239,15 @@ library GasUtils {
242239
}
243240
}
244241

245-
function _debugExecutionGasCost(uint256 messageSize, uint256 gasUsed) internal pure returns (uint256) {
246-
unchecked {
247-
// Selector overhead
248-
// -- First GAS opcode
249-
uint256 baseCost = EXECUTION_SELECTOR_OVERHEAD - 9;
250-
uint256 memoryExpansion = 0x60;
251-
// -- First GAS opcode
252-
253-
// all opcodes until message.intoCallback()
254-
baseCost += 449;
255-
256-
// -- message.intoCallback() --
257-
baseCost += 438;
258-
memoryExpansion = 0x80 + 0x01c4;
259-
uint256 gas = 0;
260-
// CALLDATACOPY 3 + (3 * words) + memory_expansion
261-
baseCost += 3;
262-
gas = _toWord(messageSize) * 3;
263-
memoryExpansion += messageSize;
264-
memoryExpansion = memoryExpansion.align32();
265-
266-
// opcodes until keccak256
267-
baseCost += 31;
268-
269-
// keccak256 30 + 6 gas per word
270-
baseCost += 30;
271-
gas = gas.saturatingAdd(_toWord(messageSize) * 6);
272-
//
273-
baseCost += 424;
274-
// -- message.intoCallback() --
275-
276-
baseCost += 34;
277-
278-
// -- _verifySignature --
279-
baseCost += 7933;
280-
// -- _verifySignature --
281-
282-
baseCost += 18;
283-
284-
// _execute
285-
baseCost += 22551;
286-
baseCost += 2; // GAS
287-
288-
baseCost += 97;
289-
// ------ CALL ------
290-
291-
baseCost += 2600;
292-
gas = gas.saturatingAdd(gasUsed);
293-
memoryExpansion = (messageSize.align32() + 0x80 + 0x0120 + 164).align32();
294-
295-
// ------ CALL ------
296-
baseCost += 67;
297-
baseCost += 100; // SLOAD
298-
baseCost += 69;
299-
baseCost += 100; // SSTORE
300-
301-
// -- emit GmpExecuted --
302-
baseCost += 141;
303-
memoryExpansion += 0x20; // MSTORE
304-
baseCost += 24;
305-
memoryExpansion += 0x20; // MSTORE
306-
baseCost += 39;
307-
baseCost += 2387; // LOG4
308-
baseCost += 26;
309-
// -- emit GmpExecuted --
310-
// end _execute
311-
312-
baseCost += 34;
313-
314-
// GasUtils.txBaseCost()
315-
{
316-
baseCost += 64; // base cost
317-
318-
// chunk start cost
319-
baseCost += 66;
320-
321-
// Selector + Signature + GmpMessage
322-
uint256 words = messageSize.align32().saturatingAdd(388 + 31) >> 5;
323-
words = (words * 106) + (((words.saturatingSub(255) + 254) / 255) * 214);
324-
gas = gas.saturatingAdd(words);
325-
326-
baseCost += 171; // End countNonZeros
327-
baseCost += 70; // End txBaseCost
328-
}
329-
// end GasUtils.txBaseCost()
330-
331-
baseCost += 482;
332-
// ----- GAS -------
333-
334-
baseCost += 168; // GAS
335-
baseCost += 6800; // REFUND CALL
336-
baseCost += 184; // RETURN
337-
338-
gas = gas.saturatingAdd(baseCost);
339-
gas = gas.saturatingAdd(memoryExpansionGasCost(_toWord(memoryExpansion)));
340-
return gas;
341-
}
342-
}
343-
344242
function _executionGasCost(uint256 messageSize, uint256 gasUsed) internal pure returns (uint256) {
345243
// Safety: The operations below can't overflow because the message size can't be greater than 2**16
346244
unchecked {
245+
// cost of calldata copy
347246
uint256 gas = _toWord(messageSize) * 3;
247+
// cost of hashing the payload
348248
gas = gas.saturatingAdd(_toWord(messageSize) * 6);
349249
gas = gas.saturatingAdd(gasUsed);
350-
uint256 memoryExpansion = messageSize.align32() + 0x80 + 0x0120 + 164 + 0x40 + 32;
250+
uint256 memoryExpansion = messageSize.align32() + 676;
351251
{
352252
// Selector + Signature + GmpMessage
353253
uint256 words = messageSize.align32().saturatingAdd(388 + 31) >> 5;

test/Batching.t.sol

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
contract Batching is BaseTest {
3939
using PrimitiveUtils for UpdateKeysMessage;
4040
using PrimitiveUtils for GmpMessage;
41+
using PrimitiveUtils for GmpCallback;
4142
using PrimitiveUtils for GmpSender;
4243
using PrimitiveUtils for address;
4344
using BranchlessMath for uint256;
@@ -218,13 +219,13 @@ contract Batching is BaseTest {
218219

219220
function sign(SigningKey memory signer, GmpMessage memory gmp) private pure returns (Signature memory) {
220221
GmpCallback memory callback = gmp.memToCallback();
221-
(uint256 e, uint256 s) = signer.signPrehashed(callback.eip712hash, SIGNING_NONCE);
222+
(uint256 e, uint256 s) = signer.signPrehashed(callback.opHash, SIGNING_NONCE);
222223
return Signature({xCoord: signer.xCoord(), e: e, s: s});
223224
}
224225

225226
function computeGmpMessageID(GmpMessage calldata message) external pure returns (bytes32) {
226227
console.logBytes(msg.data);
227-
return message.intoCallback().eip712hash;
228+
return message.intoCallback().messageId();
228229
}
229230

230231
function sign(SigningKey memory signer, InboundMessage memory message)
@@ -249,7 +250,7 @@ contract Batching is BaseTest {
249250
assembly {
250251
gmp := add(params.offset, 0x20)
251252
}
252-
operationHash = gmp.intoCallback().eip712hash;
253+
operationHash = gmp.intoCallback().opHash;
253254
} else {
254255
TssKey calldata tssKey;
255256
assembly {

0 commit comments

Comments
 (0)