diff --git a/src/IncentivizedMessageEscrow.sol b/src/IncentivizedMessageEscrow.sol index 913fb7d..f219cb9 100644 --- a/src/IncentivizedMessageEscrow.sol +++ b/src/IncentivizedMessageEscrow.sol @@ -52,10 +52,8 @@ abstract contract IncentivizedMessageEscrow is IIncentivizedMessageEscrow, Bytes //--- Storage ---// mapping(bytes32 => IncentiveDescription) _bounty; - /** @notice A hash of the emitted message and associated message context on receive - * that we can emit the same message to the same intended targets later. - */ - mapping(bytes32 => bytes32) _messageDelivered; + /** @notice A hash of the emitted message on receive such that we can emit a similar one. */ + mapping(bytes32 => mapping(bytes => mapping(bytes32 => bytes32))) _messageDelivered; // Maps applications to their escrow implementations. mapping(address => mapping(bytes32 => bytes)) public implementationAddress; @@ -170,8 +168,8 @@ abstract contract IncentivizedMessageEscrow is IIncentivizedMessageEscrow, Bytes * @notice Returns a hash of the ack unless there was no ack then it returns bytes32(uint256(1)); * If the message hasn't been delivered yet it still returns bytes32(0) */ - function messageDelivered(bytes32 messageIdentifier) external view returns(bytes32 hasMessageBeenExecuted) { - return _messageDelivered[messageIdentifier]; + function messageDelivered(bytes32 sourceIdentifier, bytes calldata sourceImplementationIdentifier, bytes32 messageIdentifier) external view returns(bytes32 hasMessageBeenExecuted) { + return _messageDelivered[sourceIdentifier][sourceImplementationIdentifier][messageIdentifier]; } /** @@ -398,9 +396,9 @@ abstract contract IncentivizedMessageEscrow is IIncentivizedMessageEscrow, Bytes // The 3 next lines act as a reentry guard, so this call doesn't have to be protected by reentry. // We will re-set _messageDelivered[messageIdentifier] again later as the hash of the ack, however, we need re-entry protection // so applications don't try to claim incentives multiple times. So, we set it now and change it later. - bytes32 messageState = _messageDelivered[messageIdentifier]; + bytes32 messageState = _messageDelivered[sourceIdentifier][sourceImplementationIdentifier][messageIdentifier]; if (messageState != bytes32(0)) revert MessageAlreadySpent(); - _messageDelivered[messageIdentifier] = bytes32(uint256(1)); + _messageDelivered[sourceIdentifier][sourceImplementationIdentifier][messageIdentifier] = bytes32(uint256(1)); // Prepare to deliver the message to application. // We need toApplication to check if the source implementation is valid @@ -437,11 +435,7 @@ abstract contract IncentivizedMessageEscrow is IIncentivizedMessageEscrow, Bytes ); // Store a hash of the acknowledgement so we can later retry a potentially invalid ack proof. - _messageDelivered[messageIdentifier] = keccak256(bytes.concat( - sourceIdentifier, - sourceImplementationIdentifier, - receiveAckWithContext - )); + _messageDelivered[sourceIdentifier][sourceImplementationIdentifier][messageIdentifier] = keccak256(receiveAckWithContext); // Message has been delivered and shouldn't be executed again. emit MessageDelivered(messageIdentifier); @@ -470,11 +464,7 @@ abstract contract IncentivizedMessageEscrow is IIncentivizedMessageEscrow, Bytes ); // Store a hash of the acknowledgement so we can later retry a potentially invalid ack proof. - _messageDelivered[messageIdentifier] = keccak256(bytes.concat( - sourceIdentifier, - sourceImplementationIdentifier, - receiveAckWithContext - )); + _messageDelivered[sourceIdentifier][sourceImplementationIdentifier][messageIdentifier] = keccak256(receiveAckWithContext); // Message has been delivered and shouldn't be executed again. emit MessageDelivered(messageIdentifier); @@ -521,11 +511,7 @@ abstract contract IncentivizedMessageEscrow is IIncentivizedMessageEscrow, Bytes ); // Store a hash of the acknowledgement so we can later retry a potentially invalid ack proof. - _messageDelivered[messageIdentifier] = keccak256(bytes.concat( - sourceIdentifier, - sourceImplementationIdentifier, - receiveAckWithContext - )); + _messageDelivered[sourceIdentifier][sourceImplementationIdentifier][messageIdentifier] = keccak256(receiveAckWithContext); // Why is the messageDelivered event emitted before _sendPacket? // Because it lets us pop messageIdentifier from the stack. This avoid a stack limit reached error. @@ -938,7 +924,7 @@ abstract contract IncentivizedMessageEscrow is IIncentivizedMessageEscrow, Bytes // This makes it ever so slighly easier to retry messages. bytes32 messageIdentifier = bytes32(receiveAckWithContext[MESSAGE_IDENTIFIER_START:MESSAGE_IDENTIFIER_END]); - bytes32 storedAckHash = _messageDelivered[messageIdentifier]; + bytes32 storedAckHash = _messageDelivered[sourceIdentifier][implementationIdentifier][messageIdentifier]; // First, check if there is actually an appropiate hash at the message identifier. // Then, check if the storedAckHash & the source target (sourceIdentifier & implementationIdentifier) matches the executed one. if (storedAckHash == bytes32(0) || storedAckHash != keccak256(bytes.concat( @@ -998,7 +984,7 @@ abstract contract IncentivizedMessageEscrow is IIncentivizedMessageEscrow, Bytes // Get the message identifier from the message. bytes32 messageIdentifier = bytes32(message[MESSAGE_IDENTIFIER_START:MESSAGE_IDENTIFIER_END]); // Read the status of the package at MessageIdentifier. - bytes32 storedAckHash = _messageDelivered[messageIdentifier]; + bytes32 storedAckHash = _messageDelivered[sourceIdentifier][implementationIdentifier][messageIdentifier]; // If has already been processed, then don't allow timeouting the message. Instead, it should be retried. if (storedAckHash != bytes32(0)) revert MessageAlreadyProcessed(); // This also protects a relayer that delivered a timedout message. diff --git a/src/interfaces/IIncentivizedMessageEscrow.sol b/src/interfaces/IIncentivizedMessageEscrow.sol index 035c162..0580ad9 100644 --- a/src/interfaces/IIncentivizedMessageEscrow.sol +++ b/src/interfaces/IIncentivizedMessageEscrow.sol @@ -10,7 +10,7 @@ import { IMessageEscrowEvents } from "./IMessageEscrowEvents.sol"; interface IIncentivizedMessageEscrow is IMessageEscrowStructs, IMessageEscrowErrors, IMessageEscrowEvents { function bounty(bytes32 messageIdentifier) external view returns(IncentiveDescription memory incentive); - function messageDelivered(bytes32 messageIdentifier) external view returns(bytes32 hasMessageBeenExecuted); + function messageDelivered(bytes32 sourceIdentifier, bytes calldata sourceImplementationIdentifier, bytes32 messageIdentifier) external view returns(bytes32 hasMessageBeenExecuted); function increaseBounty( bytes32 messageIdentifier, diff --git a/test/IncentivizedMessageEscrow/ReemitAckMessage.t.sol b/test/IncentivizedMessageEscrow/ReemitAckMessage.t.sol index b258ded..24b1ab2 100644 --- a/test/IncentivizedMessageEscrow/ReemitAckMessage.t.sol +++ b/test/IncentivizedMessageEscrow/ReemitAckMessage.t.sol @@ -12,8 +12,6 @@ contract ReemitAckMessageTest is TestCommon { ); function test_reemit_ack(bytes calldata message) public { - bytes32 feeRecipient = bytes32(uint256(uint160(address(this)))); - bytes32 destinationFeeRecipient = bytes32(uint256(uint160(address(this)))); (, bytes memory messageWithContext) = setupForAck(address(application), message, destinationFeeRecipient); @@ -33,15 +31,10 @@ contract ReemitAckMessageTest is TestCommon { // This tests a relayer trying to reemit a message which is slightly changed. function test_reemit_ack_wrong_message(bytes calldata message) public { - bytes32 feeRecipient = bytes32(uint256(uint160(address(this)))); - bytes32 destinationFeeRecipient = bytes32(uint256(uint160(address(this)))); (, bytes memory messageWithContext) = setupForAck(address(application), message, destinationFeeRecipient); - // Remove the context that setupForAck adds. - bytes memory rawMessage = this.memorySlice(messageWithContext, 96); - // Simulate a relayer changing the ack from the application. We add a byte // but it could also be removing, flipping or similar. bytes memory newMessage = bytes.concat( diff --git a/test/IncentivizedMessageEscrow/TimeoutMessage.t.sol b/test/IncentivizedMessageEscrow/TimeoutMessage.t.sol index 7694cfb..4d21c7f 100644 --- a/test/IncentivizedMessageEscrow/TimeoutMessage.t.sol +++ b/test/IncentivizedMessageEscrow/TimeoutMessage.t.sol @@ -24,7 +24,7 @@ contract TimeoutMessageTest is TestCommon, Bytes65 { vm.expectEmit(); emit Message( _DESTINATION_IDENTIFIER, - abi.encodePacked(address(escrow)), + abi.encode(address(escrow)), bytes.concat( _DESTINATION_IDENTIFIER, _DESTINATION_IDENTIFIER, @@ -38,7 +38,7 @@ contract TimeoutMessageTest is TestCommon, Bytes65 { escrow.timeoutMessage( _DESTINATION_IDENTIFIER, - abi.encodePacked(address(escrow)), + abi.encode(address(escrow)), block.number, rawSubmitMessage ); @@ -107,7 +107,7 @@ contract TimeoutMessageTest is TestCommon, Bytes65 { function test_message_cannot_be_timeouted_after_exec(bytes calldata message) public { bytes32 destinationFeeRecipient = bytes32(uint256(uint160(address(this)))); - (, bytes memory submitMessageWithContext) = setupsubmitMessage(address(application), message); + (, bytes memory submitMessageWithContext) = setupsubmitMessage(address(application), message, 2); // Ready for ack. setupprocessPacket(submitMessageWithContext, destinationFeeRecipient); @@ -115,10 +115,12 @@ contract TimeoutMessageTest is TestCommon, Bytes65 { // Remove the context bytes memory rawSubmitMessage = this.memorySlice(submitMessageWithContext, 96); + vm.warp(3); + vm.expectRevert(abi.encodeWithSignature("MessageAlreadyProcessed()")); escrow.timeoutMessage( _DESTINATION_IDENTIFIER, - abi.encodePacked(address(escrow)), + abi.encode(address(escrow)), block.number, rawSubmitMessage ); @@ -144,7 +146,7 @@ contract TimeoutMessageTest is TestCommon, Bytes65 { vm.expectRevert(abi.encodeWithSignature("DeadlineNotPassed(uint64,uint64)", uint64(newTimestamp+1), uint64(newTimestamp))); escrow.timeoutMessage( _DESTINATION_IDENTIFIER, - abi.encodePacked(address(escrow)), + abi.encode(address(escrow)), block.number, newRawSubmitMessage ); @@ -167,7 +169,7 @@ contract TimeoutMessageTest is TestCommon, Bytes65 { vm.expectRevert(abi.encodeWithSignature("DeadlineNotPassed(uint64,uint64)", 0, newTimestamp)); escrow.timeoutMessage( _DESTINATION_IDENTIFIER, - abi.encodePacked(address(escrow)), + abi.encode(address(escrow)), block.number, newRawSubmitMessage ); diff --git a/test/IncentivizedMessageEscrow/processMessage/GasSpendControl.sol b/test/IncentivizedMessageEscrow/processMessage/GasSpendControl.sol index 6576b12..6252342 100644 --- a/test/IncentivizedMessageEscrow/processMessage/GasSpendControl.sol +++ b/test/IncentivizedMessageEscrow/processMessage/GasSpendControl.sol @@ -58,7 +58,7 @@ contract GasSpendControlTest is TestCommon { messageIdentifier, _DESTINATION_ADDRESS_APPLICATION, destinationFeeRecipient, - uint48(0x36718), // Gas used + uint48(0x3697d), // Gas used uint64(1), bytes1(0xff), // This states that the call went wrong. message diff --git a/test/IncentivizedMessageEscrow/processMessage/NoReceive.t.sol b/test/IncentivizedMessageEscrow/processMessage/NoReceive.t.sol index 7c8200a..e4bc4bb 100644 --- a/test/IncentivizedMessageEscrow/processMessage/NoReceive.t.sol +++ b/test/IncentivizedMessageEscrow/processMessage/NoReceive.t.sol @@ -54,7 +54,7 @@ contract processPacketNoReceiveTest is TestCommon { messageIdentifier, _DESTINATION_ADDRESS_THIS, feeRecipient, - uint48(0x80eb), // Gas used + uint48(0x8350), // Gas used uint64(1), abi.encodePacked(bytes1(0xff)), message diff --git a/test/IncentivizedMessageEscrow/processMessage/Reentry.call.t.sol b/test/IncentivizedMessageEscrow/processMessage/Reentry.call.t.sol index 8948bbc..b2c5edf 100644 --- a/test/IncentivizedMessageEscrow/processMessage/Reentry.call.t.sol +++ b/test/IncentivizedMessageEscrow/processMessage/Reentry.call.t.sol @@ -61,7 +61,7 @@ contract CallReentryTest is TestCommon, ICrossChainReceiver { messageIdentifier, _DESTINATION_ADDRESS_APPLICATION, feeRecipient, - uint48(0xf98f), // Gas used + uint48(0xfd07), // Gas used uint64(1), uint8(1) ) diff --git a/test/IncentivizedMessageEscrow/processMessage/_handleCall.t.sol b/test/IncentivizedMessageEscrow/processMessage/_handleCall.t.sol index b7d8f1d..28e0063 100644 --- a/test/IncentivizedMessageEscrow/processMessage/_handleCall.t.sol +++ b/test/IncentivizedMessageEscrow/processMessage/_handleCall.t.sol @@ -40,7 +40,7 @@ contract processPacketCallTest is TestCommon { messageIdentifier, _DESTINATION_ADDRESS_APPLICATION, feeRecipient, - uint48(0x7b19), // Gas used + uint48(0x7d66), // Gas used uint64(1), mockAck ) diff --git a/test/OnRecvIncentivizedMockEscrow/processMessage/_handleCall.t.sol b/test/OnRecvIncentivizedMockEscrow/processMessage/_handleCall.t.sol index c504d84..188ae07 100644 --- a/test/OnRecvIncentivizedMockEscrow/processMessage/_handleCall.t.sol +++ b/test/OnRecvIncentivizedMockEscrow/processMessage/_handleCall.t.sol @@ -45,7 +45,7 @@ contract OnRecvCallTest is TestOnRecvCommon { messageIdentifier, _DESTINATION_ADDRESS_APPLICATION, feeRecipient, - uint48(0x6b4e), // Gas used + uint48(0x6d9b), // Gas used uint64(1), hex"d9b60178cfb2eb98b9ff9136532b6bd80eeae6a2c90a2f96470294981fcfb62b" )