Skip to content

Commit

Permalink
Make nonce sequential
Browse files Browse the repository at this point in the history
  • Loading branch information
Lohann committed Dec 16, 2024
1 parent 29c406a commit e342d07
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 33 deletions.
44 changes: 17 additions & 27 deletions src/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
using RouteStore for RouteStore.NetworkInfo;
using NetworkIDHelpers for NetworkID;

/**
* @dev Non-zero value used to initialize the `prevMessageHash` storage
*/
bytes32 internal constant FIRST_MESSAGE_PLACEHOLDER = bytes32(uint256(2 ** 256 - 1));

/**
* @dev Selector of `GmpCreated` event.
* keccak256("GmpCreated(bytes32,bytes32,address,uint16,uint256,uint256,bytes)");
Expand All @@ -75,7 +70,7 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
mapping(bytes32 => GmpInfo) private _messages;

// Hash of the previous GMP message submitted.
bytes32 public prevMessageHash;
uint256 internal nonce;

// Replay protection mechanism, stores the hash of the executed messages
// messageHash => shardId
Expand All @@ -97,12 +92,12 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
// EIP-712 typed hash
function initialize(address proxyAdmin, TssKey[] calldata keys, Network[] calldata networks) external {
require(PROXY_ADDRESS == address(this) || msg.sender == FACTORY, "only proxy can be initialize");
require(prevMessageHash == 0, "already initialized");
require(nonce == 0, "already initialized");
ERC1967.setAdmin(proxyAdmin);

// Initialize the prevMessageHash with a non-zero value to avoid the first GMP to spent more gas,
// Initialize the `nonce` as one to avoid the first GMP to spent more gas,
// once initialize the storage cost 21k gas, while alter it cost just 2800 gas.
prevMessageHash = FIRST_MESSAGE_PLACEHOLDER;
nonce = 1;

// Register networks
RouteStore.getMainStorage().initialize(networks, NetworkID.wrap(NETWORK_ID));
Expand All @@ -115,6 +110,10 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
emit KeySetChanged(bytes32(0), revoked, keys);
}

function prevMessageHash() external view returns (uint256) {
return nonce;
}

function gmpInfo(bytes32 id) external view returns (GmpInfo memory) {
return _messages[id];
}
Expand Down Expand Up @@ -303,30 +302,21 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
GmpSender source = msg.sender.toSender(false);

// Salt is equal to the previous message id (EIP-712 hash), this allows us to establish a sequence and eaily query the message history.
bytes32 prevHash = prevMessageHash;

// if the messageHash is the first message, we use a zero salt
uint256 salt = BranchlessMath.ternary(prevHash == FIRST_MESSAGE_PLACEHOLDER, 0, uint256(prevHash));

// Create GMP message and update prevMessageHash
bytes memory payload;
{
GmpMessage memory message =
GmpMessage(source, NETWORK_ID, destinationAddress, routeId, executionGasLimit, salt, data);
prevHash = message.eip712hash();
prevMessageHash = prevHash;
payload = message.data;
}
uint256 nextNonce = nonce++;

// Create GMP message and update nonce
GmpMessage memory message =
GmpMessage(source, NETWORK_ID, destinationAddress, routeId, executionGasLimit, nextNonce, data);

// Emit `GmpCreated` event without copy the data, to simplify the gas estimation.
_emitGmpCreated(prevHash, source, destinationAddress, routeId, executionGasLimit, salt, payload);
_emitGmpCreated(message.eip712hash(), source, destinationAddress, routeId, executionGasLimit, nextNonce, message.data);
}

/**
* @dev Emit `GmpCreated` event without copy the data, to simplify the gas estimation.
*/
function _emitGmpCreated(
bytes32 prevHash,
bytes32 messageID,
GmpSender source,
address destinationAddress,
uint16 destinationNetwork,
Expand All @@ -348,8 +338,8 @@ contract Gateway is IGateway, IExecutor, IUpgradable, GatewayEIP712 {
mstore(add(ptr, 0x60), 0x80) // data offset
let size := and(add(mload(payload), 31), 0xffffffe0)
size := add(size, 160)
log4(ptr, size, GMP_CREATED_EVENT_SELECTOR, prevHash, source, destinationAddress)
mstore(0, prevHash)
log4(ptr, size, GMP_CREATED_EVENT_SELECTOR, messageID, source, destinationAddress)
mstore(0, messageID)
return(0, 32)
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/utils/GasUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ library GasUtils {
/**
* @dev Base cost of the `IGateway.submitMessage` method.
*/
uint256 internal constant SUBMIT_BASE_COST = 23449;
uint256 internal constant SUBMIT_BASE_COST = 23449 + 19;

/**
* @dev Compute the gas cost of memory expansion.
Expand Down
2 changes: 1 addition & 1 deletion test/Example.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ contract ExampleTest is Test {
dest: address(dstToken),
destNetwork: DEST_NETWORK_ID,
gasLimit: 100_000,
salt: 0,
salt: 1,
data: abi.encode(MockERC20.CrossChainTransfer({from: ALICE, to: BOB, amount: 100}))
});

Expand Down
8 changes: 4 additions & 4 deletions test/Gateway.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ contract GatewayBase is Test {
dest: address(bytes20(keccak256("dummy_address"))),
destNetwork: DEST_NETWORK_ID,
gasLimit: 0,
salt: 0,
salt: 1,
data: new bytes(messageSize)
});

Expand Down Expand Up @@ -631,13 +631,13 @@ contract GatewayBase is Test {
dest: address(receiver),
destNetwork: DEST_NETWORK_ID,
gasLimit: 100_000,
salt: 0,
salt: 1,
data: abi.encodePacked(uint256(100_000))
});
bytes32 id = gmp.eip712hash();

// Check the previous message hash
assertEq(gateway.prevMessageHash(), bytes32(uint256(2 ** 256 - 1)), "wrong previous message hash");
assertEq(gateway.prevMessageHash(), 1, "wrong previous message hash");

CallOptions memory ctx = CallOptions({
from: gmpSender.toAddress(),
Expand Down Expand Up @@ -675,7 +675,7 @@ contract GatewayBase is Test {
assertEq(ctx.executionCost, expectedCost, "unexpected execution gas cost in first call");

// Now the second GMP message should have the salt equals to previous gmp hash
gmp.salt = uint256(id);
gmp.salt += 1;
id = gmp.eip712hash();

// Expect event
Expand Down

0 comments on commit e342d07

Please sign in to comment.