Skip to content

Commit

Permalink
Misbehavior monitoring and handling (#691)
Browse files Browse the repository at this point in the history
* Split client_def in state, consensus, header. Add sketch for Tx decoding.

* Added misbehaviour message, structures, relayer submission

* tentative try with interim update event from cosmos PR

* trying to decode the header from event

* decode the header in client update event

* Added restart support, move some of the misbehaviour detection in light client, reorg

* fix merge

* add support for potential on-chain state pruning, cleanup

* Update changelog

* sketch for time travelling lunatic attack check

* fmt

* Decode misbehaviour events, added comments

* Update to reflect bad updates in the middle

* cargo fmt

* Cleanup consensus query and allow query for all

* Allow target and trusted heights to be specified in client updates

* Allow update with any existing trusted height

* Disallow create client with same src and dst

* Fix tests

* Added mock misbehaviour

* Fix CI and reorg code

* Cleanup

* Updates after sitdown review

* Update comments

* Flip back the logic in compatible_headers()

* Rename client_misbehaviour to misbehaviour

* review comments

* fmt

* Return UpdateClient::consensus_height by copy instead of reference

* Small cleanup in LightClient::build_misbehaviour

* Small cleanup in chain::cosmos

* Set pagination limit to u64::MAX for all queries that support it to ensure we get all results at once

See #811

* Addressed review comments

Co-authored-by: Romain Ruetschi <romain@informal.systems>
  • Loading branch information
ancazamfir and romac authored Apr 9, 2021
1 parent 7c2c6a4 commit ff0e6e5
Show file tree
Hide file tree
Showing 56 changed files with 1,652 additions and 191 deletions.
7 changes: 3 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
- [ibc-relayer]
- Support for relayer restart ([#561])
- Add support for ordered channels ([#599])
- Consistent identifier handling across ICS 02, 03 and 04 ([#622])

- [ibc-relayer]
- Misbehaviour detection and evidence submission ([#632])
- Use a stateless light client without a runtime ([#673])

- [ibc-relayer-cli]
Expand All @@ -35,7 +33,7 @@
- MBT: use modelator crate ([#761])

- [ibc-relayer]
- [nothing yet]
- Consistent identifier handling across ICS 02, 03 and 04 ([#622])

- [ibc-relayer-cli]
- Clarified success path for updating a client that is already up-to-date ([#734])
Expand Down Expand Up @@ -81,6 +79,7 @@
[#550]: https://github.com/informalsystems/ibc-rs/issues/550
[#599]: https://github.com/informalsystems/ibc-rs/issues/599
[#630]: https://github.com/informalsystems/ibc-rs/issues/630
[#632]: https://github.com/informalsystems/ibc-rs/issues/632
[#672]: https://github.com/informalsystems/ibc-rs/issues/672
[#673]: https://github.com/informalsystems/ibc-rs/issues/673
[#675]: https://github.com/informalsystems/ibc-rs/issues/675
Expand Down
11 changes: 5 additions & 6 deletions e2e/e2e/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,13 @@ class ClientUpdated:
@cmd("tx raw update-client")
class TxUpdateClient(Cmd[ClientUpdated]):
dst_chain_id: ChainId
src_chain_id: ChainId
dst_client_id: ClientId

def args(self) -> List[str]:
return [self.dst_chain_id, self.src_chain_id, self.dst_client_id]
return [self.dst_chain_id, self.dst_client_id]

def process(self, result: Any) -> ClientUpdated:
return from_dict(ClientUpdated, result['UpdateClient'])
return from_dict(ClientUpdated, result['UpdateClient']['common'])


# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -102,8 +101,8 @@ def create_client(c: Config, dst: ChainId, src: ChainId) -> ClientCreated:
return client


def update_client(c: Config, dst: ChainId, src: ChainId, client_id: ClientId) -> ClientUpdated:
cmd = TxUpdateClient(dst_chain_id=dst, src_chain_id=src,
def update_client(c: Config, dst: ChainId, client_id: ClientId) -> ClientUpdated:
cmd = TxUpdateClient(dst_chain_id=dst,
dst_client_id=client_id)
res = cmd.run(c).success()
l.info(f'Updated client to: {res.consensus_height}')
Expand All @@ -122,7 +121,7 @@ def create_update_query_client(c: Config, dst: ChainId, src: ChainId) -> ClientI
split()
query_client_state(c, dst, client.client_id)
split()
update_client(c, dst, src, client.client_id)
update_client(c, dst, client.client_id)
split()
query_client_state(c, dst, client.client_id)
split()
Expand Down
1 change: 0 additions & 1 deletion e2e/e2e/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class Ordering(Enum):
ClientType = NewType('ClientType', str)
BlockHeight = NewType('BlockHeight', str)


def split():
sleep(0.5)
print()
8 changes: 5 additions & 3 deletions modules/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::Height;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum IbcEventType {
CreateClient,
UpdateClient,
SendPacket,
WriteAck,
}
Expand All @@ -21,6 +22,7 @@ impl IbcEventType {
pub fn as_str(&self) -> &'static str {
match *self {
IbcEventType::CreateClient => "create_client",
IbcEventType::UpdateClient => "update_client",
IbcEventType::SendPacket => "send_packet",
IbcEventType::WriteAck => "write_acknowledgement",
}
Expand All @@ -35,7 +37,7 @@ pub enum IbcEvent {
CreateClient(ClientEvents::CreateClient),
UpdateClient(ClientEvents::UpdateClient),
UpgradeClient(ClientEvents::UpgradeClient),
ClientMisbehavior(ClientEvents::ClientMisbehavior),
ClientMisbehaviour(ClientEvents::ClientMisbehaviour),

OpenInitConnection(ConnectionEvents::OpenInit),
OpenTryConnection(ConnectionEvents::OpenTry),
Expand Down Expand Up @@ -87,7 +89,7 @@ impl IbcEvent {
IbcEvent::NewBlock(bl) => bl.height(),
IbcEvent::CreateClient(ev) => ev.height(),
IbcEvent::UpdateClient(ev) => ev.height(),
IbcEvent::ClientMisbehavior(ev) => ev.height(),
IbcEvent::ClientMisbehaviour(ev) => ev.height(),
IbcEvent::OpenInitConnection(ev) => ev.height(),
IbcEvent::OpenTryConnection(ev) => ev.height(),
IbcEvent::OpenAckConnection(ev) => ev.height(),
Expand All @@ -113,7 +115,7 @@ impl IbcEvent {
IbcEvent::CreateClient(ev) => ev.set_height(height),
IbcEvent::UpdateClient(ev) => ev.set_height(height),
IbcEvent::UpgradeClient(ev) => ev.set_height(height),
IbcEvent::ClientMisbehavior(ev) => ev.set_height(height),
IbcEvent::ClientMisbehaviour(ev) => ev.set_height(height),
IbcEvent::OpenInitConnection(ev) => ev.set_height(height),
IbcEvent::OpenTryConnection(ev) => ev.set_height(height),
IbcEvent::OpenAckConnection(ev) => ev.set_height(height),
Expand Down
50 changes: 49 additions & 1 deletion modules/src/ics02_client/client_consensus.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
use core::marker::{Send, Sync};
use std::convert::TryFrom;
use std::convert::{TryFrom, TryInto};

use chrono::{DateTime, Utc};
use prost_types::Any;
use serde::Serialize;
use tendermint_proto::Protobuf;

use ibc_proto::ibc::core::client::v1::ConsensusStateWithHeight;

use crate::events::IbcEventType;
use crate::ics02_client::client_type::ClientType;
use crate::ics02_client::error::{Error, Kind};
use crate::ics02_client::height::Height;
use crate::ics07_tendermint::consensus_state;
use crate::ics23_commitment::commitment::CommitmentRoot;
use crate::ics24_host::identifier::ClientId;
#[cfg(any(test, feature = "mocks"))]
use crate::mock::client_state::MockConsensusState;

Expand Down Expand Up @@ -108,6 +113,41 @@ impl From<AnyConsensusState> for Any {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub struct AnyConsensusStateWithHeight {
pub height: Height,
pub consensus_state: AnyConsensusState,
}

impl Protobuf<ConsensusStateWithHeight> for AnyConsensusStateWithHeight {}

impl TryFrom<ConsensusStateWithHeight> for AnyConsensusStateWithHeight {
type Error = Error;

fn try_from(value: ConsensusStateWithHeight) -> Result<Self, Self::Error> {
let state = value
.consensus_state
.map(AnyConsensusState::try_from)
.transpose()
.map_err(|e| Kind::InvalidRawConsensusState.context(e))?
.ok_or(Kind::EmptyConsensusStateResponse)?;

Ok(AnyConsensusStateWithHeight {
height: value.height.ok_or(Kind::InvalidHeightResult)?.try_into()?,
consensus_state: state,
})
}
}

impl From<AnyConsensusStateWithHeight> for ConsensusStateWithHeight {
fn from(value: AnyConsensusStateWithHeight) -> Self {
ConsensusStateWithHeight {
height: Some(value.height.into()),
consensus_state: Some(value.consensus_state.into()),
}
}
}

impl ConsensusState for AnyConsensusState {
fn client_type(&self) -> ClientType {
self.client_type()
Expand All @@ -125,3 +165,11 @@ impl ConsensusState for AnyConsensusState {
self
}
}

#[derive(Clone, Debug)]
pub struct QueryClientEventRequest {
pub height: crate::Height,
pub event_id: IbcEventType,
pub client_id: ClientId,
pub consensus_height: crate::Height,
}
2 changes: 2 additions & 0 deletions modules/src/ics02_client/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use tendermint_proto::Protobuf;

use crate::ics02_client::client_type::ClientType;
use crate::ics02_client::error::{Error, Kind};

use crate::ics07_tendermint::client_state;
use crate::ics24_host::identifier::ChainId;
#[cfg(any(test, feature = "mocks"))]
Expand Down Expand Up @@ -53,6 +54,7 @@ impl AnyClientState {
Self::Mock(mock_state) => mock_state.latest_height(),
}
}

pub fn client_type(&self) -> ClientType {
match self {
Self::Tendermint(state) => state.client_type(),
Expand Down
6 changes: 6 additions & 0 deletions modules/src/ics02_client/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ pub enum Kind {
#[error("unknown header type: {0}")]
UnknownHeaderType(String),

#[error("unknown misbehaviour type: {0}")]
UnknownMisbehaviourType(String),

#[error("invalid raw client state")]
InvalidRawClientState,

Expand All @@ -65,6 +68,9 @@ pub enum Kind {
#[error("invalid raw header")]
InvalidRawHeader,

#[error("invalid raw misbehaviour")]
InvalidRawMisbehaviour,

#[error("invalid height result")]
InvalidHeightResult,

Expand Down
Loading

0 comments on commit ff0e6e5

Please sign in to comment.