use core::time::Duration;
use eyre::{eyre, Report as Error};
use ibc_relayer::chain::handle::ChainHandle;
use ibc_relayer::config::default::connection_delay as default_connection_delay;
use ibc_relayer::connection::{Connection, ConnectionSide};
use ibc_relayer_types::timestamp::ZERO_DURATION;
use tracing::{debug, info};
use crate::relayer::connection::TaggedConnectionExt;
use crate::types::binary::client::ClientIdPair;
use crate::types::binary::connection::ConnectedConnection;
use crate::types::binary::foreign_client::ForeignClientPair;
use crate::types::id::TaggedClientIdRef;
use crate::util::random::random_u64_range;
pub struct BootstrapConnectionOptions {
pub connection_delay: Duration,
pub pad_connection_id_a: u64,
pub pad_connection_id_b: u64,
}
pub fn bootstrap_connection<ChainA: ChainHandle, ChainB: ChainHandle>(
foreign_clients: &ForeignClientPair<ChainA, ChainB>,
options: BootstrapConnectionOptions,
) -> Result<ConnectedConnection<ChainA, ChainB>, Error> {
let chain_a = foreign_clients.handle_a();
let chain_b = foreign_clients.handle_b();
let client_id_a = foreign_clients.client_id_a();
let client_id_b = foreign_clients.client_id_b();
pad_connection_id(
&chain_a,
&chain_b,
&client_id_a,
&client_id_b,
options.pad_connection_id_a,
)?;
pad_connection_id(
&chain_b,
&chain_a,
&client_id_b,
&client_id_a,
options.pad_connection_id_b,
)?;
let connection = Connection::new(
foreign_clients.client_b_to_a.clone(),
foreign_clients.client_a_to_b.clone(),
options.connection_delay,
)?;
let connection_id_a = connection
.tagged_connection_id_a()
.ok_or_else(|| eyre!("expected connection id to present"))?
.cloned();
let connection_id_b = connection
.tagged_connection_id_b()
.ok_or_else(|| eyre!("expected connection id to present"))?
.cloned();
info!(
"created new chain/client/connection from {}/{}/{} to {}/{}/{}",
chain_a.id(),
client_id_a,
connection_id_a,
chain_b.id(),
client_id_b,
connection_id_b,
);
let connected_connection = ConnectedConnection::new(
ClientIdPair::new(client_id_a.cloned(), client_id_b.cloned()),
connection,
connection_id_a,
connection_id_b,
);
Ok(connected_connection)
}
pub fn pad_connection_id<ChainA: ChainHandle, ChainB: ChainHandle>(
chain_a: &ChainA,
chain_b: &ChainB,
client_id_a: &TaggedClientIdRef<ChainA, ChainB>,
client_id_b: &TaggedClientIdRef<ChainB, ChainA>,
pad_count: u64,
) -> Result<(), Error> {
for i in 0..pad_count {
debug!(
"creating new connection id {} on chain {}",
i + 1,
chain_a.id()
);
let connection: Connection<ChainB, ChainA> = Connection {
delay_period: ZERO_DURATION,
a_side: ConnectionSide::new(chain_b.clone(), client_id_b.cloned().into_value(), None),
b_side: ConnectionSide::new(chain_a.clone(), client_id_a.cloned().into_value(), None),
};
connection.build_conn_init_and_send()?;
}
Ok(())
}
impl Default for BootstrapConnectionOptions {
fn default() -> Self {
Self {
connection_delay: default_connection_delay(),
pad_connection_id_a: 0,
pad_connection_id_b: 0,
}
}
}
impl BootstrapConnectionOptions {
pub fn connection_delay(mut self, connection_delay: Duration) -> Self {
self.connection_delay = connection_delay;
self
}
pub fn bootstrap_with_random_ids(mut self, bootstrap_with_random_ids: bool) -> Self {
if bootstrap_with_random_ids {
self.pad_connection_id_a = random_u64_range(0, 6);
self.pad_connection_id_b = random_u64_range(0, 6);
} else {
self.pad_connection_id_a = 0;
self.pad_connection_id_b = 1;
}
self
}
}