Skip to content

Commit

Permalink
Merge pull request #234 from hyperledger-labs/refactor-handler
Browse files Browse the repository at this point in the history
Refactoring to merge handler into each feature implementation

Signed-off-by: Jun Kimura <jun.kimura@datachain.jp>
  • Loading branch information
bluele committed Nov 28, 2023
2 parents 229ef0b + fd3cfd4 commit 352dc59
Show file tree
Hide file tree
Showing 57 changed files with 1,883 additions and 1,824 deletions.
82 changes: 41 additions & 41 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
IBCTest:testBenchmarkCreateMockClient() (gas: 216645)
IBCTest:testBenchmarkRecvPacket() (gas: 153912)
IBCTest:testBenchmarkSendPacket() (gas: 89919)
IBCTest:testBenchmarkUpdateMockClient() (gas: 129946)
IBCTest:testToUint128((uint64,uint64)) (runs: 256, μ: 1013, ~: 1013)
TestICS02:testCreateClient() (gas: 20419568)
TestICS02:testInvalidCreateClient() (gas: 20267951)
TestICS02:testInvalidUpdateClient() (gas: 20272833)
TestICS02:testRegisterClient() (gas: 19902791)
TestICS02:testRegisterClientDuplicatedClientType() (gas: 19884771)
TestICS02:testRegisterClientInvalidClientType() (gas: 19873570)
TestICS02:testUpdateClient() (gas: 20415107)
TestICS03Handshake:testConnOpenAck() (gas: 1642938)
TestICS03Handshake:testConnOpenConfirm() (gas: 1781624)
TestICS03Handshake:testConnOpenInit() (gas: 1319897)
TestICS03Handshake:testConnOpenTry() (gas: 2148987)
TestICS03Handshake:testInvalidConnOpenAck() (gas: 2031709)
TestICS03Handshake:testInvalidConnOpenConfirm() (gas: 2037872)
TestICS03Handshake:testInvalidConnOpenInit() (gas: 693724)
TestICS03Handshake:testInvalidConnOpenTry() (gas: 2156100)
TestICS03Version:testCopyVersions() (gas: 560316)
TestICS03Version:testFindSupportedVersion() (gas: 19986)
TestICS03Version:testIsSupportedVersion() (gas: 8317)
TestICS03Version:testPickVersion() (gas: 27093)
TestICS03Version:testVerifyProposedVersion() (gas: 12368)
TestICS03Version:testVerifySupportedFeature() (gas: 4441)
TestICS04Handshake:testChanOpenAck() (gas: 3081103)
TestICS04Handshake:testChanOpenConfirm() (gas: 3272966)
TestICS04Handshake:testChanOpenInit() (gas: 2337459)
TestICS04Handshake:testChanOpenTry() (gas: 2840835)
TestICS04Handshake:testInvalidChanOpenAck() (gas: 2175906)
TestICS04Handshake:testInvalidChanOpenConfirm() (gas: 2234633)
TestICS04Handshake:testInvalidChanOpenInit() (gas: 1333705)
TestICS04Handshake:testInvalidChanOpenTry() (gas: 1411715)
TestICS04Packet:testInvalidSendPacket() (gas: 2301656)
TestICS04Packet:testSendPacket() (gas: 2486762)
TestICS20:testAddressToHex(address) (runs: 256, μ: 23716, ~: 23858)
TestICS20:testHexToAddress(string) (runs: 256, μ: 4817, ~: 4829)
TestICS20:testIsEscapedString() (gas: 49914)
TestICS20:testMarshaling() (gas: 150062)
TestICS20:testParseAmount(uint256) (runs: 256, μ: 27191, ~: 21814)
IBCTest:testBenchmarkCreateMockClient() (gas: 211711)
IBCTest:testBenchmarkRecvPacket() (gas: 140015)
IBCTest:testBenchmarkSendPacket() (gas: 86064)
IBCTest:testBenchmarkUpdateMockClient() (gas: 126678)
IBCTest:testToUint128((uint64,uint64)) (runs: 256, μ: 917, ~: 917)
TestICS02:testCreateClient() (gas: 23422491)
TestICS02:testInvalidCreateClient() (gas: 23270044)
TestICS02:testInvalidUpdateClient() (gas: 23273913)
TestICS02:testRegisterClient() (gas: 22894201)
TestICS02:testRegisterClientDuplicatedClientType() (gas: 22876251)
TestICS02:testRegisterClientInvalidClientType() (gas: 22861044)
TestICS02:testUpdateClient() (gas: 23417285)
TestICS03Handshake:testConnOpenAck() (gas: 1594072)
TestICS03Handshake:testConnOpenConfirm() (gas: 1728943)
TestICS03Handshake:testConnOpenInit() (gas: 1287196)
TestICS03Handshake:testConnOpenTry() (gas: 2088127)
TestICS03Handshake:testInvalidConnOpenAck() (gas: 1953639)
TestICS03Handshake:testInvalidConnOpenConfirm() (gas: 1974862)
TestICS03Handshake:testInvalidConnOpenInit() (gas: 672171)
TestICS03Handshake:testInvalidConnOpenTry() (gas: 2093785)
TestICS03Version:testCopyVersions() (gas: 560134)
TestICS03Version:testFindSupportedVersion() (gas: 19740)
TestICS03Version:testIsSupportedVersion() (gas: 8272)
TestICS03Version:testPickVersion() (gas: 26823)
TestICS03Version:testVerifyProposedVersion() (gas: 12185)
TestICS03Version:testVerifySupportedFeature() (gas: 4357)
TestICS04Handshake:testChanOpenAck() (gas: 2989540)
TestICS04Handshake:testChanOpenConfirm() (gas: 3172516)
TestICS04Handshake:testChanOpenInit() (gas: 2276564)
TestICS04Handshake:testChanOpenTry() (gas: 2760444)
TestICS04Handshake:testInvalidChanOpenAck() (gas: 2117646)
TestICS04Handshake:testInvalidChanOpenConfirm() (gas: 2176812)
TestICS04Handshake:testInvalidChanOpenInit() (gas: 1281923)
TestICS04Handshake:testInvalidChanOpenTry() (gas: 1356309)
TestICS04Packet:testInvalidSendPacket() (gas: 2319493)
TestICS04Packet:testSendPacket() (gas: 2377298)
TestICS20:testAddressToHex(address) (runs: 256, μ: 22708, ~: 22824)
TestICS20:testHexToAddress(string) (runs: 256, μ: 4776, ~: 4734)
TestICS20:testIsEscapedString() (gas: 48979)
TestICS20:testMarshaling() (gas: 148145)
TestICS20:testParseAmount(uint256) (runs: 256, μ: 27065, ~: 21653)
3 changes: 1 addition & 2 deletions contracts/apps/20-transfer/ICS20Transfer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
pragma solidity ^0.8.9;

import "../commons/IBCAppBase.sol";
import "../../core/05-port/IIBCModule.sol";
import "../../core/25-handler/IBCHandler.sol";
import "../../core/26-router/IIBCModule.sol";
import "../../proto/Channel.sol";
import "./ICS20Lib.sol";
import "solidity-bytes-utils/contracts/BytesLib.sol";
Expand Down
8 changes: 4 additions & 4 deletions contracts/apps/20-transfer/ICS20TransferBank.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ pragma solidity ^0.8.9;

import "./ICS20Transfer.sol";
import "./IICS20Bank.sol";
import "../../core/25-handler/IBCHandler.sol";
import "../../core/25-handler/IIBCHandler.sol";
import "solidity-bytes-utils/contracts/BytesLib.sol";

contract ICS20TransferBank is ICS20Transfer {
using BytesLib for bytes;

IBCHandler private immutable ibcHandler;
IIBCHandler private immutable ibcHandler;
IICS20Bank private immutable bank;

constructor(IBCHandler ibcHandler_, IICS20Bank bank_) {
constructor(IIBCHandler ibcHandler_, IICS20Bank bank_) {
ibcHandler = ibcHandler_;
bank = bank_;
}
Expand Down Expand Up @@ -43,7 +43,7 @@ contract ICS20TransferBank is ICS20Transfer {
require(_burn(_msgSender(), denom, amount));
}
bytes memory packetData = ICS20Lib.marshalJSON(denom, amount, _encodeSender(_msgSender()), receiver);
IBCHandler(ibcAddress()).sendPacket(
IIBCHandler(ibcAddress()).sendPacket(
sourcePort, sourceChannel, Height.Data({revision_number: 0, revision_height: timeoutHeight}), 0, packetData
);
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/apps/commons/IBCAppBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/utils/Context.sol";
import "../../core/05-port/IIBCModule.sol";
import "../../core/26-router/IIBCModule.sol";

/**
* @dev Base contract of the IBC App protocol
Expand Down
14 changes: 8 additions & 6 deletions contracts/apps/mock/IBCMockApp.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.9;

import "../commons/IBCAppBase.sol";
import "../../core/05-port/IIBCModule.sol";
import "../../core/25-handler/IBCHandler.sol";
import "./IBCMockLib.sol";
import {Height} from "../../proto/Client.sol";
import {Packet} from "../../proto/Channel.sol";
import {IBCAppBase} from "../commons/IBCAppBase.sol";
import {IIBCModule} from "../../core/26-router/IIBCModule.sol";
import {IIBCHandler} from "../../core/25-handler/IIBCHandler.sol";
import {IBCMockLib} from "./IBCMockLib.sol";

contract IBCMockApp is IBCAppBase {
string public constant MOCKAPP_VERSION = "mockapp-1";

IBCHandler immutable ibcHandler;
IIBCHandler immutable ibcHandler;

constructor(IBCHandler ibcHandler_) {
constructor(IIBCHandler ibcHandler_) {
ibcHandler = ibcHandler_;
}

Expand Down
4 changes: 2 additions & 2 deletions contracts/clients/IBFT2Client.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.9;

import "../core/02-client/ILightClient.sol";
import "../core/02-client/IBCHeight.sol";
import "../core/25-handler/IBCHandler.sol";
import "../core/25-handler/IIBCHandler.sol";
import "../proto/Client.sol";
import {
IbcLightclientsIbft2V1ClientState as ClientState,
Expand Down Expand Up @@ -421,7 +421,7 @@ contract IBFT2Client is ILightClient {
return false;
}

return keccak256(IBCHandler(ibcHandler).getCommitmentPrefix()) == keccak256(prefix);
return keccak256(IIBCHandler(ibcHandler).getCommitmentPrefix()) == keccak256(prefix);
}

function verifyMembership(bytes calldata proof, bytes32 root, bytes32 slot, bytes32 expectedValue)
Expand Down
6 changes: 3 additions & 3 deletions contracts/clients/MockClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.9;

import "../core/02-client/ILightClient.sol";
import "../core/02-client/IBCHeight.sol";
import "../core/25-handler/IBCHandler.sol";
import "../core/25-handler/IIBCHandler.sol";
import "../proto/Client.sol";
import {
IbcLightclientsMockV1ClientState as ClientState,
Expand Down Expand Up @@ -167,7 +167,7 @@ contract MockClient is ILightClient {
bytes calldata value
) external view virtual override returns (bool) {
require(consensusStates[clientId][height.toUint128()].timestamp != 0, "consensus state not found");
require(keccak256(IBCHandler(ibcHandler).getCommitmentPrefix()) == keccak256(prefix), "invalid prefix");
require(keccak256(IIBCHandler(ibcHandler).getCommitmentPrefix()) == keccak256(prefix), "invalid prefix");
return sha256(value) == proof.toBytes32(0);
}

Expand All @@ -185,7 +185,7 @@ contract MockClient is ILightClient {
bytes memory
) external view virtual override returns (bool) {
require(consensusStates[clientId][height.toUint128()].timestamp != 0, "consensus state not found");
require(keccak256(IBCHandler(ibcHandler).getCommitmentPrefix()) == keccak256(prefix), "invalid prefix");
require(keccak256(IIBCHandler(ibcHandler).getCommitmentPrefix()) == keccak256(prefix), "invalid prefix");
return proof.length == 0;
}

Expand Down
62 changes: 9 additions & 53 deletions contracts/core/02-client/IBCClient.sol
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./ILightClient.sol";
import "../25-handler/IBCMsgs.sol";
import "../24-host/IBCStore.sol";
import "../24-host/IBCCommitment.sol";
import "../02-client/IIBCClient.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ILightClient, ConsensusStateUpdate} from "./ILightClient.sol";
import {IBCHost} from "../24-host/IBCHost.sol";
import {IBCCommitment} from "../24-host/IBCCommitment.sol";
import {IIBCClient} from "../02-client/IIBCClient.sol";

/**
* @dev IBCClient is a contract that implements [ICS-2](https://github.com/cosmos/ibc/tree/main/spec/core/ics-002-client-semantics).
*/
contract IBCClient is IBCStore, IIBCClient {
/**
* @dev registerClient registers a new client type into the client registry
*/
function registerClient(string calldata clientType, ILightClient client) external override {
require(validateClientType(bytes(clientType)), "invalid clientType");
require(address(clientRegistry[clientType]) == address(0), "clientType already exists");
require(address(client) != address(this) && Address.isContract(address(client)), "invalid client address");
clientRegistry[clientType] = address(client);
}

contract IBCClient is IBCHost, IIBCClient {
/**
* @dev createClient creates a new client state and populates it with a given consensus state
*/
function createClient(IBCMsgs.MsgCreateClient calldata msg_) external override returns (string memory clientId) {
function createClient(MsgCreateClient calldata msg_) external override returns (string memory clientId) {
address clientImpl = clientRegistry[msg_.clientType];
require(clientImpl != address(0), "unregistered client type");
clientId = generateClientIdentifier(msg_.clientType);
Expand All @@ -41,14 +29,14 @@ contract IBCClient is IBCStore, IIBCClient {
commitments[IBCCommitment.consensusStateCommitmentKey(
clientId, update.height.revision_number, update.height.revision_height
)] = update.consensusStateCommitment;

emit GeneratedClientIdentifier(clientId);
return clientId;
}

/**
* @dev updateClient updates the consensus state and the state root from a provided header
*/
function updateClient(IBCMsgs.MsgUpdateClient calldata msg_) external override {
function updateClient(MsgUpdateClient calldata msg_) external override {
require(commitments[IBCCommitment.clientStateCommitmentKey(msg_.clientId)] != bytes32(0));
(bytes32 clientStateCommitment, ConsensusStateUpdate[] memory updates, bool ok) =
checkAndGetClient(msg_.clientId).updateClient(msg_.clientId, msg_.clientMessage);
Expand All @@ -73,36 +61,4 @@ contract IBCClient is IBCStore, IIBCClient {
nextClientSequence++;
return identifier;
}

/**
* @dev validateClientType validates the client type
* - clientType must be non-empty
* - clientType must be in the form of `^[a-z][a-z0-9-]*[a-z0-9]$`
*/
function validateClientType(bytes memory clientTypeBytes) internal pure returns (bool) {
if (clientTypeBytes.length == 0) {
return false;
}
unchecked {
for (uint256 i = 0; i < clientTypeBytes.length; i++) {
uint256 c = uint256(uint8(clientTypeBytes[i]));
if (0x61 <= c && c <= 0x7a) {
// a-z
continue;
} else if (c == 0x2d) {
// hyphen cannot be the first or last character
if (i == 0 || i == clientTypeBytes.length - 1) {
return false;
}
continue;
} else if (0x30 <= c && c <= 0x39) {
// 0-9
continue;
} else {
return false;
}
}
}
return true;
}
}
36 changes: 36 additions & 0 deletions contracts/core/02-client/IBCClientLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.9;

library IBCClientLib {
/**
* @dev validateClientType validates the client type
* - clientType must be non-empty
* - clientType must be in the form of `^[a-z][a-z0-9-]*[a-z0-9]$`
*/
function validateClientType(bytes memory clientTypeBytes) internal pure returns (bool) {
if (clientTypeBytes.length == 0) {
return false;
}
unchecked {
for (uint256 i = 0; i < clientTypeBytes.length; i++) {
uint256 c = uint256(uint8(clientTypeBytes[i]));
if (0x61 <= c && c <= 0x7a) {
// a-z
continue;
} else if (c == 0x2d) {
// hyphen cannot be the first or last character
if (i == 0 || i == clientTypeBytes.length - 1) {
return false;
}
continue;
} else if (0x30 <= c && c <= 0x39) {
// 0-9
continue;
} else {
return false;
}
}
}
return true;
}
}
2 changes: 1 addition & 1 deletion contracts/core/02-client/IBCHeight.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.9;

import "../../proto/Client.sol";
import {Height} from "../../proto/Client.sol";

library IBCHeight {
function toUint128(Height.Data memory self) internal pure returns (uint128) {
Expand Down
23 changes: 14 additions & 9 deletions contracts/core/02-client/IIBCClient.sol
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.9;

import "./ILightClient.sol";
import "../25-handler/IBCMsgs.sol";

interface IIBCClient {
/**
* @dev registerClient registers a new client type into the client registry
*/
function registerClient(string calldata clientType, ILightClient client) external;
struct MsgCreateClient {
string clientType;
bytes clientStateBytes;
bytes consensusStateBytes;
}

struct MsgUpdateClient {
string clientId;
bytes clientMessage;
}

event GeneratedClientIdentifier(string);

/**
* @dev createClient creates a new client state and populates it with a given consensus state
*/
function createClient(IBCMsgs.MsgCreateClient calldata msg_) external returns (string memory clientId);
function createClient(MsgCreateClient calldata msg_) external returns (string memory clientId);

/**
* @dev updateClient updates the consensus state and the state root from a provided header
*/
function updateClient(IBCMsgs.MsgUpdateClient calldata msg_) external;
function updateClient(MsgUpdateClient calldata msg_) external;
}
2 changes: 1 addition & 1 deletion contracts/core/02-client/ILightClient.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.9;

import "../../proto/Client.sol";
import {Height} from "../../proto/Client.sol";

/**
* @dev This defines an interface for Light Client contract can be integrated with ibc-solidity.
Expand Down
Loading

0 comments on commit 352dc59

Please sign in to comment.