Skip to content

Commit c8260d9

Browse files
committed
Add /signers/tickers route to aggregator
1 parent 5449440 commit c8260d9

File tree

9 files changed

+234
-37
lines changed

9 files changed

+234
-37
lines changed

mithril-aggregator/src/database/provider/signer.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ use mithril_common::StdResult;
1313

1414
use crate::signer_registerer::SignerRecorder;
1515

16+
#[cfg(test)]
17+
use mockall::automock;
18+
1619
/// Signer record is the representation of a stored signer.
1720
#[derive(Debug, PartialEq, Clone)]
1821
pub struct SignerRecord {
@@ -273,6 +276,14 @@ impl<'conn> Provider<'conn> for ImportSignerRecordProvider<'conn> {
273276
}
274277
}
275278

279+
/// Service to get [SignerRecord].
280+
#[cfg_attr(test, automock)]
281+
#[async_trait]
282+
pub trait SignerGetter: Sync + Send {
283+
/// Return all stored records.
284+
async fn get_all(&self) -> StdResult<Vec<SignerRecord>>;
285+
}
286+
276287
/// Service to deal with signer (read & write).
277288
pub struct SignerStore {
278289
connection: Arc<Mutex<Connection>>,
@@ -284,15 +295,6 @@ impl SignerStore {
284295
Self { connection }
285296
}
286297

287-
/// Return all stored [SignerRecord].
288-
pub async fn get_all(&self) -> StdResult<Vec<SignerRecord>> {
289-
let connection = &*self.connection.lock().await;
290-
let provider = SignerRecordProvider::new(connection);
291-
let cursor = provider.get_all()?;
292-
293-
Ok(cursor.collect())
294-
}
295-
296298
/// Import a signer in the database, its registered_at date will be left empty
297299
pub async fn import_signer(
298300
&self,
@@ -363,6 +365,17 @@ impl SignerRecorder for SignerStore {
363365
}
364366
}
365367

368+
#[async_trait]
369+
impl SignerGetter for SignerStore {
370+
async fn get_all(&self) -> StdResult<Vec<SignerRecord>> {
371+
let connection = &*self.connection.lock().await;
372+
let provider = SignerRecordProvider::new(connection);
373+
let cursor = provider.get_all()?;
374+
375+
Ok(cursor.collect())
376+
}
377+
}
378+
366379
#[cfg(test)]
367380
mod tests {
368381
use crate::database::provider::apply_all_migrations_to_db;

mithril-aggregator/src/dependency_injection/builder.rs

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ use tokio::{
3939
};
4040
use warp::Filter;
4141

42-
use crate::tools::{CExplorerSignerTickerRetriever, SignerTickersImporter, SignerTickersPersister};
4342
use crate::{
4443
artifact_builder::{
4544
CardanoImmutableFilesFullArtifactBuilder, MithrilStakeDistributionArtifactBuilder,
@@ -57,8 +56,10 @@ use crate::{
5756
MithrilStakeDistributionService, MithrilTickerService, SignedEntityService,
5857
StakeDistributionService, TickerService,
5958
},
60-
signer_registerer::SignerRecorder,
61-
tools::{GcpFileUploader, GenesisToolsDependency},
59+
tools::{
60+
CExplorerSignerTickerRetriever, GcpFileUploader, GenesisToolsDependency,
61+
SignerTickersImporter,
62+
},
6263
AggregatorConfig, AggregatorRunner, AggregatorRuntime, CertificatePendingStore,
6364
CompressedArchiveSnapshotter, Configuration, DependencyContainer, DumbSnapshotUploader,
6465
DumbSnapshotter, LocalSnapshotUploader, MithrilSignerRegisterer, MultiSigner, MultiSignerImpl,
@@ -671,7 +672,7 @@ impl DependenciesBuilder {
671672
let registerer = MithrilSignerRegisterer::new(
672673
self.get_chain_observer().await?,
673674
self.get_verification_key_store().await?,
674-
self.get_signer_recorder().await?,
675+
self.get_signer_store().await?,
675676
self.configuration.safe_epoch_retention_limit(),
676677
);
677678

@@ -862,22 +863,16 @@ impl DependenciesBuilder {
862863
Ok(signer_store)
863864
}
864865

865-
/// [SignerRecorder] service
866-
pub async fn get_signer_recorder(&mut self) -> Result<Arc<dyn SignerRecorder>> {
867-
if self.signer_store.is_none() {
868-
self.signer_store = Some(self.build_signer_store().await?);
869-
}
870-
871-
Ok(self.signer_store.as_ref().cloned().unwrap())
872-
}
873-
874-
/// [SignerTickersPersister] service
875-
pub async fn get_signer_ticker_persister(&mut self) -> Result<Arc<dyn SignerTickersPersister>> {
876-
if self.signer_store.is_none() {
877-
self.signer_store = Some(self.build_signer_store().await?);
866+
/// [SignerStore] service
867+
pub async fn get_signer_store(&mut self) -> Result<Arc<SignerStore>> {
868+
match self.signer_store.as_ref().cloned() {
869+
None => {
870+
let store = self.build_signer_store().await?;
871+
self.signer_store = Some(store.clone());
872+
Ok(store)
873+
}
874+
Some(store) => Ok(store),
878875
}
879-
880-
Ok(self.signer_store.as_ref().cloned().unwrap())
881876
}
882877

883878
async fn build_signable_builder_service(&mut self) -> Result<Arc<dyn SignableBuilderService>> {
@@ -984,12 +979,13 @@ impl DependenciesBuilder {
984979
event_transmitter: self.get_event_transmitter().await?,
985980
api_version_provider: self.get_api_version_provider().await?,
986981
stake_distribution_service: self.get_stake_distribution_service().await?,
987-
signer_recorder: self.get_signer_recorder().await?,
982+
signer_recorder: self.get_signer_store().await?,
988983
signable_builder_service: self.get_signable_builder_service().await?,
989984
signed_entity_service: self.get_signed_entity_service().await?,
990985
certifier_service: self.get_certifier_service().await?,
991986
ticker_service: self.get_ticker_service().await?,
992987
signed_entity_storer: self.get_signed_entity_storer().await?,
988+
signer_getter: self.get_signer_store().await?,
993989
};
994990

995991
Ok(dependency_manager)
@@ -1110,7 +1106,7 @@ impl DependenciesBuilder {
11101106
cexplorer_pools_url,
11111107
Some(Duration::from_secs(30)),
11121108
)?;
1113-
let persister = self.get_signer_ticker_persister().await?;
1109+
let persister = self.get_signer_store().await?;
11141110

11151111
Ok(SignerTickersImporter::new(Arc::new(retriever), persister))
11161112
}

mithril-aggregator/src/dependency_injection/containers.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ use mithril_common::{
1616
BeaconProvider,
1717
};
1818

19-
use crate::database::provider::CertificateRepository;
2019
use crate::{
2120
configuration::*,
22-
database::provider::{SignedEntityStorer, StakePoolStore},
21+
database::provider::{CertificateRepository, SignedEntityStorer, SignerGetter, StakePoolStore},
2322
event_store::{EventMessage, TransmitterService},
2423
multi_signer::MultiSigner,
2524
services::{CertifierService, SignedEntityService, StakeDistributionService, TickerService},
@@ -123,6 +122,9 @@ pub struct DependencyContainer {
123122

124123
/// Signed Entity storer
125124
pub signed_entity_storer: Arc<dyn SignedEntityStorer>,
125+
126+
/// Signer getter service
127+
pub signer_getter: Arc<dyn SignerGetter>,
126128
}
127129

128130
#[doc(hidden)]

mithril-aggregator/src/entities/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
//! This module provide domain entities for the services & state machine.
44
mod open_message;
55
mod signer_registration_message;
6+
mod signer_ticker_message;
67

78
pub use open_message::OpenMessage;
89
pub use signer_registration_message::{
910
SignerRegistrationsListItemMessage, SignerRegistrationsMessage,
1011
};
12+
pub use signer_ticker_message::SignerTickerMessage;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use mithril_common::entities::PartyId;
2+
use serde::{Deserialize, Serialize};
3+
4+
/// Message structure of a known signer
5+
#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
6+
pub struct SignerTickerMessage {
7+
/// The signer party id
8+
pub party_id: PartyId,
9+
10+
/// The signer pool ticker
11+
#[serde(skip_serializing_if = "Option::is_none")]
12+
pub pool_ticker: Option<String>,
13+
14+
/// True if the signer have registered at least once
15+
pub has_registered: bool,
16+
}

mithril-aggregator/src/http_server/routes/middlewares.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
SignerRegisterer, VerificationKeyStorer,
88
};
99

10+
use crate::database::provider::SignerGetter;
1011
use mithril_common::{api_version::APIVersionProvider, BeaconProvider};
1112
use std::convert::Infallible;
1213
use std::sync::Arc;
@@ -40,6 +41,13 @@ pub fn with_signer_registerer(
4041
warp::any().map(move || dependency_manager.signer_registerer.clone())
4142
}
4243

44+
/// With signer getter middleware
45+
pub fn with_signer_getter(
46+
dependency_manager: Arc<DependencyContainer>,
47+
) -> impl Filter<Extract = (Arc<dyn SignerGetter>,), Error = Infallible> + Clone {
48+
warp::any().map(move || dependency_manager.signer_getter.clone())
49+
}
50+
4351
/// With config middleware
4452
pub fn with_config(
4553
dependency_manager: Arc<DependencyContainer>,

mithril-aggregator/src/http_server/routes/signer_routes.rs

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ const MITHRIL_SIGNER_VERSION_HEADER: &str = "signer-node-version";
88
pub fn routes(
99
dependency_manager: Arc<DependencyContainer>,
1010
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
11-
register_signer(dependency_manager.clone()).or(registered_signers(dependency_manager))
11+
register_signer(dependency_manager.clone())
12+
.or(registered_signers(dependency_manager.clone()))
13+
.or(signers_tickers(dependency_manager))
1214
}
1315

1416
/// POST /register-signer
@@ -31,6 +33,16 @@ fn register_signer(
3133
.and_then(handlers::register_signer)
3234
}
3335

36+
/// Get /signers/tickers
37+
fn signers_tickers(
38+
dependency_manager: Arc<DependencyContainer>,
39+
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
40+
warp::path!("signers" / "tickers")
41+
.and(warp::get())
42+
.and(middlewares::with_signer_getter(dependency_manager))
43+
.and_then(handlers::signers_tickers)
44+
}
45+
3446
/// Get /signers/registered/:epoch
3547
fn registered_signers(
3648
dependency_manager: Arc<DependencyContainer>,
@@ -42,7 +54,8 @@ fn registered_signers(
4254
}
4355

4456
mod handlers {
45-
use crate::entities::SignerRegistrationsMessage;
57+
use crate::database::provider::SignerGetter;
58+
use crate::entities::{SignerRegistrationsMessage, SignerTickerMessage};
4659
use crate::event_store::{EventMessage, TransmitterService};
4760
use crate::{http_server::routes::reply, SignerRegisterer, SignerRegistrationError};
4861
use crate::{FromRegisterSignerAdapter, VerificationKeyStorer};
@@ -187,6 +200,30 @@ mod handlers {
187200
}
188201
}
189202
}
203+
204+
pub async fn signers_tickers(
205+
signer_getter: Arc<dyn SignerGetter>,
206+
) -> Result<impl warp::Reply, Infallible> {
207+
debug!("⇄ HTTP SERVER: signers/tickers");
208+
209+
match signer_getter.get_all().await {
210+
Ok(signers) => {
211+
let message: Vec<_> = signers
212+
.into_iter()
213+
.map(|s| SignerTickerMessage {
214+
party_id: s.signer_id,
215+
pool_ticker: s.pool_ticker,
216+
has_registered: s.registered_at.is_some(),
217+
})
218+
.collect();
219+
Ok(reply::json(&message, StatusCode::OK))
220+
}
221+
Err(err) => {
222+
warn!("registered_signers::error"; "error" => ?err);
223+
Ok(reply::internal_server_error(err.to_string()))
224+
}
225+
}
226+
}
190227
}
191228

192229
#[cfg(test)]
@@ -204,6 +241,7 @@ mod tests {
204241
use serde_json::Value::Null;
205242
use warp::{http::Method, test::request};
206243

244+
use crate::database::provider::{MockSignerGetter, SignerRecord};
207245
use crate::{
208246
http_server::SERVER_BASE_PATH, initialize_dependencies,
209247
signer_registerer::MockSignerRegisterer, store::MockVerificationKeyStorer,
@@ -497,4 +535,79 @@ mod tests {
497535
&response,
498536
);
499537
}
538+
539+
#[tokio::test]
540+
async fn test_signers_tickers_get_ok() {
541+
let mut mock_signer_getter = MockSignerGetter::new();
542+
mock_signer_getter
543+
.expect_get_all()
544+
.return_once(|| {
545+
Ok(vec![
546+
SignerRecord {
547+
signer_id: "pool_without_ticker".to_string(),
548+
pool_ticker: None,
549+
created_at: Default::default(),
550+
updated_at: Default::default(),
551+
registered_at: None,
552+
},
553+
SignerRecord {
554+
signer_id: "pool_with_ticker".to_string(),
555+
pool_ticker: Some("pool_ticker".to_string()),
556+
created_at: Default::default(),
557+
updated_at: Default::default(),
558+
registered_at: None,
559+
},
560+
])
561+
})
562+
.once();
563+
let mut dependency_manager = initialize_dependencies().await;
564+
dependency_manager.signer_getter = Arc::new(mock_signer_getter);
565+
566+
let method = Method::GET.as_str();
567+
let path = "/signers/tickers";
568+
569+
let response = request()
570+
.method(method)
571+
.path(&format!("/{SERVER_BASE_PATH}{path}"))
572+
.reply(&setup_router(Arc::new(dependency_manager)))
573+
.await;
574+
575+
APISpec::verify_conformity(
576+
APISpec::get_all_spec_files(),
577+
method,
578+
path,
579+
"application/json",
580+
&Null,
581+
&response,
582+
);
583+
}
584+
585+
#[tokio::test]
586+
async fn test_signers_tickers_get_ko() {
587+
let mut mock_signer_getter = MockSignerGetter::new();
588+
mock_signer_getter
589+
.expect_get_all()
590+
.return_once(|| Err(anyhow!("an error")))
591+
.once();
592+
let mut dependency_manager = initialize_dependencies().await;
593+
dependency_manager.signer_getter = Arc::new(mock_signer_getter);
594+
595+
let method = Method::GET.as_str();
596+
let path = "/signers/tickers";
597+
598+
let response = request()
599+
.method(method)
600+
.path(&format!("/{SERVER_BASE_PATH}{path}"))
601+
.reply(&setup_router(Arc::new(dependency_manager)))
602+
.await;
603+
604+
APISpec::verify_conformity(
605+
APISpec::get_all_spec_files(),
606+
method,
607+
path,
608+
"application/json",
609+
&Null,
610+
&response,
611+
);
612+
}
500613
}

mithril-aggregator/src/tools/signer_tickers_importer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ mod tests {
188188
use warp::Filter;
189189

190190
use crate::database::provider::{
191-
apply_all_migrations_to_db, disable_foreign_key_support, SignerStore,
191+
apply_all_migrations_to_db, disable_foreign_key_support, SignerGetter, SignerStore,
192192
};
193193
use crate::http_server::routes::reply;
194194

0 commit comments

Comments
 (0)