Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

807 add client specific hashing on ack and packet data #825

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ static void setup() throws Exception {
@Test
@Order(0)
void registerClient() {
getClientInterface(owner).registerClient(clientType, mockLightClient._address());
getClientInterface(owner).registerClient(clientType, mockLightClient._address(), 0);
}

@Test
Expand Down
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
@@ -1,17 +1,18 @@
package ibc.ics03.connection;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;

import icon.proto.core.client.Height;
import icon.proto.core.connection.ConnectionEnd;
import icon.proto.core.connection.Counterparty;
import icon.proto.core.connection.Version;
import ibc.core.commitment.v1.MerklePrefix;
import ibc.icon.score.util.ByteUtil;
import ibc.icon.score.util.Logger;
import ibc.ics02.client.IBCClient;
import ibc.ics24.host.IBCCommitment;
import ibc.ics24.host.IBCHost;
import icon.ibc.interfaces.ILightClient;
import icon.ibc.structs.messages.MsgConnectionOpenAck;
import icon.ibc.structs.messages.MsgConnectionOpenConfirm;
Expand All @@ -24,6 +25,12 @@ public class IBCConnection extends IBCClient {
public static final String v1Identifier = "1";
public static final List<String> supportedV1Features = List.of("ORDER_ORDERED", "ORDER_UNORDERED");

public static final MerklePrefix ICS08PREFIX = new MerklePrefix();
static {
ICS08PREFIX.setKeyPrefix("ibc".getBytes());

}

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

public String _connectionOpenInit(MsgConnectionOpenInit msg) {
Expand Down Expand Up @@ -67,6 +74,9 @@ public String _connectionOpenTry(MsgConnectionOpenTry msg) {
Counterparty expectedCounterparty = new Counterparty();
expectedCounterparty.setClientId(msg.getClientId());
expectedCounterparty.setConnectionId("");
if (IBCCommitment.getHashType(msg.getClientId()) == IBCHost.HashType.ICS08.type) {
expectedCounterparty.setPrefix(ICS08PREFIX);
}

ConnectionEnd expectedConnection = new ConnectionEnd();
expectedConnection.setClientId(counterparty.getClientId());
Expand Down Expand Up @@ -108,6 +118,9 @@ public byte[] _connectionOpenAck(MsgConnectionOpenAck msg) {
Counterparty expectedCounterparty = new Counterparty();
expectedCounterparty.setClientId(connection.getClientId());
expectedCounterparty.setConnectionId(msg.getConnectionId());
if (IBCCommitment.getHashType(connection.getClientId()) == IBCHost.HashType.ICS08.type) {
expectedCounterparty.setPrefix(ICS08PREFIX);
}

ConnectionEnd expectedConnection = new ConnectionEnd();
expectedConnection.setClientId(connection.getCounterparty().getClientId());
Expand Down Expand Up @@ -150,6 +163,9 @@ public byte[] _connectionOpenConfirm(MsgConnectionOpenConfirm msg) {
Counterparty expectedCounterparty = new Counterparty();
expectedCounterparty.setClientId(connection.getClientId());
expectedCounterparty.setConnectionId(msg.getConnectionId());
if (IBCCommitment.getHashType(connection.getClientId()) == IBCHost.HashType.ICS08.type) {
expectedCounterparty.setPrefix(ICS08PREFIX);
}

ConnectionEnd expectedConnection = new ConnectionEnd();
expectedConnection.setClientId(connection.getCounterparty().getClientId());
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,18 +175,19 @@ 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");

byte[] packetAckPath = IBCCommitment.packetAcknowledgementCommitmentPath(packet.getDestinationPort(),
packet.getDestinationChannel(), packet.getSequence());
byte[] commitmentBytes = createAcknowledgmentCommitmentBytes(connection.getClientId(), acknowledgement);
verifyPacketAcknowledgement(
connection,
proofHeight,
proof,
packetAckPath,
acknowledgement);
commitmentBytes);

if (channel.getOrdering() == Channel.Order.ORDER_ORDERED) {
DictDB<String, BigInteger> nextSequenceAckSourcePort = nextSequenceAcknowledgements
Expand Down Expand Up @@ -236,7 +238,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 +302,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 +434,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));
}

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[] createPacketCommitmentBytes(Packet packet) {
public static byte[] createWasmPacketCommitmentBytes(Packet packet) {
return ByteUtil.join(
Proto.encodeFixed64(packet.getTimeoutTimestamp(), false),
Proto.encodeFixed64(packet.getTimeoutHeight().getRevisionNumber(),
Expand All @@ -446,6 +457,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 prefix, String path) {
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
Loading
Loading