Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: Convert error to Acknowledgements #115

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 27 additions & 12 deletions src/ICS26Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,29 @@ contract ICS26Router is IICS26Router, IICS26RouterErrors, Ownable, ReentrancyGua
}

bytes[] memory acks = new bytes[](1);
acks[0] = getIBCApp(payload.destPort).onRecvPacket(
bool recvSuccess = true;
try getIBCApp(payload.destPort).onRecvPacket(
IIBCAppCallbacks.OnRecvPacketCallback({
sourceChannel: msg_.packet.sourceChannel,
destinationChannel: msg_.packet.destChannel,
sequence: msg_.packet.sequence,
payload: payload,
relayer: _msgSender()
})
);
require(acks[0].length != 0, IBCAsyncAcknowledgementNotSupported());
) returns (bytes memory ack) {
require(ack.length != 0, IBCAsyncAcknowledgementNotSupported());

acks[0] = abi.encodePacked(
ack
);
} catch (bytes memory errorData) {
recvSuccess = false;
acks[0] = abi.encodePacked(
errorData
);
}

writeAcknowledgement(msg_.packet, acks);
writeAcknowledgement(msg_.packet, recvSuccess, acks);

emit RecvPacket(msg_.packet);
}
Expand All @@ -181,7 +192,7 @@ contract ICS26Router is IICS26Router, IICS26RouterErrors, Ownable, ReentrancyGua
ICS24Host.packetAcknowledgementCommitmentPathCalldata(msg_.packet.destChannel, msg_.packet.sequence);
bytes[] memory acks = new bytes[](1);
acks[0] = msg_.acknowledgement;
bytes32 commitmentBz = ICS24Host.packetAcknowledgementCommitmentBytes32(acks);
bytes32 commitmentBz = ICS24Host.packetAcknowledgementCommitmentBytes32(msg_.recvSuccess, acks);

// verify the packet acknowledgement
ILightClientMsgs.MsgMembership memory membershipMsg = ILightClientMsgs.MsgMembership({
Expand All @@ -203,7 +214,7 @@ contract ICS26Router is IICS26Router, IICS26RouterErrors, Ownable, ReentrancyGua
return noopOnCorrectReason(reason, IICS24HostErrors.IBCPacketCommitmentNotFound.selector);
}

getIBCApp(payload.sourcePort).onAcknowledgementPacket(
try getIBCApp(payload.sourcePort).onAcknowledgementPacket(
IIBCAppCallbacks.OnAcknowledgementPacketCallback({
sourceChannel: msg_.packet.sourceChannel,
destinationChannel: msg_.packet.destChannel,
Expand All @@ -212,7 +223,9 @@ contract ICS26Router is IICS26Router, IICS26RouterErrors, Ownable, ReentrancyGua
acknowledgement: msg_.acknowledgement,
relayer: _msgSender()
})
);
) {} catch {
// no-op
}

emit AckPacket(msg_.packet, msg_.acknowledgement);
}
Expand Down Expand Up @@ -256,25 +269,27 @@ contract ICS26Router is IICS26Router, IICS26RouterErrors, Ownable, ReentrancyGua
return noopOnCorrectReason(reason, IICS24HostErrors.IBCPacketCommitmentNotFound.selector);
}

getIBCApp(payload.sourcePort).onTimeoutPacket(
try getIBCApp(payload.sourcePort).onTimeoutPacket(
IIBCAppCallbacks.OnTimeoutPacketCallback({
sourceChannel: msg_.packet.sourceChannel,
destinationChannel: msg_.packet.destChannel,
sequence: msg_.packet.sequence,
payload: payload,
relayer: _msgSender()
})
);
) {} catch {
// no-op
}

emit TimeoutPacket(msg_.packet);
}

/// @notice Writes a packet acknowledgement and emits an event
/// @param packet The packet to acknowledge
/// @param acks The acknowledgement
function writeAcknowledgement(Packet calldata packet, bytes[] memory acks) private {
IBC_STORE.commitPacketAcknowledgement(packet, acks);
emit WriteAcknowledgement(packet, acks);
function writeAcknowledgement(Packet calldata packet, bool recvSuccess, bytes[] memory acks) private {
IBC_STORE.commitPacketAcknowledgement(packet, recvSuccess, acks);
emit WriteAcknowledgement(packet, recvSuccess, acks);
}

/// @notice No-op if the reason is correct, otherwise reverts with the same reason
Expand Down
3 changes: 2 additions & 1 deletion src/interfaces/IIBCStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ interface IIBCStore {

/// @notice Commits a packet acknowledgement
/// @param packet The packet to commit the acknowledgement for
/// @param recvSuccess The success of the receivePacket app callback
/// @param acks The list of acknowledgements (one for each payload) to commit
function commitPacketAcknowledgement(IICS26RouterMsgs.Packet memory packet, bytes[] memory acks) external;
function commitPacketAcknowledgement(IICS26RouterMsgs.Packet memory packet, bool recvSuccess, bytes[] memory acks) external;

// --------------------- Events --------------------- //

Expand Down
3 changes: 2 additions & 1 deletion src/interfaces/IICS26Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ interface IICS26Router is IICS26RouterMsgs {
event RecvPacket(Packet packet);
/// @notice Emitted when a packet acknowledgement is written
/// @param packet The packet that was acknowledged
/// @param recvSuccess The success of the receivePacket app callback
/// @param acknowledgements The list of acknowledgements data
event WriteAcknowledgement(Packet packet, bytes[] acknowledgements);
event WriteAcknowledgement(Packet packet, bool recvSuccess, bytes[] acknowledgements);
/// @notice Emitted when a packet is timed out
/// @param packet The packet that was timed out
event TimeoutPacket(Packet packet);
Expand Down
2 changes: 2 additions & 0 deletions src/msgs/IICS26RouterMsgs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ interface IICS26RouterMsgs {

/// @notice Message for acknowledging packets, submitted by relayer
/// @param packet The packet to be acknowledged
/// @param recvSuccess The success of receivePacket app callback
/// @param acknowledgement The acknowledgement
/// @param proofAcked The proof of the acknowledgement commitment
/// @param proofHeight The proof height
struct MsgAckPacket {
Packet packet;
bool recvSuccess;
bytes acknowledgement;
bytes proofAcked;
IICS02ClientMsgs.Height proofHeight;
Expand Down
4 changes: 2 additions & 2 deletions src/utils/IBCStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ contract IBCStore is IIBCStore, IICS24HostErrors, Ownable {
}

/// @inheritdoc IIBCStore
function commitPacketAcknowledgement(IICS26RouterMsgs.Packet memory packet, bytes[] memory acks) public onlyOwner {
function commitPacketAcknowledgement(IICS26RouterMsgs.Packet memory packet, bool recvSuccess, bytes[] memory acks) public onlyOwner {
bytes32 path = ICS24Host.packetAcknowledgementCommitmentKeyCalldata(packet.destChannel, packet.sequence);
require(
commitments[path] == 0,
Expand All @@ -83,7 +83,7 @@ contract IBCStore is IIBCStore, IICS24HostErrors, Ownable {
)
);

bytes32 commitment = ICS24Host.packetAcknowledgementCommitmentBytes32(acks);
bytes32 commitment = ICS24Host.packetAcknowledgementCommitmentBytes32(recvSuccess, acks);
emit AckCommitted(path, commitment);
commitments[path] = commitment;
}
Expand Down
4 changes: 2 additions & 2 deletions src/utils/ICS24Host.sol
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,13 @@ library ICS24Host {
/// @dev each payload get one ack each from their application, so this function accepts a list of acks
/// @param acks The list of acknowledgements to get the commitment for
/// @return The commitment bytes
function packetAcknowledgementCommitmentBytes32(bytes[] memory acks) internal pure returns (bytes32) {
function packetAcknowledgementCommitmentBytes32(bool recvSuccess, bytes[] memory acks) internal pure returns (bytes32) {
bytes memory ackBytes = "";
for (uint256 i = 0; i < acks.length; i++) {
ackBytes = abi.encodePacked(ackBytes, sha256(acks[i]));
}

return sha256(abi.encodePacked(uint8(2), ackBytes));
return sha256(abi.encodePacked(uint8(2), recvSuccess, ackBytes));
}

/// @notice Create a prefixed path
Expand Down
4 changes: 2 additions & 2 deletions test/BenchmarkTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ contract BenchmarkTest is FixtureTest {
recvFixture.packet.destChannel, recvFixture.packet.sequence
)
);
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));
}

function test_ICS20TransferNativeSdkCoinWithSP1Fixtures_Plonk() public {
Expand All @@ -84,7 +84,7 @@ contract BenchmarkTest is FixtureTest {
recvNativeFixture.packet.destChannel, recvNativeFixture.packet.sequence
)
);
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));
}

function test_ICS20TimeoutWithSP1Fixtures_Plonk() public {
Expand Down
4 changes: 2 additions & 2 deletions test/ICS24HostTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ contract ICS24HostTest is Test {
bytes memory ack = abi.encodePacked("some bytes");
bytes[] memory acks = new bytes[](1);
acks[0] = ack;
bytes32 ackHash = ICS24Host.packetAcknowledgementCommitmentBytes32(acks);
bytes32 ackHash = ICS24Host.packetAcknowledgementCommitmentBytes32(true, acks);
string memory actualAckHash = Strings.toHexString(uint256(ackHash));
string memory expectedAckHash = "0xf03b4667413e56aaf086663267913e525c442b56fa1af4fa3f3dab9f37044c5b";
string memory expectedAckHash = "0xfc02a4453c297c9b65189ec354f4fc7f0c1327b72f6044a20d4dd1fac8fda9f7";
assertEq(actualAckHash, expectedAckHash);
}

Expand Down
32 changes: 20 additions & 12 deletions test/IntegrationTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ contract IntegrationTest is Test {

IICS26RouterMsgs.MsgAckPacket memory ackMsg = IICS26RouterMsgs.MsgAckPacket({
packet: packet,
recvSuccess: true,
acknowledgement: ICS20Lib.SUCCESSFUL_ACKNOWLEDGEMENT_JSON,
proofAcked: bytes("doesntmatter"), // dummy client will accept
proofHeight: IICS02ClientMsgs.Height({ revisionNumber: 1, revisionHeight: 42 }) // dummy client will accept
Expand Down Expand Up @@ -135,6 +136,7 @@ contract IntegrationTest is Test {

IICS26RouterMsgs.MsgAckPacket memory ackMsg = IICS26RouterMsgs.MsgAckPacket({
packet: packet,
recvSuccess: false,
acknowledgement: ICS20Lib.FAILED_ACKNOWLEDGEMENT_JSON,
proofAcked: bytes("doesntmatter"), // dummy client will accept
proofHeight: IICS02ClientMsgs.Height({ revisionNumber: 1, revisionHeight: 42 }) // dummy client will accept
Expand All @@ -159,6 +161,7 @@ contract IntegrationTest is Test {

IICS26RouterMsgs.MsgAckPacket memory ackMsg = IICS26RouterMsgs.MsgAckPacket({
packet: packet,
recvSuccess: false,
acknowledgement: ICS20Lib.FAILED_ACKNOWLEDGEMENT_JSON,
proofAcked: bytes("doesntmatter"), // dummy client will accept
proofHeight: IICS02ClientMsgs.Height({ revisionNumber: 1, revisionHeight: 42 }) // dummy client will accept
Expand All @@ -181,6 +184,7 @@ contract IntegrationTest is Test {

IICS26RouterMsgs.MsgAckPacket memory ackMsg = IICS26RouterMsgs.MsgAckPacket({
packet: packet,
recvSuccess: false,
acknowledgement: ICS20Lib.FAILED_ACKNOWLEDGEMENT_JSON,
proofAcked: bytes("doesntmatter"), // dummy client will accept
proofHeight: IICS02ClientMsgs.Height({ revisionNumber: 1, revisionHeight: 42 }) // dummy client will accept
Expand Down Expand Up @@ -285,6 +289,7 @@ contract IntegrationTest is Test {

IICS26RouterMsgs.MsgAckPacket memory ackMsg = IICS26RouterMsgs.MsgAckPacket({
packet: packet,
recvSuccess: true,
acknowledgement: ICS20Lib.SUCCESSFUL_ACKNOWLEDGEMENT_JSON,
proofAcked: bytes("doesntmatter"), // dummy client will accept
proofHeight: IICS02ClientMsgs.Height({ revisionNumber: 1, revisionHeight: 42 }) // dummy client will accept
Expand Down Expand Up @@ -339,7 +344,7 @@ contract IntegrationTest is Test {
address(erc20)
);
vm.expectEmit();
emit IICS26Router.WriteAcknowledgement(packet, singleSuccessAck);
emit IICS26Router.WriteAcknowledgement(packet, true, singleSuccessAck);
vm.expectEmit();
emit IICS26Router.RecvPacket(packet);

Expand All @@ -359,14 +364,15 @@ contract IntegrationTest is Test {
bytes32 storedAck = ics26Router.IBC_STORE().getCommitment(
ICS24Host.packetAcknowledgementCommitmentKeyCalldata(packet.destChannel, packet.sequence)
);
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));
}

function test_success_recvNoop() public {
IICS26RouterMsgs.Packet memory packet = _sendICS20Transfer();

IICS26RouterMsgs.MsgAckPacket memory ackMsg = IICS26RouterMsgs.MsgAckPacket({
packet: packet,
recvSuccess: true,
acknowledgement: ICS20Lib.SUCCESSFUL_ACKNOWLEDGEMENT_JSON,
proofAcked: bytes("doesntmatter"), // dummy client will accept
proofHeight: IICS02ClientMsgs.Height({ revisionNumber: 1, revisionHeight: 42 }) // dummy client will accept
Expand Down Expand Up @@ -421,7 +427,7 @@ contract IntegrationTest is Test {
bytes32 storedAck = ics26Router.IBC_STORE().getCommitment(
ICS24Host.packetAcknowledgementCommitmentKeyCalldata(packet.destChannel, packet.sequence)
);
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));

// call recv again, should be noop
vm.expectEmit();
Expand All @@ -435,6 +441,7 @@ contract IntegrationTest is Test {

IICS26RouterMsgs.MsgAckPacket memory ackMsg = IICS26RouterMsgs.MsgAckPacket({
packet: packet,
recvSuccess: true,
acknowledgement: ICS20Lib.SUCCESSFUL_ACKNOWLEDGEMENT_JSON,
proofAcked: bytes("doesntmatter"), // dummy client will accept
proofHeight: IICS02ClientMsgs.Height({ revisionNumber: 1, revisionHeight: 42 }) // dummy client will accept
Expand Down Expand Up @@ -489,7 +496,7 @@ contract IntegrationTest is Test {
bytes32 storedAck = ics26Router.IBC_STORE().getCommitment(
ICS24Host.packetAcknowledgementCommitmentKeyCalldata(packet.destChannel, packet.sequence)
);
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));

// override IBCStore to ErroneousIBCStore
vm.mockFunction(
Expand Down Expand Up @@ -535,7 +542,7 @@ contract IntegrationTest is Test {
vm.expectEmit(true, true, true, false); // Not checking data because we don't know the address yet
emit IICS20Transfer.ICS20ReceiveTransfer(packetData, erc20Address); // we check these values later
vm.expectEmit();
emit IICS26Router.WriteAcknowledgement(receivePacket, singleSuccessAck);
emit IICS26Router.WriteAcknowledgement(receivePacket, true, singleSuccessAck);
vm.expectEmit();
emit IICS26Router.RecvPacket(receivePacket);

Expand All @@ -552,7 +559,7 @@ contract IntegrationTest is Test {
bytes32 storedAck = ics26Router.IBC_STORE().getCommitment(
ICS24Host.packetAcknowledgementCommitmentKeyCalldata(receivePacket.destChannel, receivePacket.sequence)
);
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));

// find and extract data from the ICS20ReceiveTransfer event
Vm.Log memory receiveTransferLog = vm.getRecordedLogs()[3];
Expand Down Expand Up @@ -701,11 +708,11 @@ contract IntegrationTest is Test {
bytes32 storedAck = ics26Router.IBC_STORE().getCommitment(
ICS24Host.packetAcknowledgementCommitmentKeyCalldata(receivePacket.destChannel, receivePacket.sequence)
);
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));
bytes32 storedAck2 = ics26Router.IBC_STORE().getCommitment(
ICS24Host.packetAcknowledgementCommitmentKeyCalldata(receivePacket2.destChannel, receivePacket2.sequence)
);
assertEq(storedAck2, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck2, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));
}

function test_failure_receiveMultiPacketWithForeignBaseDenom() public {
Expand Down Expand Up @@ -806,7 +813,7 @@ contract IntegrationTest is Test {
address erc20Address;
emit IICS20Transfer.ICS20ReceiveTransfer(packetData, erc20Address); // we check these values later
vm.expectEmit();
emit IICS26Router.WriteAcknowledgement(receivePacket, singleSuccessAck);
emit IICS26Router.WriteAcknowledgement(receivePacket, true, singleSuccessAck);
vm.expectEmit();
emit IICS26Router.RecvPacket(receivePacket);

Expand All @@ -823,7 +830,7 @@ contract IntegrationTest is Test {
bytes32 storedAck = ics26Router.IBC_STORE().getCommitment(
ICS24Host.packetAcknowledgementCommitmentKeyCalldata(receivePacket.destChannel, receivePacket.sequence)
);
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));

// find and extract data from the ICS20ReceiveTransfer event
Vm.Log memory receiveTransferLog = vm.getRecordedLogs()[3];
Expand Down Expand Up @@ -945,7 +952,7 @@ contract IntegrationTest is Test {
address erc20Address;
emit IICS20Transfer.ICS20ReceiveTransfer(packetData, erc20Address); // we check these values later
vm.expectEmit();
emit IICS26Router.WriteAcknowledgement(receivePacket, singleSuccessAck);
emit IICS26Router.WriteAcknowledgement(receivePacket, true, singleSuccessAck);
vm.expectEmit();
emit IICS26Router.RecvPacket(receivePacket);

Expand All @@ -962,7 +969,7 @@ contract IntegrationTest is Test {
bytes32 storedAck = ics26Router.IBC_STORE().getCommitment(
ICS24Host.packetAcknowledgementCommitmentKeyCalldata(receivePacket.destChannel, receivePacket.sequence)
);
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(singleSuccessAck));
assertEq(storedAck, ICS24Host.packetAcknowledgementCommitmentBytes32(true, singleSuccessAck));

// find and extract data from the ICS20ReceiveTransfer event
Vm.Log memory receiveTransferLog = vm.getRecordedLogs()[3];
Expand Down Expand Up @@ -1054,6 +1061,7 @@ contract IntegrationTest is Test {

IICS26RouterMsgs.MsgAckPacket memory ackMsg = IICS26RouterMsgs.MsgAckPacket({
packet: packet,
recvSuccess: true,
acknowledgement: ICS20Lib.SUCCESSFUL_ACKNOWLEDGEMENT_JSON,
proofAcked: bytes("doesntmatter"), // dummy client will accept
proofHeight: IICS02ClientMsgs.Height({ revisionNumber: 1, revisionHeight: 42 }) // dummy client will accept
Expand Down
2 changes: 1 addition & 1 deletion test/mocks/ErroneousIBCStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ contract ErroneousIBCStore is IIBCStore {
revert CallFailure("setPacketReceipt");
}

function commitPacketAcknowledgement(IICS26RouterMsgs.Packet memory, bytes[] memory) external pure {
function commitPacketAcknowledgement(IICS26RouterMsgs.Packet memory, bool, bytes[] memory) external pure {
revert CallFailure("commitPacketAcknowledgement");
}
}
Loading