Skip to content

Commit

Permalink
feat: include chainId in yaho hashes
Browse files Browse the repository at this point in the history
  • Loading branch information
auryn-macmillan committed Mar 23, 2023
1 parent 195f097 commit 6a1bc03
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 34 deletions.
10 changes: 7 additions & 3 deletions contracts/MessageExecutor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ contract MessageExecutor {
}

function executeMessagesFromOracles(
uint256[] memory chainIds,
Message[] memory messages,
uint256[] memory messageIds,
address[] memory senders,
Expand All @@ -34,25 +35,28 @@ contract MessageExecutor {
uint256 id = messageIds[i];
if (executed[id]) revert AlreadyExecuted(address(this), id);

uint256 chainId = chainIds[i];
Message memory message = messages[i];
bytes32 reportedHash = hashi.getHash(message.toChainId, id, oracleAdapters);
bytes32 calculatedHash = calculateHash(id, yaho, senders[i], message);
bytes32 reportedHash = hashi.getHash(chainId, id, oracleAdapters);
bytes32 calculatedHash = calculateHash(chainId, id, yaho, senders[i], message);
if (reportedHash != calculatedHash) revert HashMismatch(address(this), id, reportedHash, calculatedHash);

(bool success, bytes memory returnData) = address(message.to).call(message.data);
if (!success) revert CallFailed(address(this), id);
returnDatas[i] = returnData;
executed[id] = true;
emit MessageIdExecuted(message.toChainId, bytes32(id));
}
return returnDatas;
}

function calculateHash(
uint256 chainId,
uint256 id,
address origin,
address sender,
Message memory message
) public pure returns (bytes32 calculatedHash) {
calculatedHash = keccak256(abi.encode(id, origin, sender, message));
calculatedHash = keccak256(abi.encode(chainId, id, origin, sender, message));
}
}
5 changes: 3 additions & 2 deletions contracts/Yaho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ contract Yaho is MessageDispatcher {
bytes32[] memory messageIds = new bytes32[](messages.length);
for (uint i = 0; i < messages.length; i++) {
uint256 id = count;
hashes[id] = calculateHash(id, address(this), msg.sender, messages[i]);
hashes[id] = calculateHash(block.chainid, id, address(this), msg.sender, messages[i]);
messageIds[i] = bytes32(id);
emit MessageDispatched(bytes32(id), msg.sender, messages[i].toChainId, messages[i].to, messages[i].data);
count++;
Expand Down Expand Up @@ -52,11 +52,12 @@ contract Yaho is MessageDispatcher {
}

function calculateHash(
uint256 chainId,
uint256 id,
address origin,
address sender,
Message memory message
) public pure returns (bytes32 calculatedHash) {
calculatedHash = keccak256(abi.encode(id, origin, sender, message));
calculatedHash = keccak256(abi.encode(chainId, id, origin, sender, message));
}
}
2 changes: 1 addition & 1 deletion contracts/test/MockMessageRealy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.17;
import "../interfaces/IMessageRelay.sol";

contract MockMessageRelay is IMessageRelay {
uint256 count;
uint256 public count;

function relayMessages(bytes32[] memory) external payable returns (bytes32 receipts) {
receipts = bytes32(count);
Expand Down
8 changes: 8 additions & 0 deletions contracts/test/PingPing.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;

contract PingPong {
function ping() public pure returns (string memory pong) {
pong = "pong";
}
}
133 changes: 106 additions & 27 deletions test/04_MessageExecutor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,6 @@ const ID_ONE = 1
const ID_TWO = 2
const YAHO_ADD = "0x00000000000000000000000000000000000004a1"

const MESSAGE_1 = {
to: "0x0000000000000000000000000000000000000001",
toChainId: 1,
data: 0x1111111111,
}
const MESSAGE_2 = {
to: "0x0000000000000000000000000000000000000002",
toChainId: 2,
data: 0x02,
}

const setup = async () => {
const [wallet] = await ethers.getSigners()
const Hashi = await ethers.getContractFactory("Hashi")
Expand All @@ -28,15 +17,27 @@ const setup = async () => {
const oracleAdapter = await OracleAdapter.deploy()
const Yaho = await ethers.getContractFactory("Yaho")
const yaho = await Yaho.deploy()
const PingPong = await ethers.getContractFactory("PingPong")
const pingPong = await PingPong.deploy()

const hash_one = await yaho.calculateHash(ID_ZERO, YAHO_ADD, wallet.address, MESSAGE_1)
const hash_two = await yaho.calculateHash(ID_ONE, YAHO_ADD, wallet.address, MESSAGE_2)
const message_1 = {
to: pingPong.address,
toChainId: 1,
data: pingPong.interface.getSighash("ping"),
}
const message_2 = {
to: "0x0000000000000000000000000000000000000002",
toChainId: 2,
data: 0x02,
}
const hash_one = await yaho.calculateHash(DOMAIN_ID, ID_ZERO, YAHO_ADD, wallet.address, message_1)
const hash_two = await yaho.calculateHash(DOMAIN_ID, ID_ONE, YAHO_ADD, wallet.address, message_2)
const failMessage = {
to: hashi.address,
toChainId: 1,
data: 0x1111111111,
}
const hash_fail = await yaho.calculateHash(ID_TWO, YAHO_ADD, wallet.address, failMessage)
const hash_fail = await yaho.calculateHash(DOMAIN_ID, ID_TWO, YAHO_ADD, wallet.address, failMessage)
await oracleAdapter.setHashes(DOMAIN_ID, [ID_ZERO, ID_ONE, ID_TWO], [hash_one, hash_two, hash_fail])

return {
Expand All @@ -49,6 +50,9 @@ const setup = async () => {
hash_two,
failMessage,
hash_fail,
pingPong,
message_1,
message_2,
}
}

Expand All @@ -72,19 +76,20 @@ describe("MessageExecutor", function () {

describe("calculateHash()", function () {
it("calculates correct hash of the given message", async function () {
const { messageExecutor, wallet, hash_one } = await setup()
const calculatedHash = await messageExecutor.calculateHash(0, YAHO_ADD, wallet.address, MESSAGE_1)
const { messageExecutor, wallet, hash_one, message_1 } = await setup()
const calculatedHash = await messageExecutor.calculateHash(DOMAIN_ID, 0, YAHO_ADD, wallet.address, message_1)
expect(calculatedHash).to.equal(hash_one)
})
})

describe("executeMessagesFromOracles()", function () {
it("reverts if messages, messageIds, or senders are unequal lengths", async function () {
const { messageExecutor, wallet, oracleAdapter } = await setup()
const { messageExecutor, wallet, oracleAdapter, message_1, message_2 } = await setup()

await expect(
messageExecutor.executeMessagesFromOracles(
[MESSAGE_1, MESSAGE_2],
[DOMAIN_ID, DOMAIN_ID],
[message_1, message_2],
[ID_ZERO],
[wallet.address, wallet.address],
[oracleAdapter.address],
Expand All @@ -94,7 +99,8 @@ describe("MessageExecutor", function () {
.withArgs(messageExecutor.address)
await expect(
messageExecutor.executeMessagesFromOracles(
[MESSAGE_1],
[DOMAIN_ID, DOMAIN_ID],
[message_1],
[ID_ZERO, ID_ONE],
[wallet.address, wallet.address],
[oracleAdapter.address],
Expand All @@ -104,7 +110,8 @@ describe("MessageExecutor", function () {
.withArgs(messageExecutor.address)
await expect(
messageExecutor.executeMessagesFromOracles(
[MESSAGE_1, MESSAGE_2],
[DOMAIN_ID, DOMAIN_ID],
[message_1, message_2],
[ID_ZERO, ID_ONE],
[wallet.address],
[oracleAdapter.address],
Expand All @@ -114,20 +121,92 @@ describe("MessageExecutor", function () {
.withArgs(messageExecutor.address)
})
it("reverts if reported hash does not match calculated hash", async function () {
const { messageExecutor, wallet, oracleAdapter } = await setup()
const { messageExecutor, wallet, oracleAdapter, message_1 } = await setup()
await expect(
messageExecutor.executeMessagesFromOracles([MESSAGE_1], [ID_ONE], [wallet.address], [oracleAdapter.address]),
messageExecutor.executeMessagesFromOracles(
[DOMAIN_ID],
[message_1],
[ID_ONE],
[wallet.address],
[oracleAdapter.address],
),
).to.be.revertedWithCustomError(messageExecutor, "HashMismatch")
})
it("reverts if call fails", async function () {
const { messageExecutor, wallet, oracleAdapter, failMessage } = await setup()
await expect(
messageExecutor.executeMessagesFromOracles([failMessage], [ID_TWO], [wallet.address], [oracleAdapter.address]),
messageExecutor.executeMessagesFromOracles(
[DOMAIN_ID],
[failMessage],
[ID_TWO],
[wallet.address],
[oracleAdapter.address],
),
).to.be.revertedWithCustomError(messageExecutor, "CallFailed")
})
it("executes messages")
it("emits MessageIDExecuted")
it("returns returnDatas from executedMessages")
it("reverts if transaction was already executed")
it("executes messages", async function () {
const { messageExecutor, wallet, oracleAdapter, message_1, message_2 } = await setup()

await expect(
messageExecutor.executeMessagesFromOracles(
[DOMAIN_ID, DOMAIN_ID],
[message_1, message_2],
[ID_ZERO],
[wallet.address, wallet.address],
[oracleAdapter.address],
),
)
})
it("reverts if transaction was already executed", async function () {
const { messageExecutor, wallet, oracleAdapter, message_1 } = await setup()

await expect(
messageExecutor.executeMessagesFromOracles(
[DOMAIN_ID],
[message_1],
[ID_ZERO],
[wallet.address],
[oracleAdapter.address],
),
)
await expect(
messageExecutor.executeMessagesFromOracles(
[DOMAIN_ID],
[message_1],
[ID_ZERO],
[wallet.address],
[oracleAdapter.address],
),
).to.be.revertedWithCustomError(messageExecutor, "AlreadyExecuted")
})
it("emits MessageIDExecuted", async function () {
const { messageExecutor, wallet, oracleAdapter, message_1 } = await setup()

await expect(
messageExecutor.executeMessagesFromOracles(
[DOMAIN_ID],
[message_1],
[ID_ZERO],
[wallet.address],
[oracleAdapter.address],
),
)
.to.emit(messageExecutor, "MessageIdExecuted")
.withArgs(DOMAIN_ID, "0x0000000000000000000000000000000000000000000000000000000000000000")
})
it("returns returnDatas[] from executedMessages", async function () {
const { messageExecutor, wallet, oracleAdapter, message_1 } = await setup()

const response = await messageExecutor.callStatic.executeMessagesFromOracles(
[DOMAIN_ID],
[message_1],
[ID_ZERO],
[wallet.address],
[oracleAdapter.address],
)
const output = await ethers.utils.defaultAbiCoder.decode(["string"], response[0])

expect(output[0]).to.equal("pong")
})
})
})
2 changes: 1 addition & 1 deletion test/adapters/02_OracleAdapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const emptyHexlify = (value: string) => {
return hex === "0x00" ? "0x" : hex
}

const blockRLP = (block: any) => {
const blockRLP = (block) => {
const values = [
block.parentHash,
block.sha3Uncles,
Expand Down

0 comments on commit 6a1bc03

Please sign in to comment.