Skip to content

Commit

Permalink
feat: add IBC prefix for ics-08 clients and bugfixes (#826)
Browse files Browse the repository at this point in the history
* feat: Add revision number to light client heights

Add revision number but for now do not add support for resseting chain height

* revert to using two clients

* feat: add IBC prefix for ics-08 clients and bugfixes

* fix: hash ack value before sending to verify membership for ics8 client

---------

Co-authored-by: izyak <lbackup887@gmail.com>
  • Loading branch information
AntonAndell and izyak authored Feb 12, 2024
1 parent 7d0585a commit a7af666
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 8 deletions.
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
@@ -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 @@ -181,12 +181,13 @@ public void _acknowledgePacket(Packet packet, byte[] acknowledgement, byte[] pro

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
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class Merkle {
Proof.getTendermintSpec()
);

public static MerklePath applyPrefix(String path, String prefix) {
public static MerklePath applyPrefix(String prefix, String path) {
var mpath = new MerklePath();
List<String> keyPath = new ArrayList<>();
keyPath.add(prefix);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static BigInteger getTotalVotingPower(ValidatorSet validatorSet) {
}

public static BigInteger getRevisionNumber(String chainId) {
int id = chainId.indexOf("-");
int id = chainId.lastIndexOf("-");
if (id >= 0) {
return new BigInteger(chainId.substring(id+1));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public void verifyMembership(

var root = consensusState.getRoot();
var merkleProof = MerkleProof.decode(proof);
var merklePath = applyPrefix(new String(path), StringUtil.bytesToHex("wasm".getBytes()));
var merklePath = applyPrefix(StringUtil.bytesToHex("wasm".getBytes()), new String(path));

Merkle.verifyMembership(merkleProof, Merkle.SDK_SPEC, root, merklePath, value);
}
Expand All @@ -240,7 +240,7 @@ public void verifyNonMembership(

var root = consensusState.getRoot();
var merkleProof = MerkleProof.decode(proof);
var merklePath = applyPrefix(new String(path), StringUtil.bytesToHex("wasm".getBytes()));
var merklePath = applyPrefix(StringUtil.bytesToHex("wasm".getBytes()), new String(path));

Merkle.verifyNonMembership(merkleProof, Merkle.SDK_SPEC, root, merklePath);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public static byte[] encodeBooleanArray(int order, List<Boolean> items) {
}

public static byte[] encode(int order, Boolean item) {
if (item == null) {
if (item == null || item == false) {
return new byte[0];
}

Expand Down
206 changes: 206 additions & 0 deletions proto/clients/tendermint/TendermintLight.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
syntax = "proto3";
package tendermint.light;

option go_package = "libraries/go/common/tendermint;tendermint";
import "gogoproto/gogo.proto";

message Fraction {
uint64 numerator = 1;
uint64 denominator = 2;
}

// https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp
message Duration {
int64 seconds = 1;
int32 nanos = 2;
}

message Consensus {
uint64 block = 1;
uint64 app = 2;
}

message ClientState {
option (gogoproto.goproto_getters) = false;

string chain_id = 1;
Fraction trust_level = 2;

// duration of the period since the LastestTimestamp during which the
// submitted headers are valid for upgrade
Duration trusting_period = 3;
// duration of the staking unbonding period
Duration unbonding_period = 4;
// defines how much new (untrusted) header's Time can drift into the future.
Duration max_clock_drift = 5;
// Block height when the client was frozen due to a misbehaviour
//ibc.core.client.v1.Height frozen_height = 6;
int64 frozen_height = 6;
// Latest height the client was updated to
int64 latest_height = 7;
// This flag, when set to true, will allow governance to recover a client
// which has expired
bool allow_update_after_expiry = 8;
// This flag, when set to true, will allow governance to unfreeze a client
// whose chain has experienced a misbehaviour event
bool allow_update_after_misbehaviour = 9;
}

// ConsensusState defines the consensus state from Tendermint.
message ConsensusState {
option (gogoproto.goproto_getters) = false;
// timestamp that corresponds to the block height in which the ConsensusState
// was stored.
Timestamp timestamp = 1;

// commitment root (i.e app hash)
MerkleRoot root = 2;
bytes next_validators_hash = 3;
}

// MerkleRoot defines a merkle root hash.
// In the Cosmos SDK, the AppHash of a block header becomes the root.
message MerkleRoot {
bytes hash = 1;
}

enum BlockIDFlag {
BLOCK_ID_FLAG_UNKNOWN = 0;
BLOCK_ID_FLAG_ABSENT = 1;
BLOCK_ID_FLAG_COMMIT = 2;
BLOCK_ID_FLAG_NIL = 3;
}

enum SignedMsgType {
SIGNED_MSG_TYPE_UNKNOWN = 0;
// Votes
SIGNED_MSG_TYPE_PREVOTE = 1;
SIGNED_MSG_TYPE_PRECOMMIT = 2;

// Proposals
SIGNED_MSG_TYPE_PROPOSAL = 32;
}

message CanonicalPartSetHeader {
uint32 total = 1;
bytes hash = 2;
}

message CanonicalBlockID {
bytes hash = 1;
CanonicalPartSetHeader part_set_header = 2;
}

message CanonicalVote {
SignedMsgType type = 1;
sfixed64 height = 2;
sfixed64 round = 3;
BlockID block_id = 4;
Timestamp timestamp = 5;
string chain_id = 6;
}

message Vote {
SignedMsgType type = 1;
int64 height = 2;
int32 round = 3;
BlockID block_id = 4;
Timestamp timestamp = 5;
bytes validator_address = 6;
int32 validator_index = 7;
bytes signature = 8;
}

message ValidatorSet {
repeated Validator validators = 1;
Validator proposer = 2;
int64 total_voting_power = 3;
}

message Validator {
bytes address = 1;
PublicKey pub_key = 2;
int64 voting_power = 3;
int64 proposer_priority = 4;
}

message SimpleValidator {
PublicKey pub_key = 1;
int64 voting_power = 2;
}

message PublicKey {
oneof sum {
bytes ed25519 = 1;
bytes secp256k1 = 2;
bytes sr25519 = 3;
}
}

message PartSetHeader {
uint32 total = 1;
bytes hash= 2;
}

message BlockID {
bytes hash = 1;
PartSetHeader part_set_header = 2;
}

message Commit {
int64 height = 1;
int32 round = 2;
BlockID block_id = 3;
repeated CommitSig signatures = 4;
}

// CommitSig is a part of the Vote included in a Commit.
message CommitSig {
BlockIDFlag block_id_flag = 1;
bytes validator_address = 2;
Timestamp timestamp = 3;
bytes signature = 4;
}

message Timestamp {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
int64 seconds = 1;

// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
int32 nanos = 2;
}

message LightHeader {
Consensus version = 1;
string chain_id = 2;
int64 height = 3;
Timestamp time = 4;
BlockID last_block_id = 5;
bytes last_commit_hash = 6; // commit from validators from the last block
bytes data_hash = 7; // transactions
bytes validators_hash = 8; // validators for the current block
bytes next_validators_hash = 9; // validators for the next block
bytes consensus_hash = 10; // consensus params for current block
bytes app_hash = 11; // state after txs from the previous block
bytes last_results_hash = 12; // root hash of all results from the txs from the previous block
bytes evidence_hash = 13; // evidence included in the block
bytes proposer_address = 14; // original proposer of the block
}

message SignedHeader {
LightHeader header = 1;
Commit commit = 2;
}

message TmHeader {
SignedHeader signed_header = 1;
ValidatorSet validator_set = 2;

int64 trusted_height = 3;
ValidatorSet trusted_validators = 4;
}

0 comments on commit a7af666

Please sign in to comment.