Skip to content

Commit

Permalink
Merge pull request #259 from hyperledger-labs/04-upgrades
Browse files Browse the repository at this point in the history
Implement 04-upgrade spec

Signed-off-by: Jun Kimura <[email protected]>
  • Loading branch information
bluele authored Apr 16, 2024
2 parents aed4572 + f94b691 commit 3ccaf71
Show file tree
Hide file tree
Showing 42 changed files with 6,719 additions and 308 deletions.
98 changes: 59 additions & 39 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,51 +1,71 @@
IBCMockAppTest:testHandshake() (gas: 3433206)
IBCMockAppTest:testHandshakeBetweenDifferentPorts() (gas: 2539275)
IBCMockAppTest:testPacketRelay() (gas: 9417242)
IBCMockAppTest:testPacketTimeout() (gas: 2872300)
IBCTest:testBenchmarkCreateMockClient() (gas: 209365)
IBCMockAppTest:testHandshake() (gas: 3537520)
IBCMockAppTest:testHandshakeBetweenDifferentPorts() (gas: 2644408)
IBCMockAppTest:testPacketRelay() (gas: 9584548)
IBCMockAppTest:testPacketTimeout() (gas: 2981201)
IBCTest:testBenchmarkCreateMockClient() (gas: 209410)
IBCTest:testBenchmarkLCUpdateMockClient() (gas: 39945)
IBCTest:testBenchmarkRecvPacket() (gas: 129941)
IBCTest:testBenchmarkSendPacket() (gas: 81008)
IBCTest:testBenchmarkRecvPacket() (gas: 133353)
IBCTest:testBenchmarkSendPacket() (gas: 80964)
IBCTest:testBenchmarkUpdateMockClient() (gas: 137373)
IBCTest:testToUint128((uint64,uint64)) (runs: 256, μ: 947, ~: 947)
TestICS02:testCreateClient() (gas: 23070967)
TestICS02:testInvalidCreateClient() (gas: 22920564)
TestICS02:testInvalidUpdateClient() (gas: 22922411)
TestICS02:testRegisterClient() (gas: 22665440)
TestICS02:testRegisterClientDuplicatedClientType() (gas: 22648665)
TestICS02:testRegisterClientInvalidClientType() (gas: 22632794)
TestICS02:testUpdateClient() (gas: 23087963)
TestICS03Handshake:testConnOpenAck() (gas: 1631720)
TestICS03Handshake:testConnOpenConfirm() (gas: 1766228)
TestICS03Handshake:testConnOpenInit() (gas: 1279055)
TestICS03Handshake:testConnOpenTry() (gas: 2160823)
TestICS03Handshake:testInvalidConnOpenAck() (gas: 2031544)
TestICS03Handshake:testInvalidConnOpenConfirm() (gas: 2096106)
TestICS03Handshake:testInvalidConnOpenInit() (gas: 666816)
TestICS03Handshake:testInvalidConnOpenTry() (gas: 2101149)
TestICS02:testCreateClient() (gas: 33302626)
TestICS02:testInvalidCreateClient() (gas: 33152264)
TestICS02:testInvalidUpdateClient() (gas: 33154327)
TestICS02:testRegisterClient() (gas: 32897266)
TestICS02:testRegisterClientDuplicatedClientType() (gas: 32880491)
TestICS02:testRegisterClientInvalidClientType() (gas: 32864530)
TestICS02:testUpdateClient() (gas: 33319687)
TestICS03Handshake:testConnOpenAck() (gas: 1631658)
TestICS03Handshake:testConnOpenConfirm() (gas: 1766077)
TestICS03Handshake:testConnOpenInit() (gas: 1279190)
TestICS03Handshake:testConnOpenTry() (gas: 2160696)
TestICS03Handshake:testInvalidConnOpenAck() (gas: 2031548)
TestICS03Handshake:testInvalidConnOpenConfirm() (gas: 2095798)
TestICS03Handshake:testInvalidConnOpenInit() (gas: 666951)
TestICS03Handshake:testInvalidConnOpenTry() (gas: 2101089)
TestICS03Version:testCopyVersions() (gas: 558658)
TestICS03Version:testFindSupportedVersion() (gas: 19400)
TestICS03Version:testIsSupportedVersion() (gas: 7864)
TestICS03Version:testPickVersion() (gas: 25327)
TestICS03Version:testVerifyProposedVersion() (gas: 11777)
TestICS03Version:testVerifySupportedFeature() (gas: 4153)
TestICS04Handshake:testBindPort() (gas: 37414)
TestICS04Handshake:testChanClose() (gas: 8457966)
TestICS04Handshake:testChanOpenAck() (gas: 2879243)
TestICS04Handshake:testChanOpenConfirm() (gas: 3058457)
TestICS04Handshake:testChanOpenInit() (gas: 2195918)
TestICS04Handshake:testChanOpenTry() (gas: 2653852)
TestICS04Handshake:testInvalidChanOpenAck() (gas: 2060952)
TestICS04Handshake:testInvalidChanOpenConfirm() (gas: 2116580)
TestICS04Handshake:testInvalidChanOpenInit() (gas: 1275939)
TestICS04Handshake:testInvalidChanOpenTry() (gas: 1352198)
TestICS04Packet:testAcknowledgementPacket() (gas: 2276942)
TestICS04Packet:testInvalidSendPacket() (gas: 2274365)
TestICS04Packet:testRecvPacket() (gas: 7645640)
TestICS04Packet:testRecvPacketTimeoutHeight() (gas: 2295912)
TestICS04Packet:testRecvPacketTimeoutTimestamp() (gas: 2305786)
TestICS04Packet:testSendPacket() (gas: 5018609)
TestICS04Packet:testTimeoutOnClose() (gas: 2532922)
TestICS04Handshake:testBindPort() (gas: 37502)
TestICS04Handshake:testChanClose() (gas: 8864072)
TestICS04Handshake:testChanOpenAck() (gas: 2988216)
TestICS04Handshake:testChanOpenConfirm() (gas: 3170513)
TestICS04Handshake:testChanOpenInit() (gas: 2274533)
TestICS04Handshake:testChanOpenTry() (gas: 2759774)
TestICS04Handshake:testInvalidChanOpenAck() (gas: 2115402)
TestICS04Handshake:testInvalidChanOpenConfirm() (gas: 2171859)
TestICS04Handshake:testInvalidChanOpenInit() (gas: 1299857)
TestICS04Handshake:testInvalidChanOpenTry() (gas: 1378320)
TestICS04Packet:testAcknowledgementPacket() (gas: 2393006)
TestICS04Packet:testInvalidSendPacket() (gas: 2385887)
TestICS04Packet:testRecvPacket() (gas: 7941501)
TestICS04Packet:testRecvPacketTimeoutHeight() (gas: 2411677)
TestICS04Packet:testRecvPacketTimeoutTimestamp() (gas: 2421551)
TestICS04Packet:testSendPacket() (gas: 5160796)
TestICS04Packet:testTimeoutOnClose() (gas: 2654567)
TestICS04Upgrade:testUpgradeAuthorityCancel() (gas: 32899652)
TestICS04Upgrade:testUpgradeCannotCancelWithOldErrorReceipt() (gas: 2648059)
TestICS04Upgrade:testUpgradeCannotRecvNextUpgradePacket() (gas: 3322208)
TestICS04Upgrade:testUpgradeCounterpartyAdvanceNextSequenceBeforeOpen() (gas: 3402742)
TestICS04Upgrade:testUpgradeCrossingHelloIncompatibleProposals() (gas: 3312033)
TestICS04Upgrade:testUpgradeFull() (gas: 34308220)
TestICS04Upgrade:testUpgradeInit() (gas: 2362479)
TestICS04Upgrade:testUpgradeNoChanges() (gas: 1950920)
TestICS04Upgrade:testUpgradeOutOfSync() (gas: 3051844)
TestICS04Upgrade:testUpgradeRelaySuccessAtCounterpartyFlushComplete() (gas: 3325729)
TestICS04Upgrade:testUpgradeRelaySuccessAtFlushing() (gas: 3522672)
TestICS04Upgrade:testUpgradeSendPacketFailAtFlushingOrFlushComplete() (gas: 2743014)
TestICS04Upgrade:testUpgradeTimeoutAbortAck() (gas: 10509336)
TestICS04Upgrade:testUpgradeTimeoutAbortConfirm() (gas: 11912012)
TestICS04Upgrade:testUpgradeTimeoutUpgrade() (gas: 31027545)
TestICS04Upgrade:testUpgradeToOrdered() (gas: 36895593)
TestICS04Upgrade:testUpgradeToUnordered() (gas: 29370382)
TestICS04UpgradeApp:testUpgradeAuthorizationChanneNotFound() (gas: 37604)
TestICS04UpgradeApp:testUpgradeAuthorizationRePropose() (gas: 2034676)
TestICS04UpgradeApp:testUpgradeAuthorizationRemove() (gas: 1859258)
TestICS20:testAddressToHex(address) (runs: 256, μ: 22676, ~: 22804)
TestICS20:testHexToAddress(string) (runs: 256, μ: 4776, ~: 4734)
TestICS20:testIsEscapedString() (gas: 48979)
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ abigen: build
.PHONY: network-e2e
network-e2e:
$(DOCKER_COMPOSE) -f $(E2E_TEST_COMPOSE_FILE) up --detach --wait testchain0 testchain1
TEST_MNEMONIC=$(TEST_MNEMONIC) $(FORGE) script --legacy --slow --use solc:${SOLC_VERSION} --fork-url http://127.0.0.1:8645 --broadcast \
TEST_MNEMONIC=$(TEST_MNEMONIC) $(FORGE) script --legacy --batch-size 5 --use solc:${SOLC_VERSION} --fork-url http://127.0.0.1:8645 --broadcast \
./tests/foundry/src/Deploy.s.sol
TEST_MNEMONIC=$(TEST_MNEMONIC) $(FORGE) script --legacy --slow --use solc:${SOLC_VERSION} --fork-url http://127.0.0.1:8745 --broadcast \
TEST_MNEMONIC=$(TEST_MNEMONIC) $(FORGE) script --legacy --batch-size 5 --use solc:${SOLC_VERSION} --fork-url http://127.0.0.1:8745 --broadcast \
./tests/foundry/src/Deploy.s.sol

.PHONY: network-down
Expand Down
10 changes: 6 additions & 4 deletions contracts/apps/commons/IBCAppBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ import {Packet} from "../../core/04-channel/IIBCChannel.sol";
import {IIBCModule} from "../../core/26-router/IIBCModule.sol";
import {IIBCModuleErrors} from "../../core/26-router/IIBCModuleErrors.sol";

/**
* @dev Base contract of the IBC App protocol
*/
abstract contract IBCAppBase is Context, IIBCModule, IIBCModuleErrors {
abstract contract AppBase is Context, IIBCModuleErrors {
/**
* @dev Throws if called by any account other than the IBC contract.
*/
Expand All @@ -31,7 +28,12 @@ abstract contract IBCAppBase is Context, IIBCModule, IIBCModuleErrors {
revert IBCModuleInvalidSender(_msgSender());
}
}
}

/**
* @dev Base contract of the IBC App protocol
*/
abstract contract IBCAppBase is AppBase, IIBCModule {
/**
* @dev See IIBCModule-onChanOpenInit
*
Expand Down
5 changes: 3 additions & 2 deletions contracts/apps/mock/IBCMockApp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ contract IBCMockApp is IBCAppBase, IIBCMockErrors, Ownable {
function onRecvPacket(Packet calldata packet, address)
external
view
virtual
override
onlyIBC
returns (bytes memory acknowledgement)
Expand Down Expand Up @@ -126,13 +127,13 @@ contract IBCMockApp is IBCAppBase, IIBCMockErrors, Ownable {
}
}

function onTimeoutPacket(Packet calldata packet, address) external view override onlyIBC {
function onTimeoutPacket(Packet calldata packet, address) external view virtual override onlyIBC {
if (!closeChannelAllowed) {
revert IBCModuleChannelCloseNotAllowed(packet.sourcePort, packet.sourceChannel);
}
}

function equals(bytes calldata a, bytes memory b) private pure returns (bool) {
function equals(bytes calldata a, bytes memory b) internal pure returns (bool) {
return keccak256(a) == keccak256(b);
}
}
2 changes: 1 addition & 1 deletion contracts/clients/LocalhostClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ contract LocalhostClient is ILightClient, ILightClientErrors {
ClientState.Data({
latest_height: Height.Data({revision_number: 0, revision_height: uint64(block.number)})
})
),
),
true
);
}
Expand Down
13 changes: 13 additions & 0 deletions contracts/core/03-connection/IBCConnectionLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ library IBCConnectionLib {
return verifyProposedVersion(supportedVersion, version);
}

function isSupported(Version.Data[] storage supportedVersions, string memory feature)
internal
view
returns (bool)
{
for (uint256 i = 0; i < supportedVersions.length; i++) {
if (verifySupportedFeature(supportedVersions[i], feature)) {
return true;
}
}
return false;
}

/**
* @dev verifyProposedVersion verifies that the entire feature set in the
* proposed version is supported by this chain. If the feature set is
Expand Down
14 changes: 10 additions & 4 deletions contracts/core/04-channel/IBCChannelHandshake.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ contract IBCChannelHandshake is IBCModuleManager, IIBCChannelHandshake, IIBCChan
ordering: msg_.channel.ordering,
counterparty: ChannelCounterparty.Data({port_id: msg_.portId, channel_id: ""}),
connection_hops: getCounterpartyHops(msg_.channel.connection_hops[0]),
version: msg_.counterpartyVersion
version: msg_.counterpartyVersion,
upgrade_sequence: 0
});
verifyChannelState(
connection,
Expand Down Expand Up @@ -166,7 +167,8 @@ contract IBCChannelHandshake is IBCModuleManager, IIBCChannelHandshake, IIBCChan
ordering: channel.ordering,
counterparty: ChannelCounterparty.Data({port_id: msg_.portId, channel_id: msg_.channelId}),
connection_hops: getCounterpartyHops(channel.connection_hops[0]),
version: msg_.counterpartyVersion
version: msg_.counterpartyVersion,
upgrade_sequence: 0
});

verifyChannelState(
Expand Down Expand Up @@ -204,7 +206,8 @@ contract IBCChannelHandshake is IBCModuleManager, IIBCChannelHandshake, IIBCChan
ordering: channel.ordering,
counterparty: ChannelCounterparty.Data({port_id: msg_.portId, channel_id: msg_.channelId}),
connection_hops: getCounterpartyHops(channel.connection_hops[0]),
version: channel.version
version: channel.version,
upgrade_sequence: 0
});
verifyChannelState(
connection,
Expand Down Expand Up @@ -264,7 +267,8 @@ contract IBCChannelHandshake is IBCModuleManager, IIBCChannelHandshake, IIBCChan
ordering: channel.ordering,
counterparty: ChannelCounterparty.Data({port_id: msg_.portId, channel_id: msg_.channelId}),
connection_hops: getCounterpartyHops(channel.connection_hops[0]),
version: channel.version
version: channel.version,
upgrade_sequence: 0
});
verifyChannelState(
connection,
Expand Down Expand Up @@ -301,6 +305,7 @@ contract IBCChannelHandshake is IBCModuleManager, IIBCChannelHandshake, IIBCChan
channel.connection_hops.push(connectionHops[i]);
}
channel.version = version;
channel.upgrade_sequence = 0;
updateChannelCommitment(portId, channelId);
}

Expand Down Expand Up @@ -344,6 +349,7 @@ contract IBCChannelHandshake is IBCModuleManager, IIBCChannelHandshake, IIBCChan
nextSequenceSends[portId][channelId] = 1;
nextSequenceRecvs[portId][channelId] = 1;
nextSequenceAcks[portId][channelId] = 1;
recvStartSequences[portId][channelId].sequence = 1;
commitments[IBCCommitment.nextSequenceRecvCommitmentKey(portId, channelId)] =
keccak256(abi.encodePacked((bytes8(uint64(1)))));
}
Expand Down
6 changes: 6 additions & 0 deletions contracts/core/04-channel/IBCChannelLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ library IBCChannelLib {
}
}

function buildConnectionHops(string memory connectionId) internal pure returns (string[] memory hops) {
hops = new string[](1);
hops[0] = connectionId;
return hops;
}

function toString(Channel.Order order) internal pure returns (string memory) {
if (order == Channel.Order.ORDER_UNORDERED) {
return ORDER_UNORDERED;
Expand Down
44 changes: 36 additions & 8 deletions contracts/core/04-channel/IBCChannelPacketSendRecv.sol
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,20 @@ contract IBCChannelPacketSendRecv is
*/
function recvPacket(MsgPacketRecv calldata msg_) external {
Channel.Data storage channel = channels[msg_.packet.destinationPort][msg_.packet.destinationChannel];
if (channel.state != Channel.State.STATE_OPEN) {
if (channel.state == Channel.State.STATE_OPEN) {} else if (
channel.state == Channel.State.STATE_FLUSHING || channel.state == Channel.State.STATE_FLUSHCOMPLETE
) {
RecvStartSequence storage rseq =
recvStartSequences[msg_.packet.destinationPort][msg_.packet.destinationChannel];
// prevSequence=0 means the channel is not in the process of being upgraded or counterparty has not been upgraded yet
if (rseq.prevSequence != 0) {
if (msg_.packet.sequence >= rseq.sequence) {
revert IBCChannelCannotRecvNextUpgradePacket(msg_.packet.sequence, rseq.sequence);
} else if (msg_.packet.sequence < rseq.prevSequence) {
revert IBCChannelPacketAlreadyProcessInPreviousUpgrade(msg_.packet.sequence, rseq.prevSequence);
}
}
} else {
revert IBCChannelUnexpectedChannelState(channel.state);
}

Expand Down Expand Up @@ -155,6 +168,17 @@ contract IBCChannelPacketSendRecv is
);

if (channel.ordering == Channel.Order.ORDER_UNORDERED) {
if (channel.state == Channel.State.STATE_OPEN) {
if (
msg_.packet.sequence
< recvStartSequences[msg_.packet.destinationPort][msg_.packet.destinationChannel].sequence
) {
revert IBCChannelPacketAlreadyProcessInPreviousUpgrade(
msg_.packet.sequence,
recvStartSequences[msg_.packet.destinationPort][msg_.packet.destinationChannel].sequence
);
}
}
bytes32 commitmentKey = IBCCommitment.packetReceiptCommitmentKeyCalldata(
msg_.packet.destinationPort, msg_.packet.destinationChannel, msg_.packet.sequence
);
Expand Down Expand Up @@ -202,7 +226,9 @@ contract IBCChannelPacketSendRecv is
function acknowledgePacket(MsgPacketAcknowledgement calldata msg_) external {
Channel.Data storage channel = channels[msg_.packet.sourcePort][msg_.packet.sourceChannel];
if (channel.state != Channel.State.STATE_OPEN) {
revert IBCChannelUnexpectedChannelState(channel.state);
if (channel.state != Channel.State.STATE_FLUSHING) {
revert IBCChannelUnexpectedChannelState(channel.state);
}
}

if (keccak256(bytes(msg_.packet.destinationPort)) != keccak256(bytes(channel.counterparty.port_id))) {
Expand Down Expand Up @@ -258,6 +284,14 @@ contract IBCChannelPacketSendRecv is
);
}
nextSequenceAcks[msg_.packet.sourcePort][msg_.packet.sourceChannel]++;
} else if (channel.ordering == Channel.Order.ORDER_UNORDERED) {
if (msg_.packet.sequence < ackStartSequences[msg_.packet.sourcePort][msg_.packet.sourceChannel]) {
revert IBCChannelAckAlreadyProcessedInPreviousUpgrade(
msg_.packet.sequence, ackStartSequences[msg_.packet.sourcePort][msg_.packet.sourceChannel]
);
}
} else {
revert IBCChannelUnknownChannelOrder(channel.ordering);
}

delete commitments[packetCommitmentKey];
Expand Down Expand Up @@ -331,12 +365,6 @@ contract IBCChannelPacketSendRecv is
}
}

function buildConnectionHops(string memory connectionId) private pure returns (string[] memory hops) {
hops = new string[](1);
hops[0] = connectionId;
return hops;
}

function uint64ToBigEndianBytes(uint64 v) private pure returns (bytes memory) {
return abi.encodePacked(bytes8(v));
}
Expand Down
12 changes: 4 additions & 8 deletions contracts/core/04-channel/IBCChannelPacketTimeout.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {ConnectionEnd} from "../../proto/Connection.sol";
import {Channel, ChannelCounterparty} from "../../proto/Channel.sol";
import {ILightClient} from "../02-client/ILightClient.sol";
import {IBCHeight} from "../02-client/IBCHeight.sol";
import {IBCChannelLib} from "./IBCChannelLib.sol";
import {IBCCommitment} from "../24-host/IBCCommitment.sol";
import {IBCModuleManager} from "../26-router/IBCModuleManager.sol";
import {IIBCChannelPacketTimeout} from "./IIBCChannel.sol";
Expand Down Expand Up @@ -182,8 +183,9 @@ contract IBCChannelPacketTimeout is IBCModuleManager, IIBCChannelPacketTimeout,
port_id: msg_.packet.sourcePort,
channel_id: msg_.packet.sourceChannel
}),
connection_hops: buildConnectionHops(connection.counterparty.connection_id),
version: channel.version
connection_hops: IBCChannelLib.buildConnectionHops(connection.counterparty.connection_id),
version: channel.version,
upgrade_sequence: msg_.counterpartyUpgradeSequence
});
if (
!client.verifyMembership(
Expand Down Expand Up @@ -276,12 +278,6 @@ contract IBCChannelPacketTimeout is IBCModuleManager, IIBCChannelPacketTimeout,
}
}

function buildConnectionHops(string memory connectionId) private pure returns (string[] memory hops) {
hops = new string[](1);
hops[0] = connectionId;
return hops;
}

function uint64ToBigEndianBytes(uint64 v) private pure returns (bytes memory) {
return abi.encodePacked(bytes8(v));
}
Expand Down
Loading

0 comments on commit 3ccaf71

Please sign in to comment.