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

feat: move stacks client into signer context #598

Merged
merged 2 commits into from
Oct 2, 2024
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
7 changes: 5 additions & 2 deletions signer/src/bitcoin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@ pub trait BitcoinInteract: Sync + Send {
) -> impl Future<Output = Result<Option<bitcoin::Block>, Error>> + Send;

/// get tx
fn get_tx(&self, txid: &Txid) -> impl Future<Output = Result<Option<GetTxResponse>, Error>>;
fn get_tx(
&self,
txid: &Txid,
) -> impl Future<Output = Result<Option<GetTxResponse>, Error>> + Send;

/// get tx info
fn get_tx_info(
&self,
txid: &Txid,
block_hash: &BlockHash,
) -> impl Future<Output = Result<Option<BitcoinTxInfo>, Error>>;
) -> impl Future<Output = Result<Option<BitcoinTxInfo>, Error>> + Send;

/// Estimate fee rate
// This should be implemented with the help of the `fees::EstimateFees` trait
Expand Down
4 changes: 4 additions & 0 deletions signer/src/block_observer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ mod tests {
Settings::new_from_default_config().unwrap(),
storage.clone(),
test_harness.clone(),
test_harness.clone(),
);
// There must be at least one signal receiver alive when the block observer
// later tries to send a signal, hence this line.
Expand Down Expand Up @@ -495,6 +496,7 @@ mod tests {
Settings::new_from_default_config().unwrap(),
storage.clone(),
test_harness.clone(),
test_harness.clone(),
);

let mut block_observer = BlockObserver {
Expand Down Expand Up @@ -572,6 +574,7 @@ mod tests {
Settings::new_from_default_config().unwrap(),
storage.clone(),
test_harness.clone(),
test_harness.clone(),
);

let mut block_observer = BlockObserver {
Expand Down Expand Up @@ -640,6 +643,7 @@ mod tests {
Settings::new_from_default_config().unwrap(),
storage.clone(),
test_harness.clone(),
test_harness.clone(),
);

// Now let's create two transactions, one spending to the signers
Expand Down
29 changes: 21 additions & 8 deletions signer/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use url::Url;
use crate::bitcoin::BitcoinInteract;
use crate::config::Settings;
use crate::error::Error;
use crate::stacks::api::StacksInteract;
use crate::storage::DbRead;
use crate::storage::DbWrite;
pub use messaging::*;
Expand All @@ -33,12 +34,14 @@ pub trait Context: Clone + Sync + Send {
fn get_storage_mut(&self) -> impl DbRead + DbWrite + Clone + Sync + Send;
/// Get a handle to a Bitcoin client.
fn get_bitcoin_client(&self) -> impl BitcoinInteract + Clone;
/// Get a handler to the Stacks client.
fn get_stacks_client(&self) -> impl StacksInteract + Clone;
}

/// Signer context which is passed to different components within the
/// signer binary.
#[derive(Debug, Clone)]
pub struct SignerContext<S, BC> {
pub struct SignerContext<S, BC, ST> {
config: Settings,
// Handle to the app signalling channel. This keeps the channel alive
// for the duration of the program and is used both to send messages
Expand All @@ -55,36 +58,40 @@ pub struct SignerContext<S, BC> {
// TODO: Additional clients to be added in future PRs. We may want
// to break the clients out into a separate struct to keep the field
// count down.
// /// Handle to a Stacks-RPC fallback-client.
//stacks_client: ApiFallbackClient<ST>,
/// Handle to a Stacks-RPC fallback-client.
stacks_client: ST,
// /// Handle to a Emily-API fallback-client.
//emily_client: ApiFallbackClient<EM>,
// /// Handle to a Blocklist-API fallback-client.
//blocklist_client: ApiFallbackClient<BL>,
}

impl<S, BC> SignerContext<S, BC>
impl<S, BC, ST> SignerContext<S, BC, ST>
where
S: DbRead + DbWrite + Clone + Sync + Send,
BC: for<'a> TryFrom<&'a [Url]> + BitcoinInteract + Clone + Sync + Send + 'static,
ST: for<'a> TryFrom<&'a Settings> + StacksInteract + Clone + Sync + Send + 'static,
Error: for<'a> From<<BC as TryFrom<&'a [Url]>>::Error>,
Error: for<'a> From<<ST as TryFrom<&'a Settings>>::Error>,
{
/// Initializes a new [`SignerContext`], automatically creating clients
/// based on the provided types.
pub fn init(config: Settings, db: S) -> Result<Self, Error> {
let bc = BC::try_from(&config.bitcoin.rpc_endpoints)?;
let st = ST::try_from(&config)?;

Ok(Self::new(config, db, bc))
Ok(Self::new(config, db, bc, st))
}
}

impl<S, BC> SignerContext<S, BC>
impl<S, BC, ST> SignerContext<S, BC, ST>
where
S: DbRead + DbWrite + Clone + Sync + Send,
BC: BitcoinInteract + Clone + Sync + Send,
ST: StacksInteract + Clone + Sync + Send,
{
/// Create a new signer context.
pub fn new(config: Settings, db: S, bitcoin_client: BC) -> Self {
pub fn new(config: Settings, db: S, bitcoin_client: BC, stacks_client: ST) -> Self {
// TODO: Decide on the channel capacity and how we should handle slow consumers.
// NOTE: Ideally consumers which require processing time should pull the relevent
// messages into a local VecDequeue and process them in their own time.
Expand All @@ -97,14 +104,16 @@ where
term_tx,
storage: db,
bitcoin_client,
stacks_client,
}
}
}

impl<S, BC> Context for SignerContext<S, BC>
impl<S, BC, ST> Context for SignerContext<S, BC, ST>
where
S: DbRead + DbWrite + Clone + Sync + Send,
BC: BitcoinInteract + Clone + Sync + Send,
ST: StacksInteract + Clone + Sync + Send,
{
fn config(&self) -> &Settings {
&self.config
Expand Down Expand Up @@ -147,6 +156,10 @@ where
fn get_bitcoin_client(&self) -> impl BitcoinInteract + Clone {
self.bitcoin_client.clone()
}

fn get_stacks_client(&self) -> impl StacksInteract + Clone {
self.stacks_client.clone()
}
}

#[cfg(test)]
Expand Down
6 changes: 5 additions & 1 deletion signer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}

// Initialize the signer context.
let context = SignerContext::<_, ApiFallbackClient<BitcoinCoreClient>>::init(settings, db)?;
let context = SignerContext::<
_,
ApiFallbackClient<BitcoinCoreClient>,
ApiFallbackClient<StacksClient>,
>::init(settings, db)?;

// Run the application components concurrently. We're `join!`ing them
// here so that every component can shut itself down gracefully when
Expand Down
8 changes: 8 additions & 0 deletions signer/src/testing/api_clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::bitcoin::rpc::GetTxResponse;
use crate::bitcoin::BitcoinInteract;
use crate::bitcoin::MockBitcoinInteract;
use crate::blocklist_client::BlocklistChecker;
use crate::config::Settings;
use crate::emily_client::EmilyInteract;
use crate::error::Error;
use crate::stacks::api::StacksInteract;
Expand All @@ -23,6 +24,13 @@ impl TryFrom<&[Url]> for NoopApiClient {
}
}

impl TryFrom<&Settings> for NoopApiClient {
type Error = Error;
fn try_from(_value: &Settings) -> Result<Self, Self::Error> {
Ok(NoopApiClient)
}
}

/// Noop implementation of the BitcoinInteract trait.
impl BitcoinInteract for NoopApiClient {
async fn get_tx(&self, _: &bitcoin::Txid) -> Result<Option<GetTxResponse>, Error> {
Expand Down
11 changes: 9 additions & 2 deletions signer/src/testing/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ use crate::{
config::Settings,
context::{Context, SignerContext},
error::Error,
stacks::api::StacksInteract,
storage::in_memory::{SharedStore, Store},
};

use super::api_clients::NoopApiClient;

/// A [`Context`] which can be used for testing.
///
/// This context is opinionated and uses a shared in-memory store and mocked
Expand All @@ -24,7 +27,7 @@ use crate::{
#[derive(Clone)]
pub struct TestContext<BC> {
/// The inner [`SignerContext`] which this context wraps.
pub inner: SignerContext<SharedStore, BC>,
pub inner: SignerContext<SharedStore, BC, NoopApiClient>,

/// The mocked bitcoin client.
pub bitcoin_client: BC,
Expand All @@ -39,7 +42,7 @@ where
let settings = Settings::new_from_default_config().unwrap();
let store = Store::new_shared();

let context = SignerContext::new(settings, store, bitcoin_client.clone());
let context = SignerContext::new(settings, store, bitcoin_client.clone(), NoopApiClient);

Self { inner: context, bitcoin_client }
}
Expand Down Expand Up @@ -102,6 +105,10 @@ where
fn get_bitcoin_client(&self) -> impl BitcoinInteract + Clone {
self.inner.get_bitcoin_client()
}

fn get_stacks_client(&self) -> impl StacksInteract + Clone {
NoopApiClient
}
}

/// A wrapper around a mock which can be cloned and shared between threads.
Expand Down
6 changes: 3 additions & 3 deletions signer/src/testing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::storage::postgres::PgStore;
pub const DEFAULT_CONFIG_PATH: Option<&str> = Some("./src/config/default");

/// A [`SignerContext`] which uses [`NoopApiClient`]s.
pub type NoopSignerContext<S> = SignerContext<S, NoopApiClient>;
pub type NoopSignerContext<S> = SignerContext<S, NoopApiClient, NoopApiClient>;

impl Settings {
/// Create a new `Settings` instance from the default configuration file.
Expand All @@ -42,7 +42,7 @@ impl Settings {
/// A client that can be used for integration tests. The settings are
/// loaded from the default config toml, and the PgStore is assumed to
/// point to a test database.
pub type TestSignerContext = SignerContext<PgStore, BitcoinCoreClient>;
pub type TestSignerContext = SignerContext<PgStore, BitcoinCoreClient, NoopApiClient>;

impl TestSignerContext {
/// Create a new one from the given database connection pool with the
Expand All @@ -52,7 +52,7 @@ impl TestSignerContext {

let url = config.bitcoin.rpc_endpoints.first().unwrap();
let bitcoin_client = BitcoinCoreClient::try_from(url).unwrap();
Self::new(config, db, bitcoin_client)
Self::new(config, db, bitcoin_client, NoopApiClient)
}
}

Expand Down
Loading