Skip to content

Commit

Permalink
Merge pull request #257 from hyperledger-labs/client-latest-info
Browse files Browse the repository at this point in the history
Add `getLatestInfo` function to `ILightClient`

Signed-off-by: Jun Kimura <[email protected]>
  • Loading branch information
bluele authored Feb 26, 2024
2 parents 86fa06e + 263c0e6 commit 5f47feb
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 44 deletions.
30 changes: 15 additions & 15 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
IBCMockAppTest:testHandshake() (gas: 3433206)
IBCMockAppTest:testHandshakeBetweenDifferentPorts() (gas: 2539275)
IBCMockAppTest:testPacketRelay() (gas: 9485102)
IBCMockAppTest:testPacketTimeout() (gas: 2906505)
IBCMockAppTest:testPacketRelay() (gas: 9417242)
IBCMockAppTest:testPacketTimeout() (gas: 2899060)
IBCTest:testBenchmarkCreateMockClient() (gas: 209365)
IBCTest:testBenchmarkLCUpdateMockClient() (gas: 39945)
IBCTest:testBenchmarkRecvPacket() (gas: 129941)
IBCTest:testBenchmarkSendPacket() (gas: 84051)
IBCTest:testBenchmarkSendPacket() (gas: 81008)
IBCTest:testBenchmarkUpdateMockClient() (gas: 137373)
IBCTest:testToUint128((uint64,uint64)) (runs: 256, μ: 947, ~: 947)
TestICS02:testCreateClient() (gas: 23157317)
TestICS02:testInvalidCreateClient() (gas: 23006914)
TestICS02:testInvalidUpdateClient() (gas: 23008761)
TestICS02:testRegisterClient() (gas: 22751790)
TestICS02:testRegisterClientDuplicatedClientType() (gas: 22735015)
TestICS02:testRegisterClientInvalidClientType() (gas: 22719144)
TestICS02:testUpdateClient() (gas: 23174313)
TestICS02:testCreateClient() (gas: 23141284)
TestICS02:testInvalidCreateClient() (gas: 22990881)
TestICS02:testInvalidUpdateClient() (gas: 22992728)
TestICS02:testRegisterClient() (gas: 22735757)
TestICS02:testRegisterClientDuplicatedClientType() (gas: 22718982)
TestICS02:testRegisterClientInvalidClientType() (gas: 22703111)
TestICS02:testUpdateClient() (gas: 23158280)
TestICS03Handshake:testConnOpenAck() (gas: 1631720)
TestICS03Handshake:testConnOpenConfirm() (gas: 1766228)
TestICS03Handshake:testConnOpenInit() (gas: 1279055)
Expand All @@ -40,12 +40,12 @@ TestICS04Handshake:testInvalidChanOpenConfirm() (gas: 2116580)
TestICS04Handshake:testInvalidChanOpenInit() (gas: 1275939)
TestICS04Handshake:testInvalidChanOpenTry() (gas: 1352198)
TestICS04Packet:testAcknowledgementPacket() (gas: 2276942)
TestICS04Packet:testInvalidSendPacket() (gas: 2274601)
TestICS04Packet:testInvalidSendPacket() (gas: 2274365)
TestICS04Packet:testRecvPacket() (gas: 7645640)
TestICS04Packet:testRecvPacketTimeoutHeight() (gas: 2320869)
TestICS04Packet:testRecvPacketTimeoutTimestamp() (gas: 2319828)
TestICS04Packet:testSendPacket() (gas: 5067297)
TestICS04Packet:testTimeoutOnClose() (gas: 2539008)
TestICS04Packet:testRecvPacketTimeoutHeight() (gas: 2314783)
TestICS04Packet:testRecvPacketTimeoutTimestamp() (gas: 2313742)
TestICS04Packet:testSendPacket() (gas: 5018609)
TestICS04Packet:testTimeoutOnClose() (gas: 2532922)
TestICS20:testAddressToHex(address) (runs: 256, μ: 22676, ~: 22804)
TestICS20:testHexToAddress(string) (runs: 256, μ: 4776, ~: 4734)
TestICS20:testIsEscapedString() (gas: 48979)
Expand Down
31 changes: 22 additions & 9 deletions contracts/clients/IBFT2Client.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ contract IBFT2Client is ILightClient, ILightClientErrors {
string calldata clientId,
bytes calldata protoClientState,
bytes calldata protoConsensusState
) external override onlyIBC returns (Height.Data memory height) {
) public override onlyIBC returns (Height.Data memory height) {
ClientState.Data memory clientState = unmarshalClientState(protoClientState);
ConsensusState.Data memory consensusState = unmarshalConsensusState(protoConsensusState);
if (clientState.ibc_store_address.length != 20) {
Expand All @@ -103,7 +103,7 @@ contract IBFT2Client is ILightClient, ILightClientErrors {
* The light client encodes a client message as ethereum ABI.
*/
function routeUpdateClient(string calldata clientId, bytes calldata protoClientMessage)
external
public
pure
virtual
override
Expand All @@ -118,7 +118,7 @@ contract IBFT2Client is ILightClient, ILightClientErrors {
* The timestamp is nanoseconds since unix epoch.
*/
function getTimestampAtHeight(string calldata clientId, Height.Data calldata height)
external
public
view
override
returns (uint64)
Expand All @@ -134,7 +134,7 @@ contract IBFT2Client is ILightClient, ILightClientErrors {
/**
* @dev getLatestHeight returns the latest height of the client state corresponding to `clientId`.
*/
function getLatestHeight(string calldata clientId) external view override returns (Height.Data memory) {
function getLatestHeight(string calldata clientId) public view override returns (Height.Data memory) {
ClientState.Data storage clientState = clientStates[clientId];
if (clientState.latest_height.revision_height == 0) {
revert ClientStateNotFound(clientId);
Expand All @@ -145,10 +145,23 @@ contract IBFT2Client is ILightClient, ILightClientErrors {
/**
* @dev getStatus returns the status of the client corresponding to `clientId`.
*/
function getStatus(string calldata) external pure override returns (ILightClient.ClientStatus) {
function getStatus(string calldata) public pure override returns (ILightClient.ClientStatus) {
return ILightClient.ClientStatus.Active;
}

/**
* @dev getLatestInfo returns the latest height, timestamp and status of the client corresponding to `clientId`.
*/
function getLatestInfo(string calldata clientId)
public
view
returns (Height.Data memory latestHeight, uint64 latestTimestamp, ClientStatus status)
{
latestHeight = getLatestHeight(clientId);
latestTimestamp = consensusStates[clientId][latestHeight.toUint128()].timestamp;
status = ILightClient.ClientStatus.Active;
}

/**
* @dev updateClient updates the client with the given header
*/
Expand Down Expand Up @@ -204,7 +217,7 @@ contract IBFT2Client is ILightClient, ILightClientErrors {
bytes memory prefix,
bytes memory path,
bytes calldata value
) external view override returns (bool) {
) public view override returns (bool) {
if (!validateArgsAndDelayPeriod(clientId, height, delayTimePeriod, delayBlockPeriod, prefix, proof)) {
return false;
}
Expand Down Expand Up @@ -232,7 +245,7 @@ contract IBFT2Client is ILightClient, ILightClientErrors {
bytes calldata proof,
bytes calldata prefix,
bytes calldata path
) external view override returns (bool) {
) public view override returns (bool) {
if (!validateArgsAndDelayPeriod(clientId, height, delayTimePeriod, delayBlockPeriod, prefix, proof)) {
return false;
}
Expand Down Expand Up @@ -493,7 +506,7 @@ contract IBFT2Client is ILightClient, ILightClientErrors {
* @dev getClientState returns the clientState corresponding to `clientId`.
* If it's not found, the function returns false.
*/
function getClientState(string calldata clientId) external view returns (bytes memory clientStateBytes, bool) {
function getClientState(string calldata clientId) public view returns (bytes memory clientStateBytes, bool) {
ClientState.Data storage clientState = clientStates[clientId];
if (clientState.latest_height.revision_height == 0) {
return (clientStateBytes, false);
Expand All @@ -506,7 +519,7 @@ contract IBFT2Client is ILightClient, ILightClientErrors {
* If it's not found, the function returns false.
*/
function getConsensusState(string calldata clientId, Height.Data calldata height)
external
public
view
returns (bytes memory consensusStateBytes, bool)
{
Expand Down
10 changes: 10 additions & 0 deletions contracts/clients/LocalhostClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ contract LocalhostClient is ILightClient, ILightClientErrors {
return ClientStatus.Active;
}

function getLatestInfo(string calldata clientId)
public
view
returns (Height.Data memory latestHeight, uint64 latestTimestamp, ClientStatus status)
{
latestHeight = getLatestHeight(clientId);
latestTimestamp = uint64(block.timestamp);
status = ILightClient.ClientStatus.Active;
}

/**
* @dev verifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height.
* The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
Expand Down
33 changes: 23 additions & 10 deletions contracts/clients/MockClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ contract MockClient is Ownable, ILightClient, ILightClientErrors {
string calldata clientId,
bytes calldata protoClientState,
bytes calldata protoConsensusState
) external virtual override onlyIBC returns (Height.Data memory height) {
) public virtual override onlyIBC returns (Height.Data memory height) {
ClientState.Data memory clientState = unmarshalClientState(protoClientState);
ConsensusState.Data memory consensusState = unmarshalConsensusState(protoConsensusState);
if (clientState.latest_height.revision_number != 0 || clientState.latest_height.revision_height == 0) {
Expand All @@ -70,7 +70,7 @@ contract MockClient is Ownable, ILightClient, ILightClientErrors {
* The light client encodes a client message as ethereum ABI.
*/
function routeUpdateClient(string calldata clientId, bytes calldata protoClientMessage)
external
public
pure
virtual
override
Expand All @@ -92,7 +92,7 @@ contract MockClient is Ownable, ILightClient, ILightClientErrors {
* The timestamp is nanoseconds since unix epoch.
*/
function getTimestampAtHeight(string calldata clientId, Height.Data calldata height)
external
public
view
virtual
override
Expand All @@ -108,7 +108,7 @@ contract MockClient is Ownable, ILightClient, ILightClientErrors {
/**
* @dev getLatestHeight returns the latest height of the client state corresponding to `clientId`.
*/
function getLatestHeight(string calldata clientId) external view virtual override returns (Height.Data memory) {
function getLatestHeight(string calldata clientId) public view virtual override returns (Height.Data memory) {
ClientState.Data storage clientState = clientStates[clientId];
if (clientState.latest_height.revision_height == 0) {
revert ClientStateNotFound(clientId);
Expand All @@ -119,14 +119,27 @@ contract MockClient is Ownable, ILightClient, ILightClientErrors {
/**
* @dev getStatus returns the status of the client corresponding to `clientId`.
*/
function getStatus(string calldata clientId) external view virtual override returns (ClientStatus) {
function getStatus(string calldata clientId) public view virtual override returns (ClientStatus) {
return statuses[clientId];
}

/**
* @dev getLatestInfo returns the latest height, the latest timestamp, and the status of the client corresponding to `clientId`.
*/
function getLatestInfo(string calldata clientId)
public
view
returns (Height.Data memory latestHeight, uint64 latestTimestamp, ClientStatus status)
{
latestHeight = getLatestHeight(clientId);
latestTimestamp = consensusStates[clientId][latestHeight.toUint128()].timestamp;
status = statuses[clientId];
}
/**
* @dev setStatus sets the status of the client corresponding to `clientId`.
*/
function setStatus(string calldata clientId, ClientStatus status) external virtual onlyOwner {

function setStatus(string calldata clientId, ClientStatus status) public virtual onlyOwner {
statuses[clientId] = status;
}

Expand Down Expand Up @@ -165,7 +178,7 @@ contract MockClient is Ownable, ILightClient, ILightClientErrors {
bytes memory prefix,
bytes memory path,
bytes calldata value
) external view virtual override returns (bool) {
) public view virtual override returns (bool) {
if (consensusStates[clientId][height.toUint128()].timestamp == 0) {
revert ConsensusStateNotFound(clientId, height);
}
Expand All @@ -191,7 +204,7 @@ contract MockClient is Ownable, ILightClient, ILightClientErrors {
bytes calldata proof,
bytes memory prefix,
bytes memory path
) external view virtual override returns (bool) {
) public view virtual override returns (bool) {
if (consensusStates[clientId][height.toUint128()].timestamp == 0) {
revert ConsensusStateNotFound(clientId, height);
}
Expand All @@ -208,7 +221,7 @@ contract MockClient is Ownable, ILightClient, ILightClientErrors {
* If it's not found, the function returns false.
*/
function getClientState(string calldata clientId)
external
public
view
virtual
returns (bytes memory clientStateBytes, bool)
Expand All @@ -225,7 +238,7 @@ contract MockClient is Ownable, ILightClient, ILightClientErrors {
* If it's not found, the function returns false.
*/
function getConsensusState(string calldata clientId, Height.Data calldata height)
external
public
view
virtual
returns (bytes memory consensusStateBytes, bool)
Expand Down
8 changes: 8 additions & 0 deletions contracts/core/02-client/ILightClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ interface ILightClient {
*/
function getStatus(string calldata clientId) external view returns (ClientStatus);

/**
* @dev getLatestInfo returns the latest height, the latest timestamp, and the status of the client corresponding to `clientId`.
*/
function getLatestInfo(string calldata clientId)
external
view
returns (Height.Data memory latestHeight, uint64 latestTimestamp, ClientStatus status);

/**
* @dev verifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height.
* The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
Expand Down
11 changes: 3 additions & 8 deletions contracts/core/04-channel/IBCChannelPacketSendRecv.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,14 @@ contract IBCChannelPacketSendRecv is
{
// NOTE: We can assume here that the connection state is OPEN because the channel state is OPEN
ConnectionEnd.Data storage connection = connections[channel.connection_hops[0]];
ILightClient client = ILightClient(clientImpls[connection.client_id]);
if (address(client) == address(0)) {
revert IBCHostClientNotFound(connection.client_id);
}
if (client.getStatus(connection.client_id) != ILightClient.ClientStatus.Active) {
(Height.Data memory latestHeight, uint64 latestTimestamp, ILightClient.ClientStatus status) =
ILightClient(clientImpls[connection.client_id]).getLatestInfo(connection.client_id);
if (status != ILightClient.ClientStatus.Active) {
revert IBCClientNotActiveClient(connection.client_id);
}

Height.Data memory latestHeight = client.getLatestHeight(connection.client_id);
if (!timeoutHeight.isZero() && latestHeight.gte(timeoutHeight)) {
revert IBCChannelPastPacketTimeoutHeight(timeoutHeight, latestHeight);
}
uint64 latestTimestamp = client.getTimestampAtHeight(connection.client_id, latestHeight);
if (timeoutTimestamp != 0 && latestTimestamp >= timeoutTimestamp) {
revert IBCChannelPastPacketTimeoutTimestamp(timeoutTimestamp, latestTimestamp);
}
Expand Down
Loading

0 comments on commit 5f47feb

Please sign in to comment.