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

02-client-refactor added support for multiple consensus states inside a header #115

Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 15 additions & 17 deletions contracts/core/IBCClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import "./IBCHost.sol";
import "./IBCMsgs.sol";

library IBCClient {

/**
* @dev createClient creates a new client state and populates it with a given consensus state
*/
Expand All @@ -29,20 +28,19 @@ library IBCClient {
function updateClient(IBCHost host, IBCMsgs.MsgUpdateClient calldata msg_) external {
host.onlyIBCModule();
bytes memory clientStateBytes;
bytes memory consensusStateBytes;
Height.Data memory height;
bool found;

(clientStateBytes, found) = host.getClientState(msg_.clientId);
require(found, "clientState not found");

(clientStateBytes, consensusStateBytes, height) = checkHeaderAndUpdateState(host, msg_.clientId, clientStateBytes, msg_.header);

//// persist states ////
host.setClientState(msg_.clientId, clientStateBytes);
host.setConsensusState(msg_.clientId, height, consensusStateBytes);
host.setProcessedTime(msg_.clientId, height, block.timestamp);
host.setProcessedHeight(msg_.clientId, height, block.number);
// this function call is intended to perform:
// 1. client message verification
// 2. check for duplicate height misbehaviour
// 3. if misbehaviour is found, update state accordingly and return
// 4. update state in a way that verified headers carrying one or more consensus states can be updated
// 5. persist the state internally
// 6. return an array of consensus heights
verifyClientMessageAndUpdateState(host, msg_.clientId, clientStateBytes, msg_.clientMessage);
}

// TODO implements
Expand Down Expand Up @@ -70,18 +68,18 @@ library IBCClient {
return (IClient(addr), true);
}

function checkHeaderAndUpdateState(
function verifyClientMessageAndUpdateState(
IBCHost host,
string memory clientId,
bytes memory clientStateBytes,
bytes memory headerBytes
) public returns (bytes memory newClientStateBytes, bytes memory newConsensusStateBytes, Height.Data memory height) {
bytes memory clientMessageBytes
) public returns (bool) {
(bool success, bytes memory res) = address(getClient(host, clientId)).delegatecall(
abi.encodeWithSelector(
IClient.checkHeaderAndUpdateState.selector,
host, clientId, clientStateBytes, headerBytes));
IClient.verifyClientMessageAndUpdateState.selector,
host, clientId, clientStateBytes, clientMessageBytes));
assert(success);
return abi.decode(res, (bytes, bytes, Height.Data));
return abi.decode(res, (bool));
}

function verifyClientState(
Expand Down
2 changes: 1 addition & 1 deletion contracts/core/IBCMsgs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ library IBCMsgs {

struct MsgUpdateClient {
string clientId;
bytes header;
bytes clientMessage;
}

/// Connection handshake ///
Expand Down
34 changes: 23 additions & 11 deletions contracts/core/IBFT2Client.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,12 @@ contract IBFT2Client is IClient {
return (clientState.latest_height, true);
}

/**
* @dev checkHeaderAndUpdateState checks if the provided header is valid
*/
function checkHeaderAndUpdateState(
function verifyClientMessageAndUpdateState(
IBCHost host,
string memory clientId,
string memory clientId,
bytes memory clientStateBytes,
bytes memory headerBytes
) public override view returns (bytes memory newClientStateBytes, bytes memory newConsensusStateBytes, Height.Data memory height) {
bytes memory clientMessageBytes
) public override returns (bool) {
Header.Data memory header;
ClientState.Data memory clientState;
ConsensusState.Data memory consensusState;
Expand All @@ -89,19 +86,25 @@ contract IBFT2Client is IClient {
(clientState, ok) = unmarshalClientState(clientStateBytes);
require(ok, "client state is invalid");

(header, ok) = unmarshalHeader(headerBytes);
(header, ok) = unmarshalHeader(clientMessageBytes);
require(ok, "header is invalid");

(consensusState, ok) = getConsensusState(host, clientId, header.trusted_height);
require(ok, "consensusState not found");

//// check validity ////
// check if the provided client message is valid
ParsedBesuHeader memory parsedHeader = parseBesuHeader(header);
require(parsedHeader.height.gt(header.trusted_height), "header height <= consensus state height");
(validators, ok) = verify(consensusState, parsedHeader);
require(ok, "failed to verify the header");

//// update ////
// check for duplicate height misbehaviour

// updates state upon misbehaviour, freezing the ClientState.
// This method should only be called when misbehaviour is detected
// as it does not perform any misbehaviour checks.

// if client message is verified and there is no misbehaviour, update state
consensusState.timestamp = parsedHeader.time;
consensusState.root = abi.encodePacked(
verifyStorageProof(Bytes.toAddress(clientState.ibc_store_address), parsedHeader.stateRoot, header.account_state_proof)
Expand All @@ -111,7 +114,16 @@ contract IBFT2Client is IClient {
if (parsedHeader.height.gt(clientState.latest_height)) {
clientState.latest_height = parsedHeader.height;
}
return (marshalClientState(clientState), marshalConsensusState(consensusState), parsedHeader.height);

host.setClientState(clientId, marshalClientState(clientState));
host.setConsensusState(
clientId,
parsedHeader.height,
marshalConsensusState(consensusState)
);
host.setProcessedTime(clientId, parsedHeader.height, block.timestamp);
host.setProcessedHeight(clientId, parsedHeader.height, block.number);
return true;
}

function marshalClientState(ClientState.Data memory clientState) internal pure returns (bytes memory) {
Expand Down
8 changes: 4 additions & 4 deletions contracts/core/IClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ interface IClient {
string calldata clientId
) external view returns (Height.Data memory, bool);

function checkHeaderAndUpdateState(
function verifyClientMessageAndUpdateState(
IBCHost host,
string calldata clientId,
string calldata clientId,
bytes calldata clientStateBytes,
bytes calldata headerBytes
) external returns (bytes memory newClientStateBytes, bytes memory newConsensusStateBytes, Height.Data memory height);
bytes calldata clientMessageBytes
) external returns (bool);

nadeemb53 marked this conversation as resolved.
Show resolved Hide resolved
function verifyClientState(
IBCHost host,
Expand Down
37 changes: 29 additions & 8 deletions contracts/core/MockClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,30 +51,51 @@ contract MockClient is IClient {
}

/**
* @dev checkHeaderAndUpdateState checks if the provided header is valid
* @dev verifyClientMessageAndUpdateState is intended to perform:
* 1. client message verification
* 2. check for duplicate height misbehaviour
* 3. if misbehaviour is found, update state accordingly and return
* 4. update state in a way that verified headers carrying one or more consensus states can be updated
* 5. persist the state internally
* 6. return an array of consensus heights
*/
function checkHeaderAndUpdateState(
IBCHost,
string memory,
function verifyClientMessageAndUpdateState(
IBCHost host,
string memory clientId,
bytes memory clientStateBytes,
bytes memory headerBytes
) public override pure returns (bytes memory newClientStateBytes, bytes memory newConsensusStateBytes, Height.Data memory height) {
bytes memory clientMessageBytes
) public override returns (bool) {
// verify clientMessageBytes

// check for misbehaviour

// updates state upon misbehaviour, freezing the ClientState.
// This method should only be called when misbehaviour is detected
// as it does not perform any misbehaviour checks.

// if client message is verified and there is no misbehaviour, update state
Height.Data memory height;
uint64 timestamp;
Any.Data memory anyClientState;
Any.Data memory anyConsensusState;

anyClientState = Any.decode(clientStateBytes);
require(keccak256(abi.encodePacked(anyClientState.type_url)) == clientStateTypeUrlHash, "invalid client type");
ClientState.Data memory clientState = ClientState.decode(anyClientState.value);
(height, timestamp) = parseHeader(headerBytes);
(height, timestamp) = parseHeader(clientMessageBytes);
if (height.gt(clientState.latest_height)) {
clientState.latest_height = height;
}

anyClientState.value = ClientState.encode(clientState);
anyConsensusState.type_url = "/ibc.lightclients.mock.v1.ConsensusState";
anyConsensusState.value = ConsensusState.encode(ConsensusState.Data({timestamp: timestamp}));
return (Any.encode(anyClientState), Any.encode(anyConsensusState), height);

host.setClientState(clientId, Any.encode(anyClientState));
host.setConsensusState(clientId, height, Any.encode(anyConsensusState));
host.setProcessedTime(clientId, height, block.timestamp);
host.setProcessedHeight(clientId, height, block.number);
return true;
}

function verifyClientState(
Expand Down