From 372bfa51b8779640bf35531c54f4d08aa6927055 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Raynaud Date: Wed, 19 Apr 2023 12:25:02 +0200 Subject: [PATCH] Add Signed Entity Type to Pending Certificate --- mithril-aggregator/src/certifier_service.rs | 3 +-- .../src/database/provider/open_message.rs | 2 +- .../to_certificate_pending_message.rs | 4 +++- mithril-aggregator/src/runtime/runner.rs | 17 ++++++++++++---- .../src/runtime/state_machine.rs | 13 ++++++++---- .../src/store/pending_certificate_store.rs | 5 ++++- .../src/entities/certificate_pending.rs | 9 ++++++++- .../src/entities/signed_entity_type.rs | 3 ++- .../src/messages/certificate_pending.rs | 20 +++++++++++++------ mithril-common/src/test_utils/fake_data.rs | 7 ++++++- mithril-signer/src/certificate_handler.rs | 6 +++++- .../from_pending_certificate_message.rs | 12 ++++++----- .../test_extensions/certificate_handler.rs | 3 ++- openapi.yaml | 7 ++++++- 14 files changed, 81 insertions(+), 30 deletions(-) diff --git a/mithril-aggregator/src/certifier_service.rs b/mithril-aggregator/src/certifier_service.rs index d77090dbca9..bcf04770ee4 100644 --- a/mithril-aggregator/src/certifier_service.rs +++ b/mithril-aggregator/src/certifier_service.rs @@ -4,8 +4,7 @@ use async_trait::async_trait; use chrono::Utc; use mithril_common::crypto_helper::{key_encode_hex, PROTOCOL_VERSION}; use mithril_common::entities::{ - Certificate, CertificateMetadata, Epoch, ProtocolMessage, SignedEntityType, SignerWithStake, - SingleSignatures, + Certificate, CertificateMetadata, Epoch, ProtocolMessage, SignedEntityType, SingleSignatures, }; use mithril_common::StdResult; use slog::Logger; diff --git a/mithril-aggregator/src/database/provider/open_message.rs b/mithril-aggregator/src/database/provider/open_message.rs index 18c5de6074f..9b964baf6cd 100644 --- a/mithril-aggregator/src/database/provider/open_message.rs +++ b/mithril-aggregator/src/database/provider/open_message.rs @@ -366,7 +366,7 @@ impl OpenMessageWithSingleSignatures { pub fn get_signers_id(&self) -> Vec { self.single_signatures .iter() - .map(|sig| sig.party_id) + .map(|sig| sig.party_id.to_owned()) .collect() } } diff --git a/mithril-aggregator/src/message_adapters/to_certificate_pending_message.rs b/mithril-aggregator/src/message_adapters/to_certificate_pending_message.rs index 924b6e65cc1..b7d0c2789aa 100644 --- a/mithril-aggregator/src/message_adapters/to_certificate_pending_message.rs +++ b/mithril-aggregator/src/message_adapters/to_certificate_pending_message.rs @@ -11,6 +11,8 @@ impl ToCertificatePendingMessageAdapter { pub fn adapt(certificate_pending: CertificatePending) -> CertificatePendingMessage { CertificatePendingMessage { beacon: certificate_pending.beacon, + signed_entity_type: serde_json::to_string(&certificate_pending.signed_entity_type) + .unwrap(), protocol_parameters: certificate_pending.protocol_parameters, next_protocol_parameters: certificate_pending.next_protocol_parameters, signers: Self::adapt_signers(certificate_pending.signers), @@ -55,7 +57,7 @@ mod tests { let certificate_pending = CertificatePending { signers, next_signers, - ..Default::default() + ..fake_data::certificate_pending() }; let message = ToCertificatePendingMessageAdapter::adapt(certificate_pending); diff --git a/mithril-aggregator/src/runtime/runner.rs b/mithril-aggregator/src/runtime/runner.rs index 2802b2e3890..9ddbb15d791 100644 --- a/mithril-aggregator/src/runtime/runner.rs +++ b/mithril-aggregator/src/runtime/runner.rs @@ -1,5 +1,6 @@ use async_trait::async_trait; use chrono::Utc; +use mithril_common::crypto_helper::key_decode_hex; use mithril_common::crypto_helper::ProtocolMultiSignature; use mithril_common::entities::Epoch; use mithril_common::entities::PartyId; @@ -117,6 +118,7 @@ pub trait AggregatorRunnerTrait: Sync + Send { async fn create_new_pending_certificate_from_multisigner( &self, beacon: Beacon, + signed_entity_type: &SignedEntityType, ) -> Result>; /// Return the actual working certificate from the multisigner. @@ -433,6 +435,7 @@ impl AggregatorRunnerTrait for AggregatorRunner { async fn create_new_pending_certificate_from_multisigner( &self, beacon: Beacon, + signed_entity_type: &SignedEntityType, ) -> Result> { debug!("RUNNER: create new pending certificate from multisigner"); let multi_signer = self.dependencies.multi_signer.read().await; @@ -469,6 +472,7 @@ impl AggregatorRunnerTrait for AggregatorRunner { let pending_certificate = CertificatePending::new( beacon, + signed_entity_type.to_owned(), protocol_parameters.into(), next_protocol_parameters.into(), signers, @@ -564,7 +568,8 @@ impl AggregatorRunnerTrait for AggregatorRunner { .create_certificate(signed_entity_type) .await?; - Ok(certificate) + // TODO: Quickfix, this function should be renamed to create_certificate and retrun a Result + Ok(certificate.map(|c| key_decode_hex(&c.multi_signature).unwrap())) } async fn create_snapshot_archive( @@ -745,7 +750,8 @@ pub mod tests { }; use mithril_common::digesters::DumbImmutableFileObserver; use mithril_common::entities::{ - Beacon, CertificatePending, HexEncodedKey, ProtocolMessage, StakeDistribution, + Beacon, CertificatePending, HexEncodedKey, ProtocolMessage, SignedEntityType, + StakeDistribution, }; use mithril_common::store::StakeStorer; use mithril_common::test_utils::MithrilFixtureBuilder; @@ -961,6 +967,7 @@ pub mod tests { let runner = AggregatorRunner::new(config, deps.clone()); let beacon = runner.get_beacon_from_chain().await.unwrap(); runner.update_beacon(&beacon).await.unwrap(); + let signed_entity_type = SignedEntityType::dummy(); let fixture = MithrilFixtureBuilder::default().with_signers(5).build(); let current_signers = fixture.signers_with_stake()[1..3].to_vec(); @@ -974,13 +981,14 @@ pub mod tests { .await; let mut certificate = runner - .create_new_pending_certificate_from_multisigner(beacon.clone()) + .create_new_pending_certificate_from_multisigner(beacon.clone(), &signed_entity_type) .await .unwrap(); certificate.signers.sort_by_key(|s| s.party_id.clone()); certificate.next_signers.sort_by_key(|s| s.party_id.clone()); let mut expected = CertificatePending::new( beacon, + signed_entity_type, protocol_parameters.clone(), protocol_parameters, current_signers.into_iter().map(|s| s.into()).collect(), @@ -999,6 +1007,7 @@ pub mod tests { let runner = AggregatorRunner::new(config, deps.clone()); let beacon = runner.get_beacon_from_chain().await.unwrap(); runner.update_beacon(&beacon).await.unwrap(); + let signed_entity_type = SignedEntityType::dummy(); let fixture = MithrilFixtureBuilder::default().with_signers(5).build(); @@ -1031,7 +1040,7 @@ pub mod tests { .unwrap(); let certificate_pending = runner - .create_new_pending_certificate_from_multisigner(beacon.clone()) + .create_new_pending_certificate_from_multisigner(beacon.clone(), &signed_entity_type) .await .unwrap(); diff --git a/mithril-aggregator/src/runtime/state_machine.rs b/mithril-aggregator/src/runtime/state_machine.rs index 98ec4efed4c..4d36ba81662 100644 --- a/mithril-aggregator/src/runtime/state_machine.rs +++ b/mithril-aggregator/src/runtime/state_machine.rs @@ -1,6 +1,6 @@ use crate::runtime::{AggregatorRunnerTrait, RuntimeError, WorkingCertificate}; -use mithril_common::entities::Beacon; +use mithril_common::entities::{Beacon, SignedEntityType}; use slog_scope::{crit, info, trace, warn}; use std::fmt::Display; use std::sync::Arc; @@ -324,6 +324,8 @@ impl AggregatorRuntime { new_beacon: Beacon, ) -> Result { trace!("launching transition from READY to SIGNING state"); + // TODO: Temporary, we need to compute the signed entity type from the current open message + let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(new_beacon.clone()); self.runner.update_beacon(&new_beacon).await?; let digester_result = self.runner.compute_digest(&new_beacon).await?; @@ -332,7 +334,10 @@ impl AggregatorRuntime { .await?; let certificate_pending = self .runner - .create_new_pending_certificate_from_multisigner(new_beacon.clone()) + .create_new_pending_certificate_from_multisigner( + new_beacon.clone(), + &signed_entity_type, + ) .await?; self.runner .save_pending_certificate(certificate_pending.clone()) @@ -584,9 +589,9 @@ mod tests { .returning(|_| Ok(())); runner .expect_create_new_pending_certificate_from_multisigner() - .with(predicate::eq(fake_data::beacon())) + //.with(predicate::eq(fake_data::beacon())) .once() - .returning(|_| Ok(fake_data::certificate_pending())); + .returning(|_, _| Ok(fake_data::certificate_pending())); runner .expect_create_new_working_certificate() .once() diff --git a/mithril-aggregator/src/store/pending_certificate_store.rs b/mithril-aggregator/src/store/pending_certificate_store.rs index 112cf44d94b..4fb522705cd 100644 --- a/mithril-aggregator/src/store/pending_certificate_store.rs +++ b/mithril-aggregator/src/store/pending_certificate_store.rs @@ -56,7 +56,7 @@ impl CertificatePendingStore { mod test { use super::*; - use mithril_common::entities::Beacon; + use mithril_common::entities::{Beacon, SignedEntityType}; use mithril_common::store::adapter::DumbStoreAdapter; use mithril_common::test_utils::fake_data; @@ -67,6 +67,7 @@ mod test { let beacon = Beacon::new("testnet".to_string(), 0, 0); let certificate_pending = CertificatePending::new( beacon.clone(), + SignedEntityType::dummy(), fake_data::protocol_parameters(), fake_data::protocol_parameters(), fake_data::signers(4), @@ -100,8 +101,10 @@ mod test { async fn save_certificate_pending_once() { let store = get_certificate_pending_store(false).await; let beacon = Beacon::new("testnet".to_string(), 0, 1); + let signed_entity_type = SignedEntityType::dummy(); let certificate_pending = CertificatePending::new( beacon, + signed_entity_type, fake_data::protocol_parameters(), fake_data::protocol_parameters(), fake_data::signers(1), diff --git a/mithril-common/src/entities/certificate_pending.rs b/mithril-common/src/entities/certificate_pending.rs index 60e12db9d14..9013df6dca0 100644 --- a/mithril-common/src/entities/certificate_pending.rs +++ b/mithril-common/src/entities/certificate_pending.rs @@ -1,12 +1,17 @@ use crate::entities::{Beacon, PartyId, ProtocolParameters, Signer}; use serde::{Deserialize, Serialize}; +use super::SignedEntityType; + /// CertificatePending represents a pending certificate in the process of production -#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct CertificatePending { /// Current Beacon pub beacon: Beacon, + /// Signed entity type + pub signed_entity_type: SignedEntityType, + /// Current Protocol parameters #[serde(rename = "protocol")] pub protocol_parameters: ProtocolParameters, @@ -26,6 +31,7 @@ impl CertificatePending { /// CertificatePending factory pub fn new( beacon: Beacon, + signed_entity_type: SignedEntityType, protocol_parameters: ProtocolParameters, next_protocol_parameters: ProtocolParameters, signers: Vec, @@ -33,6 +39,7 @@ impl CertificatePending { ) -> CertificatePending { CertificatePending { beacon, + signed_entity_type, protocol_parameters, next_protocol_parameters, signers, diff --git a/mithril-common/src/entities/signed_entity_type.rs b/mithril-common/src/entities/signed_entity_type.rs index 07b12565541..1d7629a70c4 100644 --- a/mithril-common/src/entities/signed_entity_type.rs +++ b/mithril-common/src/entities/signed_entity_type.rs @@ -1,3 +1,4 @@ +use serde::{Deserialize, Serialize}; use strum_macros::Display; use crate::{sqlite::HydrationError, StdError}; @@ -19,7 +20,7 @@ const ENTITY_TYPE_CARDANO_IMMUTABLE_FILES_FULL: usize = 2; /// are identified by their discriminant (i.e. index in the enum), thus the /// modification of this type should only ever consist of appending new /// variants. -#[derive(Display, Debug, Clone, PartialEq, Eq)] +#[derive(Display, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[strum(serialize_all = "PascalCase")] pub enum SignedEntityType { /// Mithril stake distribution diff --git a/mithril-common/src/messages/certificate_pending.rs b/mithril-common/src/messages/certificate_pending.rs index 2e0fb8ebd4f..860f96c1a41 100644 --- a/mithril-common/src/messages/certificate_pending.rs +++ b/mithril-common/src/messages/certificate_pending.rs @@ -4,7 +4,7 @@ use crate::{ crypto_helper::KESPeriod, entities::{ Beacon, HexEncodedOpCert, HexEncodedVerificationKey, HexEncodedVerificationKeySignature, - PartyId, ProtocolParameters, + PartyId, ProtocolParameters, SignedEntityType, }, }; @@ -14,6 +14,10 @@ pub struct CertificatePendingMessage { /// Current Beacon pub beacon: Beacon, + /// Signed entity type + #[serde(rename = "entity_type")] + pub signed_entity_type: String, + /// Current Protocol parameters #[serde(rename = "protocol")] pub protocol_parameters: ProtocolParameters, @@ -34,6 +38,7 @@ impl CertificatePendingMessage { pub fn dummy() -> Self { Self { beacon: Beacon::default(), + signed_entity_type: serde_json::to_string(&SignedEntityType::dummy()).unwrap(), protocol_parameters: ProtocolParameters { k: 5, m: 100, @@ -101,12 +106,14 @@ mod tests { use super::*; fn golden_message() -> CertificatePendingMessage { + let beacon = Beacon { + network: "preview".to_string(), + epoch: Epoch(86), + immutable_file_number: 1728, + }; CertificatePendingMessage { - beacon: Beacon { - network: "preview".to_string(), - epoch: Epoch(86), - immutable_file_number: 1728, - }, + beacon: beacon.clone(), + signed_entity_type: serde_json::to_string(&SignedEntityType::CardanoImmutableFilesFull(beacon)).unwrap(), protocol_parameters: ProtocolParameters { k: 5, m: 100, @@ -126,6 +133,7 @@ mod tests { fn test_v1() { let json = r#"{ "beacon": {"network": "preview", "epoch": 86, "immutable_file_number": 1728 }, +"entity_type": "{\"CardanoImmutableFilesFull\":{\"network\":\"preview\",\"epoch\":86,\"immutable_file_number\":1728}}", "protocol": {"k": 5, "m": 100, "phi_f": 0.65 }, "next_protocol": {"k": 50, "m": 1000, "phi_f": 0.65 }, "signers": [{"party_id": "123", "verification_key": "7b22766b223a5b3134332c3136312c3235352c34382c37382c35372c3230342c3232302c32352c3232312c3136342c3235322c3234382c31342c35362c3132362c3138362c3133352c3232382c3138382c3134352c3138312c35322c3230302c39372c39392c3231332c34362c302c3139392c3139332c38392c3138372c38382c32392c3133352c3137332c3234342c38362c33362c38332c35342c36372c3136342c362c3133372c39342c37322c362c3130352c3132382c3132382c39332c34382c3137362c31312c342c3234362c3133382c34382c3138302c3133332c39302c3134322c3139322c32342c3139332c3131312c3134322c33312c37362c3131312c3131302c3233342c3135332c39302c3230382c3139322c33312c3132342c39352c3130322c34392c3135382c39392c35322c3232302c3136352c39342c3235312c36382c36392c3132312c31362c3232342c3139345d2c22706f70223a5b3136382c35302c3233332c3139332c31352c3133362c36352c37322c3132332c3134382c3132392c3137362c33382c3139382c3230392c34372c32382c3230342c3137362c3134342c35372c3235312c34322c32382c36362c37362c38392c39372c3135382c36332c35342c3139382c3139342c3137362c3133352c3232312c31342c3138352c3139372c3232352c3230322c39382c3234332c37342c3233332c3232352c3134332c3135312c3134372c3137372c3137302c3131372c36362c3136352c36362c36322c33332c3231362c3233322c37352c36382c3131342c3139352c32322c3130302c36352c34342c3139382c342c3136362c3130322c3233332c3235332c3234302c35392c3137352c36302c3131372c3134322c3131342c3134302c3132322c31372c38372c3131302c3138372c312c31372c31302c3139352c3135342c31332c3234392c38362c35342c3232365d7d"}], diff --git a/mithril-common/src/test_utils/fake_data.rs b/mithril-common/src/test_utils/fake_data.rs index 47d0d09f7a4..53dc2fe44f7 100644 --- a/mithril-common/src/test_utils/fake_data.rs +++ b/mithril-common/src/test_utils/fake_data.rs @@ -1,7 +1,8 @@ //! Fake data builders for testing. use crate::entities::{ - CertificateMetadata, LotteryIndex, ProtocolMessage, ProtocolMessagePartKey, SingleSignatures, + CertificateMetadata, LotteryIndex, ProtocolMessage, ProtocolMessagePartKey, SignedEntityType, + SingleSignatures, }; use crate::{crypto_helper, entities}; @@ -53,6 +54,9 @@ pub fn certificate_pending() -> entities::CertificatePending { // Beacon let beacon = beacon(); + // Signed entity type + let signed_entity_type = SignedEntityType::dummy(); + // Protocol parameters let next_protocol_parameters = protocol_parameters(); let protocol_parameters = protocol_parameters(); @@ -65,6 +69,7 @@ pub fn certificate_pending() -> entities::CertificatePending { // Certificate pending entities::CertificatePending::new( beacon, + signed_entity_type, protocol_parameters, next_protocol_parameters, current_signers, diff --git a/mithril-signer/src/certificate_handler.rs b/mithril-signer/src/certificate_handler.rs index 843e952d549..b6ec11a8f76 100644 --- a/mithril-signer/src/certificate_handler.rs +++ b/mithril-signer/src/certificate_handler.rs @@ -167,7 +167,11 @@ impl CertificateHandler for CertificateHandlerHTTPClient { match response { Ok(response) => match response.status() { StatusCode::OK => match response.json::().await { - Ok(message) => Ok(Some(FromPendingCertificateMessageAdapter::adapt(message))), + Ok(message) => Ok(Some( + FromPendingCertificateMessageAdapter::adapt(message).map_err(|err| { + CertificateHandlerError::JsonParseFailed(err.to_string()) + })?, + )), Err(err) => Err(CertificateHandlerError::JsonParseFailed(err.to_string())), }, StatusCode::PRECONDITION_FAILED => Err(self.handle_api_error(&response)), diff --git a/mithril-signer/src/message_adapters/from_pending_certificate_message.rs b/mithril-signer/src/message_adapters/from_pending_certificate_message.rs index 5725593fe06..65d5cae6d56 100644 --- a/mithril-signer/src/message_adapters/from_pending_certificate_message.rs +++ b/mithril-signer/src/message_adapters/from_pending_certificate_message.rs @@ -1,6 +1,7 @@ use mithril_common::{ entities::{CertificatePending, Signer}, messages::{CertificatePendingMessage, SignerMessage}, + StdResult, }; /// Adapter to turn [CertificatePendingMessage] instances into [CertificatePending]. @@ -8,14 +9,15 @@ pub struct FromPendingCertificateMessageAdapter; impl FromPendingCertificateMessageAdapter { /// Adapter method - pub fn adapt(message: CertificatePendingMessage) -> CertificatePending { - CertificatePending { + pub fn adapt(message: CertificatePendingMessage) -> StdResult { + Ok(CertificatePending { beacon: message.beacon, + signed_entity_type: serde_json::from_str(&message.signed_entity_type)?, protocol_parameters: message.protocol_parameters, next_protocol_parameters: message.next_protocol_parameters, signers: Self::adapt_signers(message.signers), next_signers: Self::adapt_signers(message.next_signers), - } + }) } fn adapt_signers(signer_messages: Vec) -> Vec { @@ -40,7 +42,7 @@ mod tests { fn adapt_ok() { let message = CertificatePendingMessage::dummy(); let epoch = message.beacon.epoch; - let certificate_pending = FromPendingCertificateMessageAdapter::adapt(message); + let certificate_pending = FromPendingCertificateMessageAdapter::adapt(message).unwrap(); assert_eq!(epoch, certificate_pending.beacon.epoch); } @@ -49,7 +51,7 @@ mod tests { fn adapt_signers() { let mut message = CertificatePendingMessage::dummy(); message.signers = vec![SignerMessage::dummy(), SignerMessage::dummy()]; - let certificate_pending = FromPendingCertificateMessageAdapter::adapt(message); + let certificate_pending = FromPendingCertificateMessageAdapter::adapt(message).unwrap(); assert_eq!(2, certificate_pending.signers.len()); assert_eq!(1, certificate_pending.next_signers.len()); diff --git a/mithril-signer/tests/test_extensions/certificate_handler.rs b/mithril-signer/tests/test_extensions/certificate_handler.rs index d0ff6bd61d0..3f688536687 100644 --- a/mithril-signer/tests/test_extensions/certificate_handler.rs +++ b/mithril-signer/tests/test_extensions/certificate_handler.rs @@ -3,6 +3,7 @@ use std::{collections::HashMap, sync::Arc}; use async_trait::async_trait; use mithril_common::{ entities::{Beacon, CertificatePending, Epoch, EpochSettings, Signer, SingleSignatures}, + test_utils::fake_data, BeaconProvider, BeaconProviderImpl, }; use mithril_signer::{CertificateHandler, CertificateHandlerError}; @@ -72,7 +73,7 @@ impl CertificateHandler for FakeAggregator { let beacon = self.get_beacon().await?; let mut certificate_pending = CertificatePending { beacon: beacon.clone(), - ..Default::default() + ..fake_data::certificate_pending() }; let store = self.registered_signers.read().await; diff --git a/openapi.yaml b/openapi.yaml index c09fa8fe080..20544d32f9f 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -4,7 +4,7 @@ info: # `mithril-common/src/lib.rs` file. If you plan to update it # here to reflect changes in the API, please also update the constant in the # Rust file. - version: 0.1.1 + version: 0.1.2 title: Mithril Aggregator Server description: | The REST API provided by a Mithril Aggregator Node in a Mithril network. @@ -52,6 +52,7 @@ paths: Returns the information related to the current pending certificate: * protocol parameters, for current and next epoch (to setup cryptography) * beacon information (where on the chain the pending certificate should be triggered) + * entity type of the message that must be signed * verification keys of the signers, for current and next epoch responses: "200": @@ -321,6 +322,7 @@ components: additionalProperties: false required: - beacon + - entity_type - protocol - next_protocol - signers @@ -328,6 +330,9 @@ components: properties: beacon: $ref: "#/components/schemas/Beacon" + entity_type: + description: Entity type of the message that is signed + type: string protocol: $ref: "#/components/schemas/ProtocolParameters" next_protocol: