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

Implement mock cosmos chain using ibc-rs, tendermint-rs and basecoin libs #3566

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d361e02
feat: implement mock cosmos chain
Farhad-Shabani Aug 25, 2023
fc18085
fix: clean up relay impls
Farhad-Shabani Aug 25, 2023
9dcd199
imp: chain handler refinement
Farhad-Shabani Aug 26, 2023
0b56aa0
feat: add update client test
Farhad-Shabani Aug 26, 2023
78bcbf6
fix: patch tendermint testgen
Farhad-Shabani Aug 26, 2023
29ddb0a
imp: use create client traits
Farhad-Shabani Aug 27, 2023
c471a1a
imp: separate mock basecoin from chain context
Farhad-Shabani Aug 28, 2023
ff40564
imp: separate chain handles from endpoints
Farhad-Shabani Aug 28, 2023
b0717a7
fix: update cargo.lock
Farhad-Shabani Aug 28, 2023
e6f38fa
imp: better break down of methods for basecoin
Farhad-Shabani Aug 28, 2023
9016fff
imp: use random generated app_hash
Farhad-Shabani Aug 29, 2023
235a06d
fix: apply suggestions from code review
Farhad-Shabani Aug 29, 2023
1941409
imp: add more docstings + change the naming of BasecoinHandler to Bas…
Farhad-Shabani Aug 29, 2023
cd438ec
nit: drop redundant state declaration
Farhad-Shabani Aug 29, 2023
bba1b84
fix: add validators field to MockBasecoin
Farhad-Shabani Aug 29, 2023
d07e117
imp: rename connect method to sync
Farhad-Shabani Aug 29, 2023
5373f2b
imp: use TokioRuntimeContext instead
Farhad-Shabani Aug 30, 2023
c422ce2
imp: incorporate MockCosmosBuilder
Farhad-Shabani Aug 30, 2023
d31f34c
Add docstring for `MockCosmosRelay`
Farhad-Shabani Aug 30, 2023
d12f332
imp: some clean-ups
Farhad-Shabani Aug 30, 2023
b6e3e46
Merge branch 'soares/relayer-next' into farhad/mock-cosmos-chain
Farhad-Shabani Sep 5, 2023
07074a8
nit: cargo fmt
Farhad-Shabani Sep 5, 2023
fc7e864
Merge branch 'soares/relayer-next' into farhad/mock-cosmos-chain
Farhad-Shabani Sep 7, 2023
f0675bc
fix: implement missed traits for chain and component
Farhad-Shabani Sep 7, 2023
1a2c24c
fix: test_update_client should query dst_chain to see client_state up…
Farhad-Shabani Sep 12, 2023
6d34e4b
fix: use store's root_hash as app_hash for headers
Farhad-Shabani Sep 14, 2023
6040462
deps: bump ibc, ibc-proto, tendermint, basecoin
Farhad-Shabani Sep 22, 2023
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
1,165 changes: 914 additions & 251 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 4 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ members = [
"crates/relayer-mock",
"crates/relayer-runtime",
"crates/relayer-cosmos",
"crates/relayer-cosmos-mock",
"crates/telemetry",
"crates/chain-registry",
"tools/integration-test",
Expand All @@ -28,11 +29,6 @@ exclude = [
overflow-checks = true

[patch.crates-io]
# ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs.git", branch = "main" }
# tendermint = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "romac/new-misbehavior-detector" }
# tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "romac/new-misbehavior-detector" }
# tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "romac/new-misbehavior-detector" }
# tendermint-light-client = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "romac/new-misbehavior-detector" }
# tendermint-light-client-verifier = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "romac/new-misbehavior-detector" }
# tendermint-light-client-detector = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "romac/new-misbehavior-detector" }
# tendermint-testgen = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "romac/new-misbehavior-detector" }
tendermint = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "farhad/testgen-app-hash" }
tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "farhad/testgen-app-hash" }
tendermint-testgen = { git = "https://github.com/informalsystems/tendermint-rs.git", branch = "farhad/testgen-app-hash" }
38 changes: 38 additions & 0 deletions crates/relayer-cosmos-mock/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "ibc-relayer-cosmos-mock"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
readme = "README.md"
keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"]
repository = "https://github.com/informalsystems/ibc-rs"
authors = ["Informal Systems <[email protected]>"]
rust-version = "1.68"
description = """
TBD
"""

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
async-trait = "0.1.56"
basecoin-app = { git = "https://github.com/informalsystems/basecoin-rs.git" }
basecoin-store = { git = "https://github.com/informalsystems/basecoin-rs.git" }
ibc = { git = "https://github.com/cosmos/ibc-rs.git", rev= "6ffe8ce", features = ["mocks"] }
ibc-proto = "0.34.0"
ibc-relayer-components = { version = "0.1.0", path = "../relayer-components" }
ibc-relayer-components-extra = { version = "0.1.0", path = "../relayer-components-extra" }
ibc-relayer-runtime = { version = "0.1.0", path = "../relayer-runtime" }
ibc-relayer-types = { version = "0.25.0", path = "../relayer-types" }
primitive-types = { version = "0.12.0", default-features = false}
prost = "0.11.0"
serde_json = "1.0"
sha2 = { version = "0.10", default-features = false }
subtle-encoding = { version = "0.5", default-features = false }
rand = "0.8.5"
tendermint = { version = "0.33.0", features = ["rust-crypto"] }
tendermint-testgen = "0.33.0"
tracing = "0.1.36"
tokio = { version = "1.0", features = ["full"] }
tower-abci = "0.9"
tower = { version = "0.4", features = ["full"] }
194 changes: 194 additions & 0 deletions crates/relayer-cosmos-mock/src/contexts/basecoin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
use std::fmt::Debug;
use std::sync::Arc;
use std::sync::Mutex;
use std::time::Duration;

use basecoin_app::modules::auth::Auth;
use basecoin_app::modules::bank::Bank;
use basecoin_app::modules::context::prefix;
use basecoin_app::modules::context::Identifiable;
use basecoin_app::modules::ibc::Ibc;
use basecoin_app::BaseCoinApp;
use basecoin_app::Builder;
use basecoin_store::context::ProvableStore;
use ibc::core::ics24_host::identifier::ChainId;
use ibc::Height;
use ibc_relayer_components_extra::runtime::traits::spawn::Spawner;
use ibc_relayer_components_extra::runtime::traits::spawn::TaskHandle;
use ibc_relayer_runtime::types::runtime::TokioRuntimeContext;
use tendermint::Time;
use tendermint_testgen::light_block::TmLightBlock;
use tendermint_testgen::Generator;
use tendermint_testgen::Header;
use tendermint_testgen::LightBlock;
use tendermint_testgen::Validator;

use crate::traits::runner::BasecoinRunner;
use crate::types::status::ChainStatus;
use crate::util::dummy::generate_rand_app_hash;
use crate::util::mutex::MutexUtil;

/// A mock ABCI application that includes simplified store, application,
/// consensus layers.
///
/// The store consists of an in-memory AVL implementation that facilitates
/// proof verification.
///
/// The application layer includes Authentication, Bank, and IBC modules,
/// resulting in a fully operational ibc-rs implementation that runs in a
/// lightweight manner.
///
/// The consensus layer consists of a simple block production engine that
/// forgoes voting, validation, and transaction phases for the sake of
/// simplicity.
#[derive(Clone)]
pub struct MockBasecoin<S>
Farhad-Shabani marked this conversation as resolved.
Show resolved Hide resolved
where
S: ProvableStore + Debug,
{
/// Chain runtime
pub runtime: TokioRuntimeContext,
/// Chain identifier
pub chain_id: ChainId,
/// Chain validators
pub validators: Arc<Mutex<Vec<Validator>>>,
/// Chain blocks
pub blocks: Arc<Mutex<Vec<TmLightBlock>>>,
/// Chain application
pub app: BaseCoinApp<S>,
/// Current chain status
pub current_status: Arc<Mutex<ChainStatus>>,
}

impl<S: ProvableStore + Default + Debug> MockBasecoin<S> {
/// Constructs a new mock cosmos chain instance.
pub fn new(
runtime: TokioRuntimeContext,
chain_id: ChainId,
validators: Vec<Validator>,
store: S,
) -> Self {
let app_builder = Builder::new(store);

let auth = Auth::new(app_builder.module_store(&prefix::Auth {}.identifier()));
let bank = Bank::new(
app_builder.module_store(&prefix::Bank {}.identifier()),
auth.account_reader().clone(),
auth.account_keeper().clone(),
);
let ibc = Ibc::new(
app_builder.module_store(&prefix::Ibc {}.identifier()),
bank.bank_keeper().clone(),
);

// register modules with the app
let app = app_builder
.add_module(prefix::Auth {}.identifier(), auth.clone())
.add_module(prefix::Bank {}.identifier(), bank.clone())
.add_module(prefix::Ibc {}.identifier(), ibc)
.build();

let genesis_height = Height::new(chain_id.revision_number(), 1).expect("never fails");

let genesis_time = Time::now();

let genesis_block = Self::generate_block(
&chain_id,
genesis_height.revision_height(),
genesis_time,
&validators,
);

let genesis_status = Arc::new(Mutex::new(ChainStatus::new(
genesis_height,
genesis_time.into(),
)));

Self {
runtime,
chain_id,
validators: Arc::new(Mutex::new(validators)),
blocks: Arc::new(Mutex::new(vec![genesis_block])),
app,
current_status: genesis_status,
}
}

pub fn runtime(&self) -> &TokioRuntimeContext {
&self.runtime
}

pub fn get_blocks(&self) -> Vec<TmLightBlock> {
self.blocks.acquire_mutex().clone()
}

pub fn get_current_status(&self) -> ChainStatus {
self.current_status.acquire_mutex().clone()
}

pub fn update_status(&self) {
let blocks = self.blocks.acquire_mutex();

let last_block = blocks.last().expect("never fails");

let current_revision_height = last_block.signed_header.header.height.value();

let current_time = last_block.signed_header.header.time;

let current_height = Height::new(self.chain_id.revision_number(), current_revision_height)
.expect("never fails");

let mut last_status = self.current_status.acquire_mutex();

*last_status = ChainStatus::new(current_height, current_time.into());
}

pub fn generate_block(
chain_id: &ChainId,
height: u64,
time: Time,
validators: &[Validator],
) -> TmLightBlock {
let header = Header::new(validators)
.chain_id(&chain_id.to_string())
.height(height)
.time(time)
.next_validators(validators)
.app_hash(generate_rand_app_hash());

LightBlock::new_default_with_header(header)
.generate()
.expect("failed to generate light block")
}

pub fn grow_blocks(&self) {
let mut blocks = self.blocks.acquire_mutex();

let validators = self.validators.acquire_mutex();

let new_tm_light_block = Self::generate_block(
&self.chain_id,
blocks.len() as u64 + 1,
Time::now(),
&validators,
);

blocks.push(new_tm_light_block);
}

pub fn run(&self) -> Box<dyn TaskHandle> {
let chain = self.clone();

self.runtime().spawn(async move {
chain.init().await;

loop {
chain.begin_block().await;

tokio::time::sleep(Duration::from_millis(200)).await;

chain.commit().await;
}
})
}
}
35 changes: 35 additions & 0 deletions crates/relayer-cosmos-mock/src/contexts/birelay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use ibc_relayer_runtime::types::runtime::TokioRuntimeContext;
use std::sync::Arc;

use super::relay::MockCosmosRelay;
use crate::traits::endpoint::BasecoinEndpoint;

Farhad-Shabani marked this conversation as resolved.
Show resolved Hide resolved
/// Bi-directional relayer for relaying between
/// [`crates::relayer-cosmos-mock::contexts::MockCosmosRelay`]s
pub struct MockCosmosBiRelay<SrcChain: BasecoinEndpoint, DstChain: BasecoinEndpoint> {
pub runtime: TokioRuntimeContext,
pub relay_a_to_b: Arc<MockCosmosRelay<SrcChain, DstChain>>,
pub relay_b_to_a: Arc<MockCosmosRelay<DstChain, SrcChain>>,
}

impl<SrcChain: BasecoinEndpoint, DstChain: BasecoinEndpoint> MockCosmosBiRelay<SrcChain, DstChain> {
pub fn new(
runtime: TokioRuntimeContext,
relay_a_to_b: Arc<MockCosmosRelay<SrcChain, DstChain>>,
relay_b_to_a: Arc<MockCosmosRelay<DstChain, SrcChain>>,
) -> Self {
Self {
runtime,
relay_a_to_b,
relay_b_to_a,
}
}

pub fn relay_a_to_b(&self) -> &Arc<MockCosmosRelay<SrcChain, DstChain>> {
&self.relay_a_to_b
}

pub fn relay_b_to_a(&self) -> &Arc<MockCosmosRelay<DstChain, SrcChain>> {
&self.relay_b_to_a
}
}
46 changes: 46 additions & 0 deletions crates/relayer-cosmos-mock/src/contexts/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use alloc::sync::Arc;
use basecoin_store::impls::InMemoryStore;
use ibc::core::ics24_host::identifier::ChainId;
use ibc_relayer_runtime::types::runtime::TokioRuntimeContext;
use tendermint_testgen::Validator;
use tokio::runtime::Runtime as TokioRuntime;

use super::{basecoin::MockBasecoin, chain::MockCosmosContext, relay::MockCosmosRelay};
use crate::{traits::endpoint::BasecoinEndpoint, types::error::Error};

pub struct MockCosmosBuilder {
pub runtime: TokioRuntimeContext,
}

impl MockCosmosBuilder {
pub fn new(runtime: TokioRuntime) -> Self {
Self {
runtime: TokioRuntimeContext::new(Arc::new(runtime)),
}
}

pub fn build_chain(
&mut self,
chain_id: ChainId,
validators: Vec<Validator>,
) -> Arc<MockBasecoin<InMemoryStore>> {
let chain = Arc::new(MockBasecoin::new(
self.runtime.clone(),
chain_id,
validators,
InMemoryStore::default(),
));

chain.run();

chain
}

pub fn build_relay<SrcChain: BasecoinEndpoint, DstChain: BasecoinEndpoint>(
&self,
src_chain_ctx: Arc<MockCosmosContext<SrcChain>>,
dst_chain_ctx: Arc<MockCosmosContext<DstChain>>,
) -> Result<MockCosmosRelay<SrcChain, DstChain>, Error> {
MockCosmosRelay::new(self.runtime.clone(), src_chain_ctx, dst_chain_ctx)
}
}
52 changes: 52 additions & 0 deletions crates/relayer-cosmos-mock/src/contexts/chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use basecoin_app::modules::ibc::IbcContext;
use basecoin_store::impls::RevertibleStore;
use ibc::core::events::IbcEvent;
use ibc::core::ValidationContext;
use ibc::Any;
use ibc_relayer_runtime::types::runtime::TokioRuntimeContext;

use std::sync::Arc;

use crate::traits::endpoint::BasecoinEndpoint;
use crate::types::error::Error;

Farhad-Shabani marked this conversation as resolved.
Show resolved Hide resolved
/// Holds the necessary fields for querying a mock Cosmos
/// chain endpoint.
#[derive(Clone)]
pub struct MockCosmosContext<Endpoint: BasecoinEndpoint> {
/// Chain runtime
pub runtime: TokioRuntimeContext,
/// Chain handle
pub querier: Arc<Endpoint>,
}

impl<Endpoint: BasecoinEndpoint> MockCosmosContext<Endpoint> {
/// Constructs a new mock cosmos chain instance.
pub fn new(runtime: TokioRuntimeContext, querier: Arc<Endpoint>) -> Self {
Self { runtime, querier }
}

pub fn runtime(&self) -> &TokioRuntimeContext {
&self.runtime
}

pub fn ibc_context(
&self,
) -> IbcContext<RevertibleStore<<Endpoint as BasecoinEndpoint>::Store>> {
self.ibc().ctx()
}

pub fn submit_messages(&self, msgs: Vec<Any>) -> Result<Vec<Vec<IbcEvent>>, Error> {
let mut events = Vec::new();

self.ibc_context().host_height()?;

for msg in msgs {
let ibc_events = self.ibc().process_message(msg)?;

events.push(ibc_events);
}

Ok(events)
}
}
5 changes: 5 additions & 0 deletions crates/relayer-cosmos-mock/src/contexts/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod basecoin;
pub mod birelay;
pub mod builder;
pub mod chain;
pub mod relay;
Loading