Skip to content

Commit

Permalink
introduce hostHeight() and check whether upgradeTimeout has passe…
Browse files Browse the repository at this point in the history
…d in `recvPacket()` and `timeoutPacket()`

Signed-off-by: Jun Kimura <[email protected]>
  • Loading branch information
bluele committed Nov 26, 2024
1 parent 2705330 commit be0f2e2
Show file tree
Hide file tree
Showing 4 changed files with 389 additions and 61 deletions.
26 changes: 23 additions & 3 deletions contracts/core/04-channel/IBCChannelPacketSendRecv.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ pragma solidity ^0.8.20;

import {Height} from "../../proto/Client.sol";
import {ConnectionEnd} from "../../proto/Connection.sol";
import {Channel} from "../../proto/Channel.sol";
import {Channel, Timeout} from "../../proto/Channel.sol";
import {ILightClient} from "../02-client/ILightClient.sol";
import {IIBCClientErrors} from "../02-client/IIBCClientErrors.sol";
import {IBCHeight} from "../02-client/IBCHeight.sol";
import {IBCChannelUpgradeBase} from "./IBCChannelUpgrade.sol";
import {IBCCommitment} from "../24-host/IBCCommitment.sol";
import {IBCModuleManager} from "../26-router/IBCModuleManager.sol";
import {IBCChannelLib} from "./IBCChannelLib.sol";
import {IIBCChannelPacketSendRecv} from "./IIBCChannel.sol";
import {IIBCChannelErrors} from "./IIBCChannelErrors.sol";
Expand All @@ -17,7 +17,7 @@ import {IIBCChannelErrors} from "./IIBCChannelErrors.sol";
* @dev IBCChannelPacketSendRecv is a contract that implements [ICS-4](https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics).
*/
contract IBCChannelPacketSendRecv is
IBCModuleManager,
IBCChannelUpgradeBase,
IIBCChannelPacketSendRecv,
IIBCChannelErrors,
IIBCClientErrors
Expand Down Expand Up @@ -276,6 +276,26 @@ contract IBCChannelPacketSendRecv is
}

delete commitments[packetCommitmentKey];

if (channel.state == Channel.State.STATE_FLUSHING) {
Timeout.Data memory timeout = channelStorage.counterpartyUpgradeTimeout;
if (!timeout.height.isZero() || timeout.timestamp != 0) {
if (
!timeout.height.isZero() && hostHeight().gte(timeout.height)
|| timeout.timestamp != 0 && hostTimestamp() >= timeout.timestamp
) {
restoreChannel(msg_.packet.sourcePort, msg_.packet.sourceChannel, UpgradeHandshakeError.Timeout);
} else if (
canTransitionToFlushComplete(
channel.ordering, msg_.packet.sourcePort, msg_.packet.sourceChannel, channel.upgrade_sequence
)
) {
channel.state = Channel.State.STATE_FLUSHCOMPLETE;
updateChannelCommitment(msg_.packet.sourcePort, msg_.packet.sourceChannel, channel);
}
}
}

emit AcknowledgePacket(msg_.packet, msg_.acknowledgement);
lookupModuleByChannel(msg_.packet.sourcePort, msg_.packet.sourceChannel).onAcknowledgementPacket(
msg_.packet, msg_.acknowledgement, _msgSender()
Expand Down
48 changes: 34 additions & 14 deletions contracts/core/04-channel/IBCChannelPacketTimeout.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@ pragma solidity ^0.8.20;

import {Height} from "../../proto/Client.sol";
import {ConnectionEnd} from "../../proto/Connection.sol";
import {Channel, ChannelCounterparty} from "../../proto/Channel.sol";
import {Channel, ChannelCounterparty, Timeout} from "../../proto/Channel.sol";
import {ILightClient} from "../02-client/ILightClient.sol";
import {IBCHeight} from "../02-client/IBCHeight.sol";
import {IBCChannelLib} from "./IBCChannelLib.sol";
import {IBCChannelUpgradeBase} from "./IBCChannelUpgrade.sol";
import {IBCCommitment} from "../24-host/IBCCommitment.sol";
import {IBCModuleManager} from "../26-router/IBCModuleManager.sol";
import {IIBCChannelPacketTimeout} from "./IIBCChannel.sol";
import {IIBCChannelErrors} from "./IIBCChannelErrors.sol";

contract IBCChannelPacketTimeout is IBCModuleManager, IIBCChannelPacketTimeout, IIBCChannelErrors {
contract IBCChannelPacketTimeout is IBCChannelUpgradeBase, IIBCChannelPacketTimeout, IIBCChannelErrors {
using IBCHeight for Height.Data;

function timeoutPacket(MsgTimeoutPacket calldata msg_) external {
Channel.Data storage channel = getChannelStorage()[msg_.packet.sourcePort][msg_.packet.sourceChannel].channel;
ChannelStorage storage channelStorage = getChannelStorage()[msg_.packet.sourcePort][msg_.packet.sourceChannel];
Channel.Data storage channel = channelStorage.channel;
if (channel.state == Channel.State.STATE_UNINITIALIZED_UNSPECIFIED) {
revert IBCChannelUnexpectedChannelState(channel.state);
}
Expand Down Expand Up @@ -99,8 +100,6 @@ contract IBCChannelPacketTimeout is IBCModuleManager, IIBCChannelPacketTimeout,
msg_.proofHeight
);
}
channel.state = Channel.State.STATE_CLOSED;
updateChannelCommitment(msg_.packet.sourcePort, msg_.packet.sourceChannel);
} else if (channel.ordering == Channel.Order.ORDER_UNORDERED) {
bytes memory path = IBCCommitment.packetReceiptCommitmentPathCalldata(
msg_.packet.destinationPort, msg_.packet.destinationChannel, msg_.packet.sequence
Expand Down Expand Up @@ -129,6 +128,35 @@ contract IBCChannelPacketTimeout is IBCModuleManager, IIBCChannelPacketTimeout,
msg_.packet.sourcePort, msg_.packet.sourceChannel, msg_.packet.sequence
)];

if (channel.state == Channel.State.STATE_FLUSHING) {
Timeout.Data memory timeout = channelStorage.counterpartyUpgradeTimeout;
if (!timeout.height.isZero() || timeout.timestamp != 0) {
if (
!timeout.height.isZero() && hostHeight().gte(timeout.height)
|| timeout.timestamp != 0 && hostTimestamp() >= timeout.timestamp
) {
restoreChannel(msg_.packet.sourcePort, msg_.packet.sourceChannel, UpgradeHandshakeError.Timeout);
} else if (
canTransitionToFlushComplete(
channel.ordering, msg_.packet.sourcePort, msg_.packet.sourceChannel, channel.upgrade_sequence
)
) {
channel.state = Channel.State.STATE_FLUSHCOMPLETE;
updateChannelCommitment(msg_.packet.sourcePort, msg_.packet.sourceChannel, channel);
}
}
}

if (channel.ordering == Channel.Order.ORDER_ORDERED) {
if (channel.state == Channel.State.STATE_FLUSHING) {
delete channelStorage.upgrade;
deleteUpgradeCommitment(msg_.packet.sourcePort, msg_.packet.sourceChannel);
revertCounterpartyUpgrade(channelStorage);
}
channel.state = Channel.State.STATE_CLOSED;
updateChannelCommitment(msg_.packet.sourcePort, msg_.packet.sourceChannel, channel);
}

lookupModuleByChannel(msg_.packet.sourcePort, msg_.packet.sourceChannel).onTimeoutPacket(
msg_.packet, _msgSender()
);
Expand Down Expand Up @@ -290,12 +318,4 @@ contract IBCChannelPacketTimeout is IBCModuleManager, IIBCChannelPacketTimeout,
return (timeDelay + hostStorage.expectedTimePerBlock - 1) / hostStorage.expectedTimePerBlock;
}
}

/**
* @dev updateChannelCommitment updates the channel commitment for the given port and channel
*/
function updateChannelCommitment(string memory portId, string memory channelId) private {
getCommitments()[IBCCommitment.channelCommitmentKey(portId, channelId)] =
keccak256(Channel.encode(getChannelStorage()[portId][channelId].channel));
}
}
23 changes: 20 additions & 3 deletions contracts/core/24-host/IBCHost.sol
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

import {Height} from "../../proto/Client.sol";
import {ILightClient} from "../02-client/ILightClient.sol";
import {IIBCClientErrors} from "../02-client/IIBCClientErrors.sol";
import {IBCStore} from "./IBCStore.sol";
import {IIBCHostErrors} from "./IIBCHostErrors.sol";

contract IBCHost is IBCStore, IIBCHostErrors {
// It represents the prefix of the commitment proof(https://github.com/cosmos/ibc/tree/main/spec/core/ics-023-vector-commitments#prefix).
// In ibc-solidity, the prefix is not required, but for compatibility with ibc-go this must be a non-empty value.
/// @dev It represents the prefix of the commitment proof(https://github.com/cosmos/ibc/tree/main/spec/core/ics-023-vector-commitments#prefix).
/// In ibc-solidity, the prefix is not required, but for compatibility with ibc-go this must be a non-empty value.
bytes internal constant DEFAULT_COMMITMENT_PREFIX = bytes("ibc");
/// @dev It represents the default revision number.
uint64 internal constant DEFAULT_REVISION_NUMBER = 0;

/**
* @dev hostTimestamp returns the current timestamp(Unix time in nanoseconds) of the host chain.
*/
function hostTimestamp() internal view virtual returns (uint64) {
function hostTimestamp() internal view returns (uint64) {
return uint64(block.timestamp) * 1e9;
}

/**
* @dev hostHeight returns the current height of the host chain.
*/
function hostHeight() internal view returns (Height.Data memory) {
return Height.Data({revision_number: _getRevisionNumber(), revision_height: uint64(block.number)});
}

/**
* @dev checkAndGetClient returns the client implementation for the given client ID.
*/
Expand All @@ -35,4 +45,11 @@ contract IBCHost is IBCStore, IIBCHostErrors {
function _getCommitmentPrefix() internal view virtual returns (bytes memory) {
return DEFAULT_COMMITMENT_PREFIX;
}

/**
* @dev _getRevisionNumber returns the revision number of the host chain.
*/
function _getRevisionNumber() internal view virtual returns (uint64) {
return DEFAULT_REVISION_NUMBER;
}
}
Loading

0 comments on commit be0f2e2

Please sign in to comment.