Skip to content

Commit

Permalink
feat: hash depending on client type
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonAndell committed Feb 12, 2024
1 parent 95c1ed8 commit dc07e0d
Show file tree
Hide file tree
Showing 312 changed files with 21,403 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ibc.icon.score.util.Logger;
import ibc.icon.score.util.NullChecker;
import ibc.ics24.host.IBCHost;
import ibc.ics24.host.IBCStore;
import icon.ibc.interfaces.ILightClient;
import icon.ibc.structs.messages.MsgCreateClient;
import icon.ibc.structs.messages.MsgUpdateClient;
Expand All @@ -16,9 +17,10 @@ public class IBCClient extends IBCHost {

static Logger logger = new Logger("ibc-core");

public void registerClient(String clientType, Address lightClient) {
public void registerClient(String clientType, Address lightClient, int hashType) {
Context.require(clientRegistry.get(clientType) == null, "Already registered.");
clientRegistry.set(clientType, lightClient);
IBCStore.hashType.set(clientType, hashType);
}

public String _createClient(MsgCreateClient msg) {
Expand All @@ -32,6 +34,7 @@ public String _createClient(MsgCreateClient msg) {
clientTypes.set(clientId, msg.getClientType());
clientImplementations.set(clientId, lightClientAddr);
btpNetworkId.set(clientId, msg.getBtpNetworkId());
// hashMethod.set(clientId, msg.getHashMethod());

ILightClient client = getClient(clientId);
client.createClient(clientId, msg.getClientState(), msg.getConsensusState());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ibc.icon.score.util.ByteUtil;
import ibc.icon.score.util.Proto;
import ibc.ics24.host.IBCCommitment;
import ibc.ics24.host.IBCHost;
import icon.ibc.interfaces.ILightClient;
import icon.ibc.structs.messages.MsgRequestTimeoutPacket;
import score.Context;
Expand Down Expand Up @@ -58,7 +59,7 @@ public void _sendPacket(Packet packet) {
packet.getSourceChannel(),
packet.getSequence());

byte[] packetCommitment = createPacketCommitment(packet);
byte[] packetCommitment = createPacketCommitment(connection.getClientId(), packet);
commitments.set(packetCommitmentKey, packetCommitment);
packetHeights.at(packet.getSourcePort()).at(packet.getSourceChannel()).set(packet.getSequence(),
Context.getBlockHeight());
Expand Down Expand Up @@ -99,7 +100,7 @@ public void _recvPacket(Packet packet, byte[] proof, byte[] proofHeight) {

byte[] commitmentPath = IBCCommitment.packetCommitmentPath(packet.getSourcePort(),
packet.getSourceChannel(), packet.getSequence());
byte[] commitmentBytes = createPacketCommitmentBytes(packet);
byte[] commitmentBytes = createPacketCommitmentBytes(connection.getClientId(), packet);

verifyPacketCommitment(
connection,
Expand Down Expand Up @@ -145,7 +146,7 @@ public void _writeAcknowledgement(String destinationPortId, String destinationCh
byte[] ackCommitmentKey = IBCCommitment.packetAcknowledgementCommitmentKey(destinationPortId,
destinationChannel, sequence);
Context.require(commitments.get(ackCommitmentKey) == null, "acknowledgement for packet already exists");
byte[] ackCommitment = IBCCommitment.keccak256(acknowledgement);
byte[] ackCommitment = createAcknowledgmentCommitment(connection.getClientId(), acknowledgement);
commitments.set(ackCommitmentKey, ackCommitment);
ackHeights.at(destinationPortId).at(destinationChannel).set(sequence,
Context.getBlockHeight());
Expand Down Expand Up @@ -174,7 +175,7 @@ public void _acknowledgePacket(Packet packet, byte[] acknowledgement, byte[] pro
packet.getSourceChannel(), packet.getSequence());
byte[] packetCommitment = commitments.get(packetCommitmentKey);
Context.require(packetCommitment != null, "packet commitment not found");
byte[] commitment = createPacketCommitment(packet);
byte[] commitment = createPacketCommitment(connection.getClientId(), packet);

Context.require(Arrays.equals(packetCommitment, commitment), "commitment byte[] are not equal");

Expand Down Expand Up @@ -236,7 +237,7 @@ public void _requestTimeout(MsgRequestTimeoutPacket msg) {

byte[] commitmentPath = IBCCommitment.packetCommitmentPath(packet.getSourcePort(),
packet.getSourceChannel(), packet.getSequence());
byte[] commitmentBytes = createPacketCommitmentBytes(packet);
byte[] commitmentBytes = createPacketCommitmentBytes(connection.getClientId(), packet);
verifyPacketCommitment(
connection,
proofHeight,
Expand Down Expand Up @@ -300,7 +301,7 @@ public void _timeoutPacket(Packet packet, byte[] proofHeight, byte[] proof, BigI
packet.getSourceChannel(), packet.getSequence());
byte[] packetCommitment = commitments.get(packetCommitmentKey);
Context.require(packetCommitment != null, "packet commitment not found");
byte[] commitment = createPacketCommitment(packet);
byte[] commitment = createPacketCommitment(connection.getClientId(), packet);

Context.require(Arrays.equals(packetCommitment, commitment), "commitment byte[] are not equal");

Expand Down Expand Up @@ -432,11 +433,20 @@ private BigInteger calcBlockDelay(BigInteger timeDelay) {
return blockDelay;
}

private byte[] createPacketCommitment(Packet packet) {
return IBCCommitment.keccak256(createPacketCommitmentBytes(packet));
private byte[] createPacketCommitment(String clientId, Packet packet) {
return IBCCommitment.keccak256(createPacketCommitmentBytes(clientId, packet));
}

public static byte[] createPacketCommitmentBytes(Packet packet) {
private byte[] createPacketCommitmentBytes(String clientId, Packet packet) {
int hashType = IBCCommitment.getHashType(clientId);
if (hashType == IBCHost.HashType.ICS08.type) {
return createIBCPacketCommitmentBytes(packet);
}

return createWasmPacketCommitmentBytes(packet);
}

public static byte[] createWasmPacketCommitmentBytes(Packet packet) {
return ByteUtil.join(
Proto.encodeFixed64(packet.getTimeoutTimestamp(), false),
Proto.encodeFixed64(packet.getTimeoutHeight().getRevisionNumber(),
Expand All @@ -446,6 +456,29 @@ public static byte[] createPacketCommitmentBytes(Packet packet) {
IBCCommitment.keccak256(packet.getData()));
}

public static byte[] createIBCPacketCommitmentBytes(Packet packet) {
return IBCCommitment.sha256(ByteUtil.join(
Proto.encodeFixed64(packet.getTimeoutTimestamp(), false),
Proto.encodeFixed64(packet.getTimeoutHeight().getRevisionNumber(),
false),
Proto.encodeFixed64(packet.getTimeoutHeight().getRevisionHeight(),
false),
IBCCommitment.sha256(packet.getData())));
}

private byte[] createAcknowledgmentCommitment(String clientId, byte[] ack) {
return IBCCommitment.keccak256(createAcknowledgmentCommitmentBytes(clientId, ack));
}

public static byte[] createAcknowledgmentCommitmentBytes(String clientId, byte[] ack) {
int hashType = IBCCommitment.getHashType(clientId);
if (hashType == IBCHost.HashType.ICS08.type) {
return IBCCommitment.sha256(ack);
}

return ack;
}

private boolean lt(Height h1, Height h2) {
return h1.getRevisionNumber().compareTo(h2.getRevisionNumber()) < 0
|| (h1.getRevisionNumber().equals(h2.getRevisionNumber())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ public class Merkle {
Proof.getTendermintSpec()
);

public static MerklePath applyPrefix(String path) {
public static MerklePath applyPrefix(String path, String prefix) {
var mpath = new MerklePath();
List<String> keyPath = new ArrayList<>();
keyPath.add(StringUtil.bytesToHex("wasm".getBytes()));
keyPath.add(prefix);
keyPath.add(path);
mpath.setKeyPath(keyPath);
return mpath;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
* "https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements#path-space">path-space</a>
*/
public class IBCCommitment {
private static final String KECCAK256 = "keccak-256";
private static final String SHA256 = "sha-256";
public static final String KECCAK256 = "keccak-256";
public static final String SHA256 = "sha-256";

public static byte[] keccak256(byte[] msg) {
return Context.hash(KECCAK256, msg);
Expand All @@ -22,6 +22,11 @@ public static byte[] sha256(byte[] msg) {
return Context.hash(SHA256, msg);
}

public static int getHashType(String clientId) {
String clientType = IBCStore.clientTypes.get(clientId);
return IBCStore.hashType.getOrDefault(clientType, IBCHost.HashType.WASM.type);
}

public static byte[] clientStatePath(String clientId) {
return StringUtil.encodePacked("clients/", clientId, "/clientState");
}
Expand Down
19 changes: 19 additions & 0 deletions contracts/javascore/ibc/src/main/java/ibc/ics24/host/IBCHost.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@ public class IBCHost extends IBCStore {
private static final String TAG = "IBCHOST: ";
private static final Address chainScore = Address.fromString("cx0000000000000000000000000000000000000000");

public enum HashType {
WASM(0),
ICS08(1);

public final int type;
HashType(int type){ this.type = type; }

public int type() { return type; }

static public HashType of(int type) {
for(HashType t : values()) {
if (t.type == type) {
return t;
}
}
throw new IllegalArgumentException();
}
}

/***
* claimCapability allows the IBC app module to claim a capability that core IBC
* passes to it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public abstract class IBCStore extends ModuleManager implements IIBCHost {
private static final String BTP_NETWORK_ID = "btpNetworkId";
private static final String TIMEOUT_REQUESTS = "timeout_requests";
private static final String ACK_HEIGHTS = "ackHeights";
private static final String HASH_METHOD = "hashMethod";

// DB Variables
// Commitments
Expand Down Expand Up @@ -81,6 +82,8 @@ public abstract class IBCStore extends ModuleManager implements IIBCHost {
public static final DictDB<String, Integer> btpNetworkId = Context.newDictDB(BTP_NETWORK_ID, Integer.class);
public static final DictDB<byte[], Boolean> timeoutRequests = Context.newDictDB(TIMEOUT_REQUESTS, Boolean.class);

public static final DictDB<String, Integer> hashType = Context.newDictDB(HASH_METHOD, Integer.class);

@External(readonly = true)
public byte[] getCommitment(byte[] key) {
return commitments.get(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import score.Address;
import score.Context;
import score.annotation.External;
import score.annotation.Optional;

import java.math.BigInteger;

import ibc.ics24.host.IBCHost;
import icon.ibc.structs.messages.MsgCreateClient;

public class IBCHandler extends IBCHandlerPacket {
Expand All @@ -24,9 +26,10 @@ public String name() {
* registerClient registers a new client type into the client registry
*/
@External
public void registerClient(String clientType, Address client) {
public void registerClient(String clientType, Address client, @Optional int hashType) {
onlyOwner();
super.registerClient(clientType, client);
IBCHost.HashType.of(hashType);
super.registerClient(clientType, client, hashType);
}

@External
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ public void setup() throws Exception {
void registerClient_alreadyRegistered() {
// Arrange
String clientType = "clientType";
client.invoke(owner, "registerClient", clientType, lightClient.getAddress());
client.invoke(owner, "registerClient", clientType, lightClient.getAddress(), 0);

// Act & Assert
String expectedErrorMessage = "Already registered";
Executable registerWithSameType = () -> {
client.invoke(owner, "registerClient", clientType,
lightClient.getAddress());
lightClient.getAddress(), 0);
};
AssertionError e = assertThrows(AssertionError.class, registerWithSameType);
assertTrue(e.getMessage().contains(expectedErrorMessage));
Expand Down Expand Up @@ -85,7 +85,7 @@ void createClient() {
String expectedClientId = msg.getClientType() + "-0";

// Act
client.invoke(owner, "registerClient", msg.getClientType(), lightClient.getAddress());
client.invoke(owner, "registerClient", msg.getClientType(), lightClient.getAddress(), 0);
client.invoke(owner, "_createClient", msg);

// Assert
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package ibc.ics04.channel;

import static ibc.ics04.channel.IBCPacket.createPacketCommitmentBytes;
import static ibc.ics04.channel.IBCPacket.createWasmPacketCommitmentBytes;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
Expand Down Expand Up @@ -405,7 +405,7 @@ void recvPacket_outOfOrder_UnOrdered() {
basePacket.getSourceChannel(), basePacket.getSequence());
byte[] commitmentPath2 = IBCCommitment.packetCommitmentPath(basePacket.getSourcePort(),
basePacket.getSourceChannel(), basePacket.getSequence().add(BigInteger.ONE));
byte[] commitmentBytes = createPacketCommitmentBytes(basePacket);
byte[] commitmentBytes = createWasmPacketCommitmentBytes(basePacket);

// Act
basePacket.setSequence(BigInteger.TWO);
Expand Down Expand Up @@ -450,7 +450,7 @@ void recvPacket_UnOrdered() {

byte[] commitmentPath = IBCCommitment.packetCommitmentPath(basePacket.getSourcePort(),
basePacket.getSourceChannel(), basePacket.getSequence());
byte[] commitmentBytes = createPacketCommitmentBytes(basePacket);
byte[] commitmentBytes = createWasmPacketCommitmentBytes(basePacket);

// Act
packet.invoke(owner, "_recvPacket", basePacket, proof, proofHeight.encode());
Expand All @@ -470,7 +470,7 @@ void recvPacket_Ordered() {

byte[] commitmentPath = IBCCommitment.packetCommitmentPath(basePacket.getSourcePort(),
basePacket.getSourceChannel(), basePacket.getSequence());
byte[] commitmentBytes = createPacketCommitmentBytes(basePacket);
byte[] commitmentBytes = createWasmPacketCommitmentBytes(basePacket);

// Act
packet.invoke(owner, "_recvPacket", basePacket, proof, proofHeight.encode());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ void setExpectedTimePerBlock() throws Exception {
void handlerAdminPermissions() {
// TODO: should be a admin and not a owner.
assertOnlyCallableBy(owner, "bindPort", portId);
assertOnlyCallableBy(owner, "registerClient", clientType, lightClient.getAddress());
assertOnlyCallableBy(owner, "registerClient", clientType, lightClient.getAddress(), 0);
assertOnlyCallableBy(owner, "setExpectedTimePerBlock", BigInteger.TWO);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ protected void setup() throws Exception {

void createClient() {
// Arrange
handler.invoke(owner, "registerClient", clientType, lightClient.getAddress());
handler.invoke(owner, "registerClient", clientType, lightClient.getAddress(), 0);
MsgCreateClient msg = new MsgCreateClient();
msg.setClientState(new byte[0]);
msg.setConsensusState(new byte[0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import icon.ibc.structs.messages.MsgUpdateClient;
import score.Address;
import score.annotation.EventLog;
import score.annotation.Optional;

@ScoreClient
public interface IIBCClient {
Expand All @@ -19,8 +20,9 @@ public interface IIBCClient {
* {@code @dev} registerClient registers a new client type into the client registry
* @param clientType Type of client
* @param lightClient Light client contract address
* @param hashType Optional hashType (WASM or ICS08) default WASM
*/
void registerClient(String clientType, Address client);
void registerClient(String clientType, Address client, @Optional int hashType);

/**
* {@code @dev} createClient creates a new client state and populates it with a given
Expand Down
Loading

0 comments on commit dc07e0d

Please sign in to comment.