From 9160dce383358e833836cffb70e20e95c5612c12 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 19 Nov 2021 09:56:45 -0600 Subject: [PATCH] Add architecture.md and module-level documentation (#1556) * Add arch doc with mention of flex-error * Add module-level documentation * Add some more module-level documentation * Add some more module-level documentation * Add more module-level documentation * Add Fungible Token Transfer section to arch.md * Fix broken markdown link * Add changelog entry * Run cargo fmt * Incorporate PR feedback * Replace `ibc-rs-layout` image * Fix broken markdown link * Fix broken markdown links * Replace layout image * Change header ordering --- .../unreleased/improvements/1556-arch-doc.md | 5 + docs/architecture/architecture.md | 130 ++++++++++++++++++ docs/architecture/assets/ibc-rs-layout.png | Bin 0 -> 58389 bytes .../ics20_fungible_token_transfer/mod.rs | 4 +- modules/src/applications/mod.rs | 2 + modules/src/clients/ics07_tendermint/mod.rs | 3 +- modules/src/clients/mod.rs | 2 + modules/src/core/ics02_client/mod.rs | 2 +- modules/src/core/ics03_connection/mod.rs | 3 +- modules/src/core/ics04_channel/mod.rs | 3 +- modules/src/core/ics05_port/mod.rs | 3 + modules/src/core/ics23_commitment/mod.rs | 3 + modules/src/core/ics24_host/mod.rs | 3 +- modules/src/core/ics26_routing/mod.rs | 3 +- modules/src/core/mod.rs | 3 + modules/src/lib.rs | 13 +- modules/src/relayer/ics18_relayer/mod.rs | 2 +- modules/src/relayer/mod.rs | 4 + 18 files changed, 174 insertions(+), 14 deletions(-) create mode 100644 .changelog/unreleased/improvements/1556-arch-doc.md create mode 100644 docs/architecture/architecture.md create mode 100644 docs/architecture/assets/ibc-rs-layout.png diff --git a/.changelog/unreleased/improvements/1556-arch-doc.md b/.changelog/unreleased/improvements/1556-arch-doc.md new file mode 100644 index 0000000000..1f019e1274 --- /dev/null +++ b/.changelog/unreleased/improvements/1556-arch-doc.md @@ -0,0 +1,5 @@ +- Add architecture.md doc that gives a high-level overview of the structure of the codebase. +- Add some module-level documentation + ([#1556][1556]) + +[1556]: https://github.com/informalsystems/ibc-rs/pulls/1556 diff --git a/docs/architecture/architecture.md b/docs/architecture/architecture.md new file mode 100644 index 0000000000..ea549cfd8f --- /dev/null +++ b/docs/architecture/architecture.md @@ -0,0 +1,130 @@ +# Architecture + +This document describes the architecture of `ibc-rs`. If you're looking for a high-level overview of the code base, you've come to the right place! + +## Terms + +Some important terms and acronyms that are commonly used include: + + * **IBC**: Refers to the **I**nter**B**lockchain **C**ommunication protocol, a distributed protocol that allows different sovereign blockchains to communicate with one another. The protocol has both on-chain and off-chain components. + * **ICS**: Refers to **I**nter**C**hain **S**tandards, which are stadardization documents that capture the specifications of the IBC protocol across multiple documents. For example, ICS02 captures the client abstraction of the IBC protocol. + * **IBC module**: Refers to a piece of on-chain logic on an IBC-enabled chain. + * **Relayer**: Refers to an off-chain process that is responsible for relaying packets between chains. + * **Hermes**: Refers to the `ibc-rs` crate's particular relayer implementation. + +## Bird's Eye View + +![][layout-image] + +At its highest level, `ibc-rs` implements the InterBlockchain Communication protocol which is captured in [specifications in a separate repository][ibc-specs]. `ibc-rs` exposes modules that implement the specified protocol logic. The IBC protocol can be understood as having two separate components: on-chain and off-chain logic. The relayer, which is the main off-chain component, is a standalone process, of which Hermes is an implementation. On-chain components can be thought of as modules or smart contracts that run as part of a chain. The main on-chain components deal with the abstractions of clients, connections, and channels. + +## Code Map + +This section talks briefly about the various directories and modules in `ibc-rs`. + +### `modules`/`ibc` + +> Note: While the name of the directory is `modules`, the name of the crate is `ibc`. + +This crate contains the main data structures and on-chain logic of the IBC protocol; the fundamental pieces. There is the conceptual notion of 'handlers', which are pieces of code that each handle a particular type of message. The most notable handlers are the [client][ibc-client], [connection][ibc-connection], and [channel][ibc-channel] handlers. + +> Note: The naming of directories in the `ibc` crate follow a slightly different convention compared to the other crates in `ibc-rs`. This is because this crate implements the [ICS standards][ics-standards]. Modules in the `ibc` crate that implement a piece of the ICS standard are prefixed with the standard's designation. For example, the `modules/src/ics02_client` implements [ICS 02][ics02], which specifies the Client abstraction. These prefixes may be removed in the future. + +#### Core + +Consists of the designs and logic pertaining to the transport, authentication, and ordering layers of the IBC protocol, the fundamental pieces. + +##### ICS 02 - Client + +Clients encapsulate all of the verification methods of another IBC-enabled chain in order to ensure that the other chain adheres to the IBC protocol and does not exhibit misbehaviour. Clients "track" the metadata of the other chain's blocks, and each chain has a client for every other chain that it communicates with. + +##### ICS 03 - Connection + +Connections associate a chain with another chain by connecting a client on the local chain with a client on the remote chain. This association is pair-wise unique and is established between two chains following a 4-step handshake process. + +##### ICS 04 - Channel + +Channels are an abstraction layer that facilitate communication between applications and the chains those applications are built upon. One important function that channels can fulfill is guaranteeing that data packets sent between an application and its chain are well-ordered. + +##### ICS 05 - Port + +The port standard specifies an allocation scheme by which modules can bind to uniquely-named ports allocated by the IBC handler in order to facilitate module-to-module traffic. These ports are used to open channels and can be transferred or released by the module which originally bound them. + +##### ICS 23 - Commitment + +Commitments (sometimes called _vector commitments_) define an efficient cryptographic construction to prove inclusion or non-inclusion of values in at particular paths in state. This scheme provides a guarantee of a particular state transition that has occurred on one chain which can be verified on another chain. + +#### Applications + +Consists of various packet encoding and processing semantics which underpin the various types of transactions that users can perform on any IBC-compliant chain. + +##### ICS 20 - Fungible Token Transfer + +Specifies the packet data structure, state machine handling logic, and encoding details used for transferring fungible tokens between IBC chains. This process preserves asset fungibility and ownership while limiting the impact of Byzantine faults. + +#### Clients + +Consists of implementations of client verification algorithms (following the base client interface that is defined in `Core`) for specific types of chains. A chain uses these verification algorithms to verify the state of a remote chain. + +##### ICS 07 - Tendermint + +The Tendermint client implements a client verification algorithm for blockchains which use the Tendermint consensus algorithm. This enables state machines of various sorts replicated using the Tendermint consensus algorithm to interface with other replicated state machines or solo machines over IBC. + +#### Relayer + +Contains utilities for testing the `ibc` crate against the Hermes IBC relayer. It acts as scaffolding for gluing the `ibc` crate with Hermes for testing purposes. + +##### ICS 18 - Relayer + +Relayer algorithms are the "physical" connection layer of IBC — off-chain processes responsible for relaying data between two chains running the IBC protocol by scanning the state of each chain, constructing appropriate datagrams, and executing them on the opposite chain as allowed by the protocol. + +### `relayer` + +This crate provides the logic for relaying datagrams between chains. The process of relaying packets is an off-chain process that is kicked off by submitting transactions to read from or write to an IBC-enabled chain's state. More broadly, a relayer enables a chain to ascertain another chain's state by accessing its clients, connections, channels, or anything that is IBC-related. + +### `relayer-cli` + +A CLI wrapper around the `relayer` crate for running and issuing commands to a chain via a relayer. This crate exposes the Hermes binary. + +### `relayer-rest` + +An add-on to the CLI mainly for exposing some internal runtime details of Hermes for debugging and observability reasons. + +### `proto` + +Depends on the `proto-compiler` crate's generated proto files. + +Consists of protobuf-generated Rust types which are necessary for interacting with the Cosmos SDK. Also contains client and server methods that the relayer library includes for accessing the gRPC calls of a chain. + +### `proto-compiler` + +CLI tool to automate the compilation of proto buffers, which allows Hermes developers to go from a type specified in proto files to generate client gRPC code or server gRPC code. + +### `telemetry` + +Used by Hermes to gather telemetry data and expose it via a Prometheus endpoint. + +## Cross-Cutting Concerns + +### Testing + +Most of the components in the `ibc` crate (i.e. the `modules` directory) have basic unit testing coverage. These unit tests make use of mocked up chain components in order to ensure that message payloads are being sent and received as expected. + +We also run end-to-end tests to more thoroughly test IBC modules in a more heterogenous fashion. + +### Error Handling + +Most errors occur within the relayer as a result of either I/O operations or user misconfiguration. I/O-related errors can be sub-categorized into web socket errors and chain RPC errors. The latter occur when full nodes are out of sync with the rest of the network, which result in transactions that are based off of conflicting chain states. Such errors are usually either resolved by retrying the transaction, or might require operator intervention in order to flush the transaction from the mempool in conjunction with restarting the full node. + +The [flex-error][flex-error] library is the main tool used to handle errors in the code. This [demo][flex-error-demo] showcases some of the main patterns of how `flex-error` is used. For a more real-world example, [this][relayer-errors] file defines all of the possible errors for the relayer. + +[flex-error]: https://github.com/informalsystems/flex-error +[flex-error-demo]: https://github.com/informalsystems/flex-error/blob/master/flex-error-demo-full/src/main.rs +[ibc-specs]: https://github.com/cosmos/ibc#interchain-standards +[ics-standards]: https://github.com/cosmos/ibc#standardisation +[ibc-client]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics02_client +[ibc-connection]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics03_connection +[ibc-channel]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics04_channel +[ics02]: https://github.com/cosmos/ibc/blob/master/spec/core/ics-002-client-semantics/README.md +[layout-image]: assets/ibc-rs-layout.png +[relayer-errors]: https://github.com/informalsystems/ibc-rs/blob/master/relayer/src/error.rs diff --git a/docs/architecture/assets/ibc-rs-layout.png b/docs/architecture/assets/ibc-rs-layout.png new file mode 100644 index 0000000000000000000000000000000000000000..9e68bae5f81c14fd470835d97b7e82216fb00bbc GIT binary patch literal 58389 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 literal 0 HcmV?d00001 diff --git a/modules/src/applications/ics20_fungible_token_transfer/mod.rs b/modules/src/applications/ics20_fungible_token_transfer/mod.rs index 9bd1bbcbbb..96032a193a 100644 --- a/modules/src/applications/ics20_fungible_token_transfer/mod.rs +++ b/modules/src/applications/ics20_fungible_token_transfer/mod.rs @@ -1,4 +1,6 @@ -//! ICS 20: IBC Transfer implementation +//! ICS 20: Token Transfer implementation allows for multi-chain denomination handling, which +//! constitutes a "fungible token transfer bridge module" between the IBC routing module and an +//! asset tracking module. pub mod context; pub mod error; pub mod msgs; diff --git a/modules/src/applications/mod.rs b/modules/src/applications/mod.rs index c3eb98a343..911e26b7c9 100644 --- a/modules/src/applications/mod.rs +++ b/modules/src/applications/mod.rs @@ -1,3 +1,5 @@ +//! Various packet encoding semantics which underpin the various types of transactions. + pub mod ics20_fungible_token_transfer; // TODO: These consts should move into the ICS27 namespace diff --git a/modules/src/clients/ics07_tendermint/mod.rs b/modules/src/clients/ics07_tendermint/mod.rs index 0c4263997f..3b32d8e62f 100644 --- a/modules/src/clients/ics07_tendermint/mod.rs +++ b/modules/src/clients/ics07_tendermint/mod.rs @@ -1,4 +1,5 @@ -//! ICS 07: Tendermint Client +//! ICS 07: Tendermint Client implements a client verification algorithm for blockchains which use +//! the Tendermint consensus algorithm. pub mod client_def; pub mod client_state; diff --git a/modules/src/clients/mod.rs b/modules/src/clients/mod.rs index cc3da1b010..65ea910b18 100644 --- a/modules/src/clients/mod.rs +++ b/modules/src/clients/mod.rs @@ -1 +1,3 @@ +//! Implementations of client verification algorithms for specific types of chains. + pub mod ics07_tendermint; diff --git a/modules/src/core/ics02_client/mod.rs b/modules/src/core/ics02_client/mod.rs index ca2713d6a9..9c25ef479f 100644 --- a/modules/src/core/ics02_client/mod.rs +++ b/modules/src/core/ics02_client/mod.rs @@ -1,4 +1,4 @@ -//! ICS 02: IBC Client implementation +//! ICS 02: Client implementation for verifying remote IBC-enabled chains. pub mod client_consensus; pub mod client_def; diff --git a/modules/src/core/ics03_connection/mod.rs b/modules/src/core/ics03_connection/mod.rs index 696f43e071..b3e9cf77c0 100644 --- a/modules/src/core/ics03_connection/mod.rs +++ b/modules/src/core/ics03_connection/mod.rs @@ -1,4 +1,5 @@ -//! ICS 03: IBC Connection implementation +//! ICS 03: Connection implementation for connecting a client +//! on the local chain with a client on a remote chain. pub mod connection; /// Context definitions (dependencies for the protocol). diff --git a/modules/src/core/ics04_channel/mod.rs b/modules/src/core/ics04_channel/mod.rs index 1baad1e342..952d695b1f 100644 --- a/modules/src/core/ics04_channel/mod.rs +++ b/modules/src/core/ics04_channel/mod.rs @@ -1,4 +1,5 @@ -//! ICS 04: IBC Channel implementation +//! ICS 04: Channel implementation that facilitates communication between +//! applications and the chains those applications are built upon. pub mod channel; pub mod context; diff --git a/modules/src/core/ics05_port/mod.rs b/modules/src/core/ics05_port/mod.rs index 7f6f91fb09..015cdced9b 100644 --- a/modules/src/core/ics05_port/mod.rs +++ b/modules/src/core/ics05_port/mod.rs @@ -1,3 +1,6 @@ +//! ICS 05: Port implementation specifies the allocation scheme used by modules to +//! bind to uniquely named ports. + pub mod capabilities; pub mod context; pub mod error; diff --git a/modules/src/core/ics23_commitment/mod.rs b/modules/src/core/ics23_commitment/mod.rs index 885c5dbd1a..e3806ad771 100644 --- a/modules/src/core/ics23_commitment/mod.rs +++ b/modules/src/core/ics23_commitment/mod.rs @@ -1,3 +1,6 @@ +//! ICS 23: Commitment implementation of a cryptographic scheme that verifies +//! state transitions between chains. + pub mod commitment; pub mod error; pub mod merkle; diff --git a/modules/src/core/ics24_host/mod.rs b/modules/src/core/ics24_host/mod.rs index 3e1f15ab6d..23be43fb73 100644 --- a/modules/src/core/ics24_host/mod.rs +++ b/modules/src/core/ics24_host/mod.rs @@ -1,4 +1,5 @@ -//! ICS 24: Host Requirements +//! ICS 24: Host defines the minimal set of interfaces that a +//! state machine hosting an IBC-enabled chain must implement. pub use path::{ClientUpgradePath, Path, IBC_QUERY_PATH, SDK_UPGRADE_QUERY_PATH}; diff --git a/modules/src/core/ics26_routing/mod.rs b/modules/src/core/ics26_routing/mod.rs index 40cf9bee79..79e5a5ff29 100644 --- a/modules/src/core/ics26_routing/mod.rs +++ b/modules/src/core/ics26_routing/mod.rs @@ -1,4 +1,5 @@ -//! ICS 26: Routing module implementation +//! ICS 26: Routing module keeps a lookup table of modules for looking +//! the appropriate module to relay to when a packet is received. pub mod context; pub mod error; diff --git a/modules/src/core/mod.rs b/modules/src/core/mod.rs index 22134b7235..ef9cc94681 100644 --- a/modules/src/core/mod.rs +++ b/modules/src/core/mod.rs @@ -1,3 +1,6 @@ +//! The designs and logic pertaining to the transport, authentication, and +//! ordering layers of the IBC protocol. + pub mod ics02_client; pub mod ics03_connection; pub mod ics04_channel; diff --git a/modules/src/lib.rs b/modules/src/lib.rs index 81bf999aa9..026d4123f2 100644 --- a/modules/src/lib.rs +++ b/modules/src/lib.rs @@ -15,7 +15,7 @@ )] #![forbid(unsafe_code)] -//! This library implements the _I_nter_B_lockchain _C_ommunication (IBC) protocol in Rust. IBC is +//! This library implements the InterBlockchain Communication (IBC) protocol in Rust. IBC is //! a distributed protocol that enables communication between distinct sovereign blockchains. //! Loose analogies may be drawn between the IBC protocol and the TCP/UDP protocols that enable //! communication over the internet via packet streaming. Indeed, IBC also encodes the notion of @@ -25,24 +25,25 @@ //! Standards][ics-standards]. The classification consists of [Core][core], [Clients][clients], //! [Applications][applications], and [Relayer][relayer]. //! -//! Core consists of the designs and logic pertaining to the transport, authentication, and +//! `Core` consists of the designs and logic pertaining to the transport, authentication, and //! ordering layers of the IBC protocol, the fundamental pieces. //! -//! Clients consists of implementations of client verification algorithms (following the base +//! `Clients` consists of implementations of client verification algorithms (following the base //! client interface that is defined in `Core`) for specific types of chains. A chain uses these //! verification algorithms to verify the state of remote chains. //! -//! Applications consist of various packet encoding and processing semantics which underpin the +//! `Applications` consists of various packet encoding and processing semantics which underpin the //! various types of transactions that users can perform on any IBC-compliant chain. //! -//! Relayer contains utilities for testing the `ibc` crate against the Hermes IBC relayer. It acts +//! `Relayer` contains utilities for testing the `ibc` crate against the [Hermes IBC relayer][relayer-repo]. It acts //! as scaffolding for gluing the `ibc` crate with Hermes for testing purposes. //! //! [core]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core //! [clients]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/clients //! [applications]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/applications -//! [relayer]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/relayer //! [ics-standards]: https://github.com/cosmos/ibc#interchain-standards +//! [relayer]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/relayer +//! [relayer-repo]: https://github.com/informalsystems/ibc-rs/tree/master/relayer extern crate alloc; extern crate std; diff --git a/modules/src/relayer/ics18_relayer/mod.rs b/modules/src/relayer/ics18_relayer/mod.rs index 380a73836c..254c69aa4e 100644 --- a/modules/src/relayer/ics18_relayer/mod.rs +++ b/modules/src/relayer/ics18_relayer/mod.rs @@ -1,4 +1,4 @@ -//! ICS 18: Implementation of basic relayer functions. +//! ICS 18: Relayer contains utilities for testing `ibc` against the Hermes relayer. pub mod context; pub mod error; diff --git a/modules/src/relayer/mod.rs b/modules/src/relayer/mod.rs index c66ccf49a7..e88996bcd5 100644 --- a/modules/src/relayer/mod.rs +++ b/modules/src/relayer/mod.rs @@ -1 +1,5 @@ +//! Utilities for testing the `ibc` crate against the [Hermes IBC relayer][relayer-repo]. +//! +//! [relayer-repo]: https://github.com/informalsystems/ibc-rs/tree/master/relayer + pub mod ics18_relayer;