From c7cf0ab0ba84cd6bee90a74343901fc8a4da002c Mon Sep 17 00:00:00 2001 From: sydhds Date: Tue, 28 Mar 2023 18:24:50 +0200 Subject: [PATCH 01/13] Initial code for DenunciationFactory & DenunciationPool --- Cargo.lock | 2 + massa-consensus-exports/src/channels.rs | 3 +- massa-consensus-worker/src/controller.rs | 9 + massa-factory-worker/Cargo.toml | 1 + .../src/denunciation_factory.rs | 238 ++++++++++++++++++ massa-factory-worker/src/lib.rs | 1 + massa-factory-worker/src/manager.rs | 9 + massa-factory-worker/src/run.rs | 28 ++- massa-factory-worker/src/tests/scenarios.rs | 87 +++++++ massa-factory-worker/src/tests/tools.rs | 14 +- massa-models/src/denunciation.rs | 100 +++++++- massa-node/src/main.rs | 15 +- massa-pool-exports/src/controller_traits.rs | 3 + massa-pool-exports/src/test_exports/mock.rs | 13 + massa-pool-worker/Cargo.toml | 1 + massa-pool-worker/src/controller_impl.rs | 13 +- massa-pool-worker/src/denunciation_pool.rs | 85 +++++++ massa-pool-worker/src/endorsement_pool.rs | 20 +- massa-pool-worker/src/lib.rs | 1 + massa-pool-worker/src/operation_pool.rs | 1 + massa-pool-worker/src/worker.rs | 12 +- massa-storage/src/denunciation_indexes.rs | 37 +++ massa-storage/src/lib.rs | 89 +++++++ 23 files changed, 771 insertions(+), 11 deletions(-) create mode 100644 massa-factory-worker/src/denunciation_factory.rs create mode 100644 massa-pool-worker/src/denunciation_pool.rs create mode 100644 massa-storage/src/denunciation_indexes.rs diff --git a/Cargo.lock b/Cargo.lock index 1e218ea6228..3864af05c07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2624,6 +2624,7 @@ name = "massa_factory_worker" version = "0.1.0" dependencies = [ "anyhow", + "crossbeam-channel", "massa_consensus_exports", "massa_factory_exports", "massa_hash 0.1.0", @@ -2820,6 +2821,7 @@ dependencies = [ name = "massa_pool_worker" version = "0.1.0" dependencies = [ + "crossbeam-channel", "massa_execution_exports", "massa_hash 0.1.0", "massa_models", diff --git a/massa-consensus-exports/src/channels.rs b/massa-consensus-exports/src/channels.rs index d09c628aa09..51d22d131cb 100644 --- a/massa-consensus-exports/src/channels.rs +++ b/massa-consensus-exports/src/channels.rs @@ -1,6 +1,6 @@ use massa_execution_exports::ExecutionController; use massa_models::block::{Block, FilledBlock}; -use massa_models::block_header::BlockHeader; +use massa_models::block_header::{BlockHeader, SecuredHeader}; use massa_pool_exports::PoolController; use massa_pos_exports::SelectorController; use massa_protocol_exports::ProtocolCommandSender; @@ -26,4 +26,5 @@ pub struct ConsensusChannels { pub block_header_sender: tokio::sync::broadcast::Sender, /// Channel use by Websocket (if they are enable) to broadcast a new block integrated pub filled_block_sender: tokio::sync::broadcast::Sender, + pub denunciation_factory_sender: crossbeam_channel::Sender, } diff --git a/massa-consensus-worker/src/controller.rs b/massa-consensus-worker/src/controller.rs index 42043454290..db92025fe1c 100644 --- a/massa-consensus-worker/src/controller.rs +++ b/massa-consensus-worker/src/controller.rs @@ -281,6 +281,15 @@ impl ConsensusController for ConsensusControllerImpl { .block_header_sender .send(header.clone().content); } + + if let Err(e) = self + .channels + .denunciation_factory_sender + .send(header.clone()) + { + warn!("Cannot send header to denunciation factory: {}", e); + } + if let Err(err) = self .command_sender .try_send(ConsensusCommand::RegisterBlockHeader(block_id, header)) diff --git a/massa-factory-worker/Cargo.toml b/massa-factory-worker/Cargo.toml index 52c950b23c5..6d5934630c7 100644 --- a/massa-factory-worker/Cargo.toml +++ b/massa-factory-worker/Cargo.toml @@ -11,6 +11,7 @@ anyhow = "1.0" parking_lot = { version = "0.12", features = ["deadlock_detection"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +crossbeam-channel = "0.5" tracing = "0.1" # custom modules massa_models = { path = "../massa-models" } diff --git a/massa-factory-worker/src/denunciation_factory.rs b/massa-factory-worker/src/denunciation_factory.rs new file mode 100644 index 00000000000..6b7d8ff4053 --- /dev/null +++ b/massa-factory-worker/src/denunciation_factory.rs @@ -0,0 +1,238 @@ +use std::collections::hash_map::Entry; +use std::collections::{HashMap, HashSet}; +use std::thread; + +use crossbeam_channel::{select, Receiver}; +use tracing::{debug, info, warn}; + +use massa_factory_exports::{FactoryChannels, FactoryConfig}; +use massa_models::block_header::SecuredHeader; +use massa_models::denunciation::Denunciation; +use massa_models::endorsement::SecureShareEndorsement; +use massa_models::slot::Slot; + +// TODO: rework these values +const DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN: usize = 4096; +const DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN: usize = 4096; + +/// Structure gathering all elements needed by the factory thread +#[allow(dead_code)] +pub(crate) struct DenunciationFactoryWorker { + cfg: FactoryConfig, + channels: FactoryChannels, + factory_receiver: Receiver<()>, + consensus_receiver: Receiver, + endorsement_pool_receiver: Receiver, + + // TODO: optim with PreHashSet? + // internal for endorsements (or secure share endorsements) + /// Internal storage for endorsement - + /// store at max 1 endorsement per entry, as soon as we have 2 we produce a Denunciation + endorsements_by_slot_index: HashMap<(Slot, u32), Vec>, + /// Cache to avoid processing several time the same endorsement denunciation + seen_endorsement_denunciation: HashSet<(Slot, u32)>, + // internal for block header (or secured header) + /// Internal storage for endorsement - + /// store at max 1 endorsement per entry, as soon as we have 2 we produce a Denunciation + block_header_by_slot: HashMap>, + /// Cache to avoid processing several time the same endorsement denunciation + seen_block_header_denunciation: HashSet, +} + +impl DenunciationFactoryWorker { + /// Creates the `FactoryThread` structure to gather all data and references + /// needed by the factory worker thread. + pub(crate) fn spawn( + cfg: FactoryConfig, + channels: FactoryChannels, + factory_receiver: Receiver<()>, + consensus_receiver: Receiver, + endorsement_pool_receiver: Receiver, + ) -> thread::JoinHandle<()> { + thread::Builder::new() + .name("denunciation-factory".into()) + .spawn(|| { + let mut factory = Self { + cfg, + channels, + factory_receiver, + consensus_receiver, + endorsement_pool_receiver, + endorsements_by_slot_index: Default::default(), + seen_endorsement_denunciation: Default::default(), + block_header_by_slot: Default::default(), + seen_block_header_denunciation: Default::default(), + }; + factory.run(); + }) + .expect("failed to spawn thread : denunciation-factory") + } + + /// Process new secured header (~ block header) + fn process_new_secured_header(&mut self, secured_header: SecuredHeader) { + let key = secured_header.content.slot; + if self.seen_block_header_denunciation.contains(&key) { + warn!( + "Denunciation factory process a block header that have already been denounced: {}", + secured_header + ); + return; + } + + // TODO: need 2 separate constants here? + if self.seen_block_header_denunciation.len() + > DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN + || self.block_header_by_slot.len() > DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN + { + warn!( + "Denunciation factory cannot process - cache full: {}, {}", + self.seen_block_header_denunciation.len(), + self.block_header_by_slot.len() + ); + return; + } + + let denunciation_: Option = match self.block_header_by_slot.entry(key) { + Entry::Occupied(mut eo) => { + let secured_headers = eo.get_mut(); + // Store at max 2 SecuredHeader's + if secured_headers.len() == 1 { + secured_headers.push(secured_header); + + // TODO / OPTIM?: use [] ? + // safe to unwrap as we just checked the vec len + let header_1 = secured_headers.get(0).unwrap(); + let header_2 = secured_headers.get(1).unwrap(); + let de_ = Denunciation::try_from((header_1, header_2)); + if let Err(e) = de_ { + debug!("Denunciation factory cannot create denunciation from block headers: {}", e); + return; + } + Some(de_.unwrap()) // Already checked for error + } else { + // Already 2 entries - so a Denunciation has already been created + None + } + } + Entry::Vacant(ev) => { + ev.insert(vec![secured_header]); + None + } + }; + + if let Some(denunciation) = denunciation_ { + info!( + "Created a new block header denunciation : {:?}", + denunciation + ); + + let mut de_storage = self.channels.storage.clone_without_refs(); + de_storage.store_denunciation(denunciation); + self.channels.pool.add_denunciations(de_storage); + } + } + + /// Process new secure share endorsement (~ endorsement) + fn process_new_secure_share_endorsement( + &mut self, + secure_share_endorsement: SecureShareEndorsement, + ) { + let key = ( + secure_share_endorsement.content.slot, + secure_share_endorsement.content.index, + ); + if self.seen_endorsement_denunciation.contains(&key) { + warn!( + "Denunciation factory process an endorsement that have already been denounced: {}", + secure_share_endorsement + ); + return; + } + + if self.seen_endorsement_denunciation.len() > DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN + || self.endorsements_by_slot_index.len() + > DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN + { + warn!( + "Denunciation factory cannot process - cache full: {}, {}", + self.seen_endorsement_denunciation.len(), + self.endorsements_by_slot_index.len() + ); + return; + } + + let denunciation_: Option = match self.endorsements_by_slot_index.entry(key) { + Entry::Occupied(mut eo) => { + let secure_share_endorsements = eo.get_mut(); + // Store at max 2 endo + if secure_share_endorsements.len() == 1 { + secure_share_endorsements.push(secure_share_endorsement); + + // TODO / OPTIM?: use [] ? + // safe to unwrap as we just checked the vec len + let header_1 = secure_share_endorsements.get(0).unwrap(); + let header_2 = secure_share_endorsements.get(1).unwrap(); + let de_ = Denunciation::try_from((header_1, header_2)); + if let Err(e) = de_ { + debug!("Denunciation factory cannot create denunciation from block headers: {}", e); + return; + } + Some(de_.unwrap()) // Already checked for error + } else { + // Already 2 entries - so a Denunciation has already been created + None + } + } + Entry::Vacant(ev) => { + ev.insert(vec![secure_share_endorsement]); + None + } + }; + + if let Some(denunciation) = denunciation_ { + info!( + "Created a new endorsement denunciation : {:?}", + denunciation + ); + } + } + + /// main run loop of the denunciation creator thread + fn run(&mut self) { + loop { + select! { + recv(self.consensus_receiver) -> secured_header_ => { + match secured_header_ { + Ok(secured_header) => { + info!("Denunciation factory receives a new block header: {}", secured_header); + self.process_new_secured_header(secured_header); + }, + Err(e) => { + warn!("Denunciation factory cannot receive from consensus receiver: {}", e); + break; + } + } + }, + recv(self.endorsement_pool_receiver) -> secure_share_endorsement_ => { + match secure_share_endorsement_ { + Ok(secure_share_endorsement) => { + info!("Denunciation factory receives a new endorsement: {}", secure_share_endorsement); + self.process_new_secure_share_endorsement(secure_share_endorsement) + } + Err(e) => { + warn!("Denunciation factory cannot receive from endorsement pool receiver: {}", e); + break; + } + } + } + recv(self.factory_receiver) -> msg_ => { + if let Err(e) = msg_ { + warn!("Denunciation factory receive an error from factory receiver: {}", e); + } + // factory_receiver send () and is supposed to be a STOP message + break; + } + } + } + } +} diff --git a/massa-factory-worker/src/lib.rs b/massa-factory-worker/src/lib.rs index 0e0be25a5c0..99305da41cc 100644 --- a/massa-factory-worker/src/lib.rs +++ b/massa-factory-worker/src/lib.rs @@ -3,6 +3,7 @@ #![feature(deadline_api)] mod block_factory; +mod denunciation_factory; mod endorsement_factory; mod manager; mod run; diff --git a/massa-factory-worker/src/manager.rs b/massa-factory-worker/src/manager.rs index 6990b3f6516..e2bffc651cc 100644 --- a/massa-factory-worker/src/manager.rs +++ b/massa-factory-worker/src/manager.rs @@ -16,6 +16,9 @@ pub struct FactoryManagerImpl { /// endorsement worker message sender and join handle pub(crate) endorsement_worker: Option<(mpsc::Sender<()>, JoinHandle<()>)>, + + /// denunciation worker message sender and join handle + pub(crate) denunciation_worker: Option<(crossbeam_channel::Sender<()>, JoinHandle<()>)>, } impl FactoryManager for FactoryManagerImpl { @@ -34,6 +37,12 @@ impl FactoryManager for FactoryManagerImpl { warn!("endorsement factory worker panicked: {:?}", err); } } + if let Some((chan_tx, join_handle)) = self.denunciation_worker.take() { + std::mem::drop(chan_tx); + if let Err(err) = join_handle.join() { + warn!("denunciation factory worker panicked: {:?}", err); + } + } info!("factory stopped"); } } diff --git a/massa-factory-worker/src/run.rs b/massa-factory-worker/src/run.rs index 6e7f4e71e55..36c7f71098c 100644 --- a/massa-factory-worker/src/run.rs +++ b/massa-factory-worker/src/run.rs @@ -3,11 +3,16 @@ use parking_lot::RwLock; use std::sync::{mpsc, Arc}; +use crossbeam_channel::{unbounded, Receiver}; + +use crate::denunciation_factory::DenunciationFactoryWorker; use crate::{ block_factory::BlockFactoryWorker, endorsement_factory::EndorsementFactoryWorker, manager::FactoryManagerImpl, }; use massa_factory_exports::{FactoryChannels, FactoryConfig, FactoryManager}; +use massa_models::block_header::SecuredHeader; +use massa_models::endorsement::SecureShareEndorsement; use massa_wallet::Wallet; /// Start factory @@ -23,6 +28,8 @@ pub fn start_factory( cfg: FactoryConfig, wallet: Arc>, channels: FactoryChannels, + denunciation_factory_consensus_receiver: Receiver, + denunciation_factory_endorsement_pool_receiver: Receiver, ) -> Box { // create block factory channel let (block_worker_tx, block_worker_rx) = mpsc::channel::<()>(); @@ -30,6 +37,9 @@ pub fn start_factory( // create endorsement factory channel let (endorsement_worker_tx, endorsement_worker_rx) = mpsc::channel::<()>(); + // create denunciation factory channel + let (denunciation_worker_tx, denunciation_worker_rx) = unbounded::<()>(); + // start block factory worker let block_worker_handle = BlockFactoryWorker::spawn( cfg.clone(), @@ -39,13 +49,27 @@ pub fn start_factory( ); // start endorsement factory worker - let endorsement_worker_handle = - EndorsementFactoryWorker::spawn(cfg, wallet, channels, endorsement_worker_rx); + let endorsement_worker_handle = EndorsementFactoryWorker::spawn( + cfg.clone(), + wallet, + channels.clone(), + endorsement_worker_rx, + ); + + // start denunciation factory worker + let denunciation_worker_handle = DenunciationFactoryWorker::spawn( + cfg, + channels, + denunciation_worker_rx, + denunciation_factory_consensus_receiver, + denunciation_factory_endorsement_pool_receiver, + ); // create factory manager let manager = FactoryManagerImpl { block_worker: Some((block_worker_tx, block_worker_handle)), endorsement_worker: Some((endorsement_worker_tx, endorsement_worker_handle)), + denunciation_worker: Some((denunciation_worker_tx, denunciation_worker_handle)), }; Box::new(manager) diff --git a/massa-factory-worker/src/tests/scenarios.rs b/massa-factory-worker/src/tests/scenarios.rs index 45267a5150e..9135a0fe6ad 100644 --- a/massa-factory-worker/src/tests/scenarios.rs +++ b/massa-factory-worker/src/tests/scenarios.rs @@ -1,4 +1,11 @@ use super::TestFactory; +use massa_hash::Hash; +use massa_models::block_header::{BlockHeader, BlockHeaderSerializer, SecuredHeader}; +use massa_models::block_id::BlockId; +use massa_models::config::THREAD_COUNT; +use massa_models::denunciation::{Denunciation, DenunciationId}; +use massa_models::endorsement::{Endorsement, EndorsementSerializerLW}; +use massa_models::slot::Slot; use massa_models::{ amount::Amount, operation::{Operation, OperationSerializer, OperationType}, @@ -6,6 +13,7 @@ use massa_models::{ }; use massa_signature::KeyPair; use std::str::FromStr; +use std::time::Duration; /// Creates a basic empty block with the factory. #[test] @@ -63,3 +71,82 @@ fn basic_creation_with_multiple_operations() { } assert_eq!(block.content.operations.len(), 2); } + +/// Send 2 block headers and check if a Denunciation op is in storage +#[test] +#[ignore] +fn test_denunciation_factory_block_header_denunciation() { + let keypair = KeyPair::generate(); + + let slot = Slot::new(2, 1); + let parents: Vec = (0..THREAD_COUNT) + .map(|i| BlockId(Hash::compute_from(&[i]))) + .collect(); + + let parents2: Vec = (0..THREAD_COUNT) + .map(|i| BlockId(Hash::compute_from(&[i + 1]))) + .collect(); + + let header1 = BlockHeader { + slot, + parents: parents.clone(), + operation_merkle_root: Hash::compute_from("mno".as_bytes()), + endorsements: vec![Endorsement::new_verifiable( + Endorsement { + slot: Slot::new(1, 1), + index: 1, + endorsed_block: BlockId(Hash::compute_from("blk1".as_bytes())), + }, + EndorsementSerializerLW::new(), + &keypair, + ) + .unwrap()], + }; + + let secured_header_1: SecuredHeader = + BlockHeader::new_verifiable(header1, BlockHeaderSerializer::new(), &keypair).unwrap(); + + let header2 = BlockHeader { + slot, + parents: parents2, + operation_merkle_root: Hash::compute_from("mno".as_bytes()), + endorsements: vec![Endorsement::new_verifiable( + Endorsement { + slot: Slot::new(1, 1), + index: 1, + endorsed_block: BlockId(Hash::compute_from("blk1".as_bytes())), + }, + EndorsementSerializerLW::new(), + &keypair, + ) + .unwrap()], + }; + + let secured_header_2: SecuredHeader = + BlockHeader::new_verifiable(header2, BlockHeaderSerializer::new(), &keypair).unwrap(); + + // Built it to compare with what the factory will produce + let denunciation = Denunciation::try_from((&secured_header_1, &secured_header_2)).unwrap(); + let denunciation_id = DenunciationId::from(&denunciation); + + let test_factory = TestFactory::new(&keypair); + + test_factory + .denunciation_factory_sender + .send(secured_header_1.clone()) + .unwrap(); + test_factory + .denunciation_factory_sender + .send(secured_header_2.clone()) + .unwrap(); + + // Wait for denunciation factory to create the Denunciation + std::thread::sleep(Duration::from_secs(1)); + + let de_indexes = test_factory.storage.read_denunciations(); + assert_eq!(de_indexes.get(&denunciation_id), Some(&denunciation)); + + drop(de_indexes); // release RwLockReadGuard + // stop everything + drop(test_factory); +} diff --git a/massa-factory-worker/src/tests/tools.rs b/massa-factory-worker/src/tests/tools.rs index afb1336d9de..87fab3ed49b 100644 --- a/massa-factory-worker/src/tests/tools.rs +++ b/massa-factory-worker/src/tests/tools.rs @@ -1,3 +1,4 @@ +use crossbeam_channel::Sender; use massa_consensus_exports::test_exports::{ ConsensusEventReceiver, MockConsensusController, MockConsensusControllerMessage, }; @@ -11,6 +12,7 @@ use std::{ use massa_factory_exports::{ test_exports::create_empty_block, FactoryChannels, FactoryConfig, FactoryManager, }; +use massa_models::block_header::SecuredHeader; use massa_models::{ address::Address, block_id::BlockId, config::ENDORSEMENT_COUNT, endorsement::SecureShareEndorsement, operation::SecureShareOperation, prehash::PreHashMap, @@ -42,8 +44,10 @@ pub struct TestFactory { factory_config: FactoryConfig, factory_manager: Box, genesis_blocks: Vec<(BlockId, u64)>, - storage: Storage, + pub(crate) storage: Storage, keypair: KeyPair, + pub(crate) denunciation_factory_sender: Sender, + pub(crate) denunciation_factory_tx: Sender, } impl TestFactory { @@ -58,6 +62,10 @@ impl TestFactory { let (consensus_controller, consensus_event_receiver) = MockConsensusController::new_with_receiver(); let (pool_controller, pool_receiver) = MockPoolController::new_with_receiver(); + let (denunciation_factory_tx, denunciation_factory_rx) = + crossbeam_channel::unbounded::(); + let (denunciation_factory_sender, denunciation_factory_receiver) = + crossbeam_channel::bounded(massa_models::config::CHANNEL_SIZE); let mut storage = Storage::create_root(); let mut factory_config = FactoryConfig::default(); let (_protocol_controller, protocol_command_sender) = MockProtocolController::new(); @@ -88,6 +96,8 @@ impl TestFactory { protocol: protocol_command_sender, storage: storage.clone_without_refs(), }, + denunciation_factory_receiver, + denunciation_factory_rx, ); TestFactory { @@ -99,6 +109,8 @@ impl TestFactory { genesis_blocks, storage, keypair: default_keypair.clone(), + denunciation_factory_sender, + denunciation_factory_tx, } } diff --git a/massa-models/src/denunciation.rs b/massa-models/src/denunciation.rs index a7af7332904..bee336ef663 100644 --- a/massa-models/src/denunciation.rs +++ b/massa-models/src/denunciation.rs @@ -19,17 +19,21 @@ use crate::endorsement::{ }; use crate::slot::{Slot, SlotDeserializer, SlotSerializer}; +use crate::prehash::PreHashed; +use crate::secure_share::Id; use massa_hash::{Hash, HashDeserializer, HashSerializer}; use massa_serialization::{ Deserializer, SerializeError, Serializer, U32VarIntDeserializer, U32VarIntSerializer, + U64VarIntSerializer, }; use massa_signature::{ MassaSignatureError, PublicKey, PublicKeyDeserializer, Signature, SignatureDeserializer, }; +/// A Variant of Denunciation enum for endorsement #[allow(dead_code)] #[derive(Debug, PartialEq)] -struct EndorsementDenunciation { +pub struct EndorsementDenunciation { public_key: PublicKey, slot: Slot, index: u32, @@ -69,9 +73,10 @@ impl EndorsementDenunciation { } } +/// A Variant of Denunciation enum for block header #[allow(dead_code)] #[derive(Debug, PartialEq)] -struct BlockHeaderDenunciation { +pub struct BlockHeaderDenunciation { public_key: PublicKey, slot: Slot, hash_1: Hash, @@ -117,8 +122,10 @@ impl BlockHeaderDenunciation { } } +/// A denunciation enum #[derive(Debug, PartialEq)] -enum Denunciation { +#[allow(missing_docs)] +pub enum Denunciation { Endorsement(EndorsementDenunciation), BlockHeader(BlockHeaderDenunciation), } @@ -714,6 +721,93 @@ impl Deserializer for DenunciationDeserializer { // End Ser / Der +// Denunciation Id + +/// Endorsement ID size in bytes +pub const DENUNCIATION_ID_SIZE_BYTES: usize = massa_hash::HASH_SIZE_BYTES; + +/// endorsement id +#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct DenunciationId(Hash); + +const DENUNCIATION_ID_PREFIX: char = 'D'; +const DENUNCIATION_ID_VERSION: u64 = 0; + +impl PreHashed for DenunciationId {} + +impl Id for DenunciationId { + fn new(hash: Hash) -> Self { + Self(hash) + } + + fn get_hash(&self) -> &Hash { + &self.0 + } +} + +impl std::fmt::Display for DenunciationId { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let u64_serializer = U64VarIntSerializer::new(); + // might want to allocate the vector with capacity in order to avoid re-allocation + let mut bytes: Vec = Vec::new(); + u64_serializer + .serialize(&DENUNCIATION_ID_VERSION, &mut bytes) + .map_err(|_| std::fmt::Error)?; + bytes.extend(self.0.to_bytes()); + write!( + f, + "{}{}", + DENUNCIATION_ID_PREFIX, + bs58::encode(bytes).with_check().into_string() + ) + } +} + +impl std::fmt::Debug for DenunciationId { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self) + } +} + +impl DenunciationId { + /// denunciation id to bytes + pub fn to_bytes(&self) -> &[u8; DENUNCIATION_ID_SIZE_BYTES] { + self.0.to_bytes() + } + + /// endorsement id into bytes + pub fn into_bytes(self) -> [u8; DENUNCIATION_ID_SIZE_BYTES] { + self.0.into_bytes() + } + + /// endorsement id from bytes + pub fn from_bytes(data: &[u8; DENUNCIATION_ID_SIZE_BYTES]) -> DenunciationId { + DenunciationId(Hash::from_bytes(data)) + } +} + +impl From<&Denunciation> for DenunciationId { + fn from(value: &Denunciation) -> Self { + match value { + Denunciation::Endorsement(endo_de) => { + let mut to_hash = Vec::new(); + to_hash.extend(endo_de.public_key.to_bytes()); + to_hash.extend(endo_de.slot.to_bytes_key()); + to_hash.extend(endo_de.index.to_le_bytes()); + DenunciationId(Hash::compute_from(&to_hash)) + } + Denunciation::BlockHeader(blkh_de) => { + let mut to_hash = Vec::new(); + to_hash.extend(blkh_de.public_key.to_bytes()); + to_hash.extend(blkh_de.slot.to_bytes_key()); + DenunciationId(Hash::compute_from(&to_hash)) + } + } + } +} + +// End Denunciation Id + #[cfg(test)] mod tests { use super::*; diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 918c402fadd..c42624773a9 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -47,6 +47,7 @@ use massa_models::config::constants::{ T0, THREAD_COUNT, VERSION, }; use massa_models::config::CONSENSUS_BOOTSTRAP_PART_SIZE; +use massa_models::endorsement::SecureShareEndorsement; use massa_network_exports::{Establisher, NetworkConfig, NetworkManager}; use massa_network_worker::start_network_controller; use massa_pool_exports::{PoolChannels, PoolConfig, PoolManager}; @@ -374,12 +375,15 @@ async fn launch( let pool_channels = PoolChannels { operation_sender: broadcast::channel(pool_config.broadcast_operations_capacity).0, }; + let (denunciation_factory_tx, denunciation_factory_rx) = + crossbeam_channel::unbounded::(); let (pool_manager, pool_controller) = start_pool_controller( pool_config, &shared_storage, execution_controller.clone(), pool_channels.clone(), + denunciation_factory_tx, ); let (protocol_command_sender, protocol_command_receiver) = @@ -415,6 +419,8 @@ async fn launch( let (consensus_event_sender, consensus_event_receiver) = crossbeam_channel::bounded(CHANNEL_SIZE); + let (denunciation_factory_sender, denunciation_factory_receiver) = + crossbeam_channel::bounded(CHANNEL_SIZE); let consensus_channels = ConsensusChannels { execution_controller: execution_controller.clone(), selector_controller: selector_controller.clone(), @@ -426,6 +432,7 @@ async fn launch( block_sender: broadcast::channel(consensus_config.broadcast_blocks_capacity).0, filled_block_sender: broadcast::channel(consensus_config.broadcast_filled_blocks_capacity) .0, + denunciation_factory_sender, }; let (consensus_controller, consensus_manager) = start_consensus_worker( @@ -505,7 +512,13 @@ async fn launch( protocol: ProtocolCommandSender(protocol_command_sender.clone()), storage: shared_storage.clone(), }; - let factory_manager = start_factory(factory_config, node_wallet.clone(), factory_channels); + let factory_manager = start_factory( + factory_config, + node_wallet.clone(), + factory_channels, + denunciation_factory_receiver, + denunciation_factory_rx, + ); // launch bootstrap server let bootstrap_manager = start_bootstrap_server( diff --git a/massa-pool-exports/src/controller_traits.rs b/massa-pool-exports/src/controller_traits.rs index b07711f67f9..85c03963464 100644 --- a/massa-pool-exports/src/controller_traits.rs +++ b/massa-pool-exports/src/controller_traits.rs @@ -38,6 +38,9 @@ pub trait PoolController: Send + Sync { /// Check if the pool contains a list of operations. Returns one boolean per item. fn contains_operations(&self, operations: &[OperationId]) -> Vec; + /// Add denunciations to pool. Simply print a warning on failure. + fn add_denunciations(&mut self, denunciations: Storage); + /// Returns a boxed clone of self. /// Useful to allow cloning `Box`. fn clone_box(&self) -> Box; diff --git a/massa-pool-exports/src/test_exports/mock.rs b/massa-pool-exports/src/test_exports/mock.rs index c45d2d89a98..c58d9716423 100644 --- a/massa-pool-exports/src/test_exports/mock.rs +++ b/massa-pool-exports/src/test_exports/mock.rs @@ -31,6 +31,11 @@ pub enum MockPoolControllerMessage { /// Storage that contains all operations operations: Storage, }, + /// Add denunciations to the pool + AddDenunciations { + /// Storage that contains all denunciations + denunciations: Storage, + }, /// Get block endorsements GetBlockEndorsements { /// Block id of the block endorsed @@ -229,4 +234,12 @@ impl PoolController for MockPoolController { fn clone_box(&self) -> Box { Box::new(self.clone()) } + + fn add_denunciations(&mut self, denunciations: Storage) { + self.0 + .lock() + .unwrap() + .send(MockPoolControllerMessage::AddDenunciations { denunciations }) + .unwrap(); + } } diff --git a/massa-pool-worker/Cargo.toml b/massa-pool-worker/Cargo.toml index be4a15529a4..5aae0435bd3 100644 --- a/massa-pool-worker/Cargo.toml +++ b/massa-pool-worker/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] num = "0.4" +crossbeam-channel = "0.5" tracing = "0.1" # custom modules parking_lot = { version = "0.12", features = ["deadlock_detection"] } diff --git a/massa-pool-worker/src/controller_impl.rs b/massa-pool-worker/src/controller_impl.rs index e09ce8862d0..32151d324da 100644 --- a/massa-pool-worker/src/controller_impl.rs +++ b/massa-pool-worker/src/controller_impl.rs @@ -12,7 +12,10 @@ use std::sync::mpsc::TrySendError; use std::sync::{mpsc::SyncSender, Arc}; use tracing::{info, warn}; -use crate::{endorsement_pool::EndorsementPool, operation_pool::OperationPool}; +use crate::{ + denunciation_pool::DenunciationPool, endorsement_pool::EndorsementPool, + operation_pool::OperationPool, +}; /// A generic command to send commands to a pool pub enum Command { @@ -33,6 +36,8 @@ pub struct PoolControllerImpl { pub(crate) operation_pool: Arc>, /// Shared reference to the endorsement pool pub(crate) endorsement_pool: Arc>, + /// Shared reference to the denunciation pool + pub(crate) denunciation_pool: Arc>, /// Operation write worker command sender pub(crate) operations_input_sender: SyncSender, /// Endorsement write worker command sender @@ -150,6 +155,12 @@ impl PoolController for PoolControllerImpl { let lck = self.operation_pool.read(); operations.iter().map(|id| lck.contains(id)).collect() } + + /// Add denunciation to pool + fn add_denunciations(&mut self, denunciations: Storage) { + let mut lck = self.denunciation_pool.write(); + lck.add_denunciation(denunciations); + } } /// Implementation of the pool manager. diff --git a/massa-pool-worker/src/denunciation_pool.rs b/massa-pool-worker/src/denunciation_pool.rs new file mode 100644 index 00000000000..0d2c23984bf --- /dev/null +++ b/massa-pool-worker/src/denunciation_pool.rs @@ -0,0 +1,85 @@ +use massa_models::prehash::{CapacityAllocator, PreHashSet}; + +use massa_pool_exports::PoolConfig; +use massa_storage::Storage; + +pub struct DenunciationPool { + /// configuration + config: PoolConfig, + /// storage + storage: Storage, +} + +impl DenunciationPool { + pub fn init(config: PoolConfig, storage: &Storage) -> Self { + Self { + config, + storage: storage.clone_without_refs(), + } + } + + // Not used yet + /* + /// Get the number of stored elements + pub fn len(&self) -> usize { + self.storage.get_denunciation_refs().len() + } + + /// Checks whether an element is stored in the pool + pub fn contains(&self, id: &DenunciationId) -> bool { + self.storage.get_denunciation_refs().contains(id) + } + */ + + /// Add a list of denunciation to the pool + pub(crate) fn add_denunciation(&mut self, mut denunciation_storage: Storage) { + let denunciation_ids = denunciation_storage + .get_denunciation_refs() + .iter() + .copied() + .collect::>(); + + let mut added = PreHashSet::with_capacity(denunciation_ids.len()); + let mut removed = PreHashSet::with_capacity(denunciation_ids.len()); + + // populate added + { + let de_indexes = denunciation_storage.read_denunciations(); + for de_id in denunciation_ids { + let _de = de_indexes.get(&de_id).expect( + "Attempting to add denunciation to pool but it is absent from given storage", + ); + + // TODO: do not add denunciation if expired + + // TODO: check that we do not add "duplicate" + added.insert(de_id); + } + } + + // populate removed + // TODO: remove from self storage + + // take ownership on added denunciations + self.storage.extend(denunciation_storage.split_off( + &Default::default(), + &Default::default(), + &Default::default(), + &added, + )); + + // drop removed endorsements from storage + self.storage.drop_denunciation_refs(&removed); + } + + // In next PR + /* + pub fn get_block_denunciations( + &self, + slot: &Slot, + target_block: &BlockId, + ) -> Vec { + todo!() + } + */ +} diff --git a/massa-pool-worker/src/endorsement_pool.rs b/massa-pool-worker/src/endorsement_pool.rs index 3aa6f40c400..18aec2b248e 100644 --- a/massa-pool-worker/src/endorsement_pool.rs +++ b/massa-pool-worker/src/endorsement_pool.rs @@ -1,5 +1,7 @@ //! Copyright (c) 2022 MASSA LABS +use crossbeam_channel::Sender; +use massa_models::endorsement::SecureShareEndorsement; use massa_models::{ block_id::BlockId, endorsement::EndorsementId, @@ -9,6 +11,7 @@ use massa_models::{ use massa_pool_exports::PoolConfig; use massa_storage::Storage; use std::collections::{BTreeMap, HashMap}; +use tracing::warn; pub struct EndorsementPool { /// configuration @@ -26,16 +29,24 @@ pub struct EndorsementPool { /// last consensus final periods, per thread last_cs_final_periods: Vec, + + /// Queue to Denunciation factory + denunciation_factory_tx: Sender, } impl EndorsementPool { - pub fn init(config: PoolConfig, storage: &Storage) -> Self { + pub fn init( + config: PoolConfig, + storage: &Storage, + denunciation_factory_tx: Sender, + ) -> Self { EndorsementPool { last_cs_final_periods: vec![0u64; config.thread_count as usize], endorsements_indexed: Default::default(), endorsements_sorted: vec![Default::default(); config.thread_count as usize], config, storage: storage.clone_without_refs(), + denunciation_factory_tx, } } @@ -116,6 +127,12 @@ impl EndorsementPool { } added.insert(endo.id); } + + // And send endorsements to Denunciation Factory + // let de_interest = DenunciationInterest::WrappedEndorsement(endo.clone()); + if let Err(e) = self.denunciation_factory_tx.send(endo.clone()) { + warn!("Cannot send endorsement to Denunciation factory: {}", e); + } } } @@ -139,6 +156,7 @@ impl EndorsementPool { &Default::default(), &Default::default(), &added, + &Default::default(), )); // drop removed endorsements from storage diff --git a/massa-pool-worker/src/lib.rs b/massa-pool-worker/src/lib.rs index f5d6d2ea93e..678874bb469 100644 --- a/massa-pool-worker/src/lib.rs +++ b/massa-pool-worker/src/lib.rs @@ -9,6 +9,7 @@ #![feature(let_chains)] mod controller_impl; +mod denunciation_pool; mod endorsement_pool; mod operation_pool; mod types; diff --git a/massa-pool-worker/src/operation_pool.rs b/massa-pool-worker/src/operation_pool.rs index 6f20d0c9f10..ad3499beac0 100644 --- a/massa-pool-worker/src/operation_pool.rs +++ b/massa-pool-worker/src/operation_pool.rs @@ -179,6 +179,7 @@ impl OperationPool { &Default::default(), &added, &Default::default(), + &Default::default(), )); // Clean the removed operations from storage. diff --git a/massa-pool-worker/src/worker.rs b/massa-pool-worker/src/worker.rs index 918f0ed4468..46f3d44423a 100644 --- a/massa-pool-worker/src/worker.rs +++ b/massa-pool-worker/src/worker.rs @@ -3,9 +3,12 @@ //! Write worker for the pools, allowing asynchronous writes. use crate::controller_impl::{Command, PoolManagerImpl}; +use crate::denunciation_pool::DenunciationPool; use crate::operation_pool::OperationPool; use crate::{controller_impl::PoolControllerImpl, endorsement_pool::EndorsementPool}; +use crossbeam_channel::Sender; use massa_execution_exports::ExecutionController; +use massa_models::endorsement::SecureShareEndorsement; use massa_pool_exports::PoolConfig; use massa_pool_exports::{PoolChannels, PoolController, PoolManager}; use massa_storage::Storage; @@ -112,6 +115,7 @@ pub fn start_pool_controller( storage: &Storage, execution_controller: Box, channels: PoolChannels, + denunciation_factory_tx: Sender, ) -> (Box, Box) { let (operations_input_sender, operations_input_receiver) = sync_channel(config.channels_size); let (endorsements_input_sender, endorsements_input_receiver) = @@ -122,11 +126,17 @@ pub fn start_pool_controller( execution_controller, channels, ))); - let endorsement_pool = Arc::new(RwLock::new(EndorsementPool::init(config, storage))); + let endorsement_pool = Arc::new(RwLock::new(EndorsementPool::init( + config, + storage, + denunciation_factory_tx, + ))); + let denunciation_pool = Arc::new(RwLock::new(DenunciationPool::init(config, storage))); let controller = PoolControllerImpl { _config: config, operation_pool: operation_pool.clone(), endorsement_pool: endorsement_pool.clone(), + denunciation_pool: denunciation_pool, operations_input_sender: operations_input_sender.clone(), endorsements_input_sender: endorsements_input_sender.clone(), }; diff --git a/massa-storage/src/denunciation_indexes.rs b/massa-storage/src/denunciation_indexes.rs new file mode 100644 index 00000000000..c67cad18a62 --- /dev/null +++ b/massa-storage/src/denunciation_indexes.rs @@ -0,0 +1,37 @@ +use massa_models::denunciation::Denunciation; +use massa_models::{denunciation::DenunciationId, prehash::PreHashMap}; + +/// Container for all endorsements and different indexes. +/// Note: The structure can evolve and store more indexes. +#[derive(Default)] +pub struct DenunciationIndexes { + /// Denunciations structure container + denunciations: PreHashMap, +} + +impl DenunciationIndexes { + /// Insert a denunciation + /// Arguments: + /// - denunciation: the denunciation to insert + pub(crate) fn insert(&mut self, denunciation: Denunciation) { + let denunciation_id = DenunciationId::from(&denunciation); + self.denunciations.try_insert(denunciation_id, denunciation); + } + + /// Remove a endorsement, remove from the indexes and made some clean-up in indexes if necessary. + /// Arguments: + /// * `endorsement_id`: the endorsement id to remove + pub(crate) fn remove(&mut self, denunciation_id: &DenunciationId) -> Option { + self.denunciations.remove(denunciation_id) + } + + /// Gets a reference to a stored denunciation, if any. + pub fn get(&self, id: &DenunciationId) -> Option<&Denunciation> { + self.denunciations.get(id) + } + + /// Checks whether an denunciation exists in global storage. + pub fn contains(&self, id: &DenunciationId) -> bool { + self.denunciations.contains_key(id) + } +} diff --git a/massa-storage/src/lib.rs b/massa-storage/src/lib.rs index ddae0329d80..55fc605558b 100644 --- a/massa-storage/src/lib.rs +++ b/massa-storage/src/lib.rs @@ -11,6 +11,7 @@ #![feature(map_try_insert)] mod block_indexes; +mod denunciation_indexes; mod endorsement_indexes; mod operation_indexes; @@ -18,12 +19,15 @@ mod operation_indexes; mod tests; use block_indexes::BlockIndexes; +use denunciation_indexes::DenunciationIndexes; use endorsement_indexes::EndorsementIndexes; +use massa_models::denunciation::Denunciation; use massa_models::prehash::{CapacityAllocator, PreHashMap, PreHashSet, PreHashed}; use massa_models::secure_share::Id; use massa_models::{ block::SecureShareBlock, block_id::BlockId, + denunciation::DenunciationId, endorsement::{EndorsementId, SecureShareEndorsement}, operation::{OperationId, SecureShareOperation}, }; @@ -41,6 +45,8 @@ pub struct Storage { operations: Arc>, /// global operation storage endorsements: Arc>, + /// global denunciation storage + denunciations: Arc>, /// global block reference counter block_owners: Arc>>, @@ -48,6 +54,8 @@ pub struct Storage { operation_owners: Arc>>, /// global endorsement reference counter endorsement_owners: Arc>>, + /// global denunciation reference counter + denunciation_owners: Arc>>, /// locally used block references local_used_blocks: PreHashSet, @@ -55,6 +63,8 @@ pub struct Storage { local_used_ops: PreHashSet, /// locally used endorsement references local_used_endorsements: PreHashSet, + /// locally used denunciation references + local_used_denunciations: PreHashSet, } impl Debug for Storage { @@ -103,12 +113,15 @@ impl Storage { blocks: Default::default(), operations: Default::default(), endorsements: Default::default(), + denunciations: Default::default(), block_owners: Default::default(), operation_owners: Default::default(), endorsement_owners: Default::default(), + denunciation_owners: Default::default(), local_used_blocks: Default::default(), local_used_ops: Default::default(), local_used_endorsements: Default::default(), + local_used_denunciations: Default::default(), } } @@ -118,14 +131,18 @@ impl Storage { blocks: self.blocks.clone(), operations: self.operations.clone(), endorsements: self.endorsements.clone(), + denunciations: self.denunciations.clone(), + operation_owners: self.operation_owners.clone(), block_owners: self.block_owners.clone(), endorsement_owners: self.endorsement_owners.clone(), + denunciation_owners: self.denunciation_owners.clone(), // do not clone local ref lists local_used_ops: Default::default(), local_used_blocks: Default::default(), local_used_endorsements: Default::default(), + local_used_denunciations: Default::default(), } } @@ -162,6 +179,7 @@ impl Storage { blocks: &PreHashSet, operations: &PreHashSet, endorsements: &PreHashSet, + denunciations: &PreHashSet, ) -> Storage { // Make a clone of self, which has no ref ownership. let mut res = self.clone_without_refs(); @@ -196,6 +214,15 @@ impl Storage { }) .collect(); + res.local_used_denunciations = denunciations + .iter() + .map(|id| { + self.local_used_denunciations + .take(id) + .expect("split endorsement ref not owned by source") + }) + .collect(); + res } @@ -391,6 +418,11 @@ impl Storage { self.blocks.read() } + /// Gets a read reference to the denunciation index + pub fn read_denunciations(&self) -> RwLockReadGuard { + self.denunciations.read() + } + /// Claim endorsement references. /// Returns the set of operation refs that were found and claimed. pub fn claim_endorsement_refs( @@ -473,6 +505,63 @@ impl Storage { } Storage::internal_claim_refs(&ids, &mut owners, &mut self.local_used_endorsements); } + + /// Store denunciation + pub fn store_denunciation(&mut self, denunciation: Denunciation) { + let mut owners = self.denunciation_owners.write(); + let mut de_indexes = self.denunciations.write(); + let de_id = DenunciationId::from(&denunciation); + de_indexes.insert(denunciation); + let mut ids = PreHashSet::with_capacity(1); + ids.insert(de_id); + Storage::internal_claim_refs(&ids, &mut owners, &mut self.local_used_denunciations); + } + + /// get the denunciation reference ownership + pub fn get_denunciation_refs(&self) -> &PreHashSet { + &self.local_used_denunciations + } + + /// Drop local denunciation references. + /// Ignores already-absent refs. + pub fn drop_denunciation_refs(&mut self, ids: &PreHashSet) { + if ids.is_empty() { + return; + } + let mut owners = self.denunciation_owners.write(); + let mut orphaned_ids = Vec::new(); + for id in ids { + if !self.local_used_denunciations.remove(id) { + // the object was already not referenced locally + continue; + } + match owners.entry(*id) { + hash_map::Entry::Occupied(mut occ) => { + let res_count = { + let cnt = occ.get_mut(); + *cnt = cnt + .checked_sub(1) + .expect("less than 1 owner on storage object reference drop"); + *cnt + }; + if res_count == 0 { + orphaned_ids.push(*id); + occ.remove(); + } + } + hash_map::Entry::Vacant(_vac) => { + panic!("missing object in storage on storage object reference drop"); + } + } + } + // if there are orphaned objects, remove them from storage + if !orphaned_ids.is_empty() { + let mut des = self.denunciations.write(); + for id in orphaned_ids { + des.remove(&id); + } + } + } } impl Drop for Storage { From ac0f1c61035aecef4b49ecb4c6b7c4e8d2fbae2c Mon Sep 17 00:00:00 2001 From: sydhds Date: Wed, 29 Mar 2023 19:24:45 +0200 Subject: [PATCH 02/13] Add cleanup in DenunciationPool && DenunciationFactory --- Cargo.lock | 1 + massa-factory-exports/src/config.rs | 6 ++ .../src/test_exports/config.rs | 2 + .../src/denunciation_factory.rs | 78 +++++++++++------- massa-factory-worker/src/tests/scenarios.rs | 15 ++-- massa-factory-worker/src/tests/tools.rs | 17 +++- massa-models/src/config/constants.rs | 7 ++ massa-models/src/denunciation.rs | 34 ++++++++ massa-node/src/main.rs | 8 +- massa-pool-exports/Cargo.toml | 4 +- massa-pool-exports/src/config.rs | 9 +++ massa-pool-exports/src/controller_traits.rs | 3 + massa-pool-exports/src/test_exports/config.rs | 9 ++- massa-pool-exports/src/test_exports/mock.rs | 37 ++++++--- massa-pool-worker/Cargo.toml | 1 + massa-pool-worker/src/controller_impl.rs | 46 ++++++++++- massa-pool-worker/src/denunciation_pool.rs | 79 ++++++++++++++++--- massa-pool-worker/src/worker.rs | 54 ++++++++++++- massa-storage/src/denunciation_indexes.rs | 1 + 19 files changed, 345 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3864af05c07..6be01072e85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2828,6 +2828,7 @@ dependencies = [ "massa_pool_exports", "massa_signature", "massa_storage", + "massa_time", "num", "parking_lot", "tokio", diff --git a/massa-factory-exports/src/config.rs b/massa-factory-exports/src/config.rs index d1a0ecb769b..c3aff957212 100644 --- a/massa-factory-exports/src/config.rs +++ b/massa-factory-exports/src/config.rs @@ -27,4 +27,10 @@ pub struct FactoryConfig { /// maximum number of operation ids in block pub max_operations_per_block: u32, + + /// cycle duration in periods + pub periods_per_cycle: u64, + + /// denunciation expiration as cycle delta + pub denunciation_expire_cycle_delta: u64, } diff --git a/massa-factory-exports/src/test_exports/config.rs b/massa-factory-exports/src/test_exports/config.rs index a1d9ff34549..1ad558f10e8 100644 --- a/massa-factory-exports/src/test_exports/config.rs +++ b/massa-factory-exports/src/test_exports/config.rs @@ -14,6 +14,8 @@ impl Default for FactoryConfig { max_block_size: MAX_BLOCK_SIZE as u64, max_block_gas: MAX_GAS_PER_BLOCK, max_operations_per_block: MAX_OPERATIONS_PER_BLOCK, + periods_per_cycle: PERIODS_PER_CYCLE, + denunciation_expire_cycle_delta: DENUNCIATION_EXPIRE_CYCLE_DELTA, } } } diff --git a/massa-factory-worker/src/denunciation_factory.rs b/massa-factory-worker/src/denunciation_factory.rs index 6b7d8ff4053..573ad36d472 100644 --- a/massa-factory-worker/src/denunciation_factory.rs +++ b/massa-factory-worker/src/denunciation_factory.rs @@ -1,5 +1,5 @@ use std::collections::hash_map::Entry; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::thread; use crossbeam_channel::{select, Receiver}; @@ -10,6 +10,8 @@ use massa_models::block_header::SecuredHeader; use massa_models::denunciation::Denunciation; use massa_models::endorsement::SecureShareEndorsement; use massa_models::slot::Slot; +use massa_models::timeslots::get_closest_slot_to_timestamp; +use massa_time::MassaTime; // TODO: rework these values const DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN: usize = 4096; @@ -29,14 +31,12 @@ pub(crate) struct DenunciationFactoryWorker { /// Internal storage for endorsement - /// store at max 1 endorsement per entry, as soon as we have 2 we produce a Denunciation endorsements_by_slot_index: HashMap<(Slot, u32), Vec>, - /// Cache to avoid processing several time the same endorsement denunciation - seen_endorsement_denunciation: HashSet<(Slot, u32)>, + // internal for block header (or secured header) /// Internal storage for endorsement - /// store at max 1 endorsement per entry, as soon as we have 2 we produce a Denunciation + // FIXME: Store per 'Slot' then per 'PubKey' block_header_by_slot: HashMap>, - /// Cache to avoid processing several time the same endorsement denunciation - seen_block_header_denunciation: HashSet, } impl DenunciationFactoryWorker { @@ -59,9 +59,7 @@ impl DenunciationFactoryWorker { consensus_receiver, endorsement_pool_receiver, endorsements_by_slot_index: Default::default(), - seen_endorsement_denunciation: Default::default(), block_header_by_slot: Default::default(), - seen_block_header_denunciation: Default::default(), }; factory.run(); }) @@ -71,22 +69,10 @@ impl DenunciationFactoryWorker { /// Process new secured header (~ block header) fn process_new_secured_header(&mut self, secured_header: SecuredHeader) { let key = secured_header.content.slot; - if self.seen_block_header_denunciation.contains(&key) { - warn!( - "Denunciation factory process a block header that have already been denounced: {}", - secured_header - ); - return; - } - // TODO: need 2 separate constants here? - if self.seen_block_header_denunciation.len() - > DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN - || self.block_header_by_slot.len() > DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN - { + if self.block_header_by_slot.len() > DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN { warn!( - "Denunciation factory cannot process - cache full: {}, {}", - self.seen_block_header_denunciation.len(), + "Denunciation factory cannot process - cache full: {}", self.block_header_by_slot.len() ); return; @@ -130,6 +116,8 @@ impl DenunciationFactoryWorker { de_storage.store_denunciation(denunciation); self.channels.pool.add_denunciations(de_storage); } + + self.cleanup_cache(); } /// Process new secure share endorsement (~ endorsement) @@ -141,7 +129,7 @@ impl DenunciationFactoryWorker { secure_share_endorsement.content.slot, secure_share_endorsement.content.index, ); - if self.seen_endorsement_denunciation.contains(&key) { + if self.endorsements_by_slot_index.contains_key(&key) { warn!( "Denunciation factory process an endorsement that have already been denounced: {}", secure_share_endorsement @@ -149,13 +137,9 @@ impl DenunciationFactoryWorker { return; } - if self.seen_endorsement_denunciation.len() > DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN - || self.endorsements_by_slot_index.len() - > DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN - { + if self.endorsements_by_slot_index.len() > DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN { warn!( - "Denunciation factory cannot process - cache full: {}, {}", - self.seen_endorsement_denunciation.len(), + "Denunciation factory cannot process - cache full: {}", self.endorsements_by_slot_index.len() ); return; @@ -194,7 +178,45 @@ impl DenunciationFactoryWorker { "Created a new endorsement denunciation : {:?}", denunciation ); + + let mut de_storage = self.channels.storage.clone_without_refs(); + de_storage.store_denunciation(denunciation); + self.channels.pool.add_denunciations(de_storage); } + + self.cleanup_cache(); + } + + fn cleanup_cache(&mut self) { + let now = MassaTime::now().expect("could not get current time"); + + // get closest slot according to the current absolute time + let slot_now = get_closest_slot_to_timestamp( + self.cfg.thread_count, + self.cfg.t0, + self.cfg.genesis_timestamp, + now, + ); + + self.endorsements_by_slot_index.retain(|(slot, _index), _| { + Denunciation::is_expired( + slot, + &slot_now, + self.channels.pool.get_final_cs_periods(), + self.cfg.periods_per_cycle, + self.cfg.denunciation_expire_cycle_delta, + ) + }); + + self.block_header_by_slot.retain(|slot, _| { + Denunciation::is_expired( + slot, + &slot_now, + self.channels.pool.get_final_cs_periods(), + self.cfg.periods_per_cycle, + self.cfg.denunciation_expire_cycle_delta, + ) + }); } /// main run loop of the denunciation creator thread diff --git a/massa-factory-worker/src/tests/scenarios.rs b/massa-factory-worker/src/tests/scenarios.rs index 9135a0fe6ad..c5f0dd721ff 100644 --- a/massa-factory-worker/src/tests/scenarios.rs +++ b/massa-factory-worker/src/tests/scenarios.rs @@ -2,16 +2,18 @@ use super::TestFactory; use massa_hash::Hash; use massa_models::block_header::{BlockHeader, BlockHeaderSerializer, SecuredHeader}; use massa_models::block_id::BlockId; -use massa_models::config::THREAD_COUNT; +use massa_models::config::{T0, THREAD_COUNT}; use massa_models::denunciation::{Denunciation, DenunciationId}; use massa_models::endorsement::{Endorsement, EndorsementSerializerLW}; use massa_models::slot::Slot; +use massa_models::timeslots::get_closest_slot_to_timestamp; use massa_models::{ amount::Amount, operation::{Operation, OperationSerializer, OperationType}, secure_share::SecureShareContent, }; use massa_signature::KeyPair; +use massa_time::MassaTime; use std::str::FromStr; use std::time::Duration; @@ -74,11 +76,13 @@ fn basic_creation_with_multiple_operations() { /// Send 2 block headers and check if a Denunciation op is in storage #[test] -#[ignore] fn test_denunciation_factory_block_header_denunciation() { let keypair = KeyPair::generate(); - let slot = Slot::new(2, 1); + let now = MassaTime::now().expect("could not get current time"); + // get closest slot according to the current absolute time + let slot = get_closest_slot_to_timestamp(THREAD_COUNT, T0, now, now); + let parents: Vec = (0..THREAD_COUNT) .map(|i| BlockId(Hash::compute_from(&[i]))) .collect(); @@ -146,7 +150,8 @@ fn test_denunciation_factory_block_header_denunciation() { let de_indexes = test_factory.storage.read_denunciations(); assert_eq!(de_indexes.get(&denunciation_id), Some(&denunciation)); - drop(de_indexes); // release RwLockReadGuard - // stop everything + // release RwLockReadGuard + drop(de_indexes); + // stop everything drop(test_factory); } diff --git a/massa-factory-worker/src/tests/tools.rs b/massa-factory-worker/src/tests/tools.rs index 87fab3ed49b..9234d286c1c 100644 --- a/massa-factory-worker/src/tests/tools.rs +++ b/massa-factory-worker/src/tests/tools.rs @@ -37,10 +37,11 @@ use massa_wallet::test_exports::create_test_wallet; /// The factory will ask that to the the pool, consensus and factory and then will send the block to the consensus. /// You can use the method `new` to build all the mocks and make the connections /// Then you can use the method `get_next_created_block` that will manage the answers from the mock to the factory depending on the parameters you gave. +#[allow(dead_code)] pub struct TestFactory { consensus_event_receiver: ConsensusEventReceiver, pool_receiver: PoolEventReceiver, - selector_receiver: Receiver, + selector_receiver: Option>, factory_config: FactoryConfig, factory_manager: Box, genesis_blocks: Vec<(BlockId, u64)>, @@ -103,7 +104,7 @@ impl TestFactory { TestFactory { consensus_event_receiver, pool_receiver, - selector_receiver, + selector_receiver: Some(selector_receiver), factory_config, factory_manager, genesis_blocks, @@ -136,6 +137,8 @@ impl TestFactory { loop { match self .selector_receiver + .as_ref() + .unwrap() .recv_timeout(Duration::from_millis(100)) { Ok(MockSelectorControllerMessage::GetProducer { @@ -235,6 +238,16 @@ impl TestFactory { impl Drop for TestFactory { fn drop(&mut self) { + // Need this otherwise factory_manager is stuck while waiting for block & endorsement factory + // to join + // For instance, block factory is waiting for selector.get_producer(...) + // endorsement factory is waiting for selector.get_selection(...) + // Note: that this will make the 2 threads panic + // TODO: find a better way to resolve this + if let Some(selector_receiver) = self.selector_receiver.take() { + drop(selector_receiver); + } + self.factory_manager.stop(); } } diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 905e6e47a25..fbd0ded622f 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -226,6 +226,13 @@ pub const NETWORK_NODE_EVENT_CHANNEL_SIZE: usize = 10_000; /// Threshold to accept a new versioning pub const VERSIONING_THRESHOLD_TRANSITION_ACCEPTED: Amount = Amount::from_mantissa_scale(75, 0); +// +// Constants for denunciation factory +// + +/// denunciation expiration delta (in cycle count) +pub const DENUNCIATION_EXPIRE_CYCLE_DELTA: u64 = 3; + // Some checks at compile time that should not be ignored! #[allow(clippy::assertions_on_constants)] const _: () = { diff --git a/massa-models/src/denunciation.rs b/massa-models/src/denunciation.rs index bee336ef663..8a7cf499f15 100644 --- a/massa-models/src/denunciation.rs +++ b/massa-models/src/denunciation.rs @@ -265,6 +265,40 @@ impl Denunciation { && public_key.verify_signature(&hash_1, &signature_1).is_ok() && public_key.verify_signature(&hash_2, &signature_2).is_ok()) } + + /// Get Denunciation slot ref + pub fn get_slot(&self) -> &Slot { + match self { + Denunciation::Endorsement(endo_de) => &endo_de.slot, + Denunciation::BlockHeader(blkh_de) => &blkh_de.slot, + } + } + + /// For a given slot (and given the slot at now()), check if it can be denounced + /// Can be used to check if block header | endorsement is not too old (at reception or too cleanup cache) + pub fn is_expired( + slot: &Slot, + slot_at_now: &Slot, + last_cs_final_periods: &[u64], + periods_per_cycle: u64, + denunciation_expire_cycle_delta: u64, + ) -> bool { + // Slot is final -> cannot be Denounced anymore, it's too late! + if slot.period <= last_cs_final_periods[slot.thread as usize] { + return true; + } + + // As we need to ensure that the Denounced has some 'Deferred credits' + // we will reject Denunciation older than 3 cycle compared to the current slot + let cycle = slot.get_cycle(periods_per_cycle); + let next_cycle = slot_at_now.get_cycle(periods_per_cycle); + + if (next_cycle - cycle) > denunciation_expire_cycle_delta { + return true; + } + + false + } } /// Create a new Denunciation from 2 SecureShareEndorsement diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index c42624773a9..d859a83f7d2 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -46,7 +46,7 @@ use massa_models::config::constants::{ POS_SAVED_CYCLES, PROTOCOL_CONTROLLER_CHANNEL_SIZE, PROTOCOL_EVENT_CHANNEL_SIZE, ROLL_PRICE, T0, THREAD_COUNT, VERSION, }; -use massa_models::config::CONSENSUS_BOOTSTRAP_PART_SIZE; +use massa_models::config::{CONSENSUS_BOOTSTRAP_PART_SIZE, DENUNCIATION_EXPIRE_CYCLE_DELTA}; use massa_models::endorsement::SecureShareEndorsement; use massa_network_exports::{Establisher, NetworkConfig, NetworkManager}; use massa_network_worker::start_network_controller; @@ -370,6 +370,10 @@ async fn launch( channels_size: POOL_CONTROLLER_CHANNEL_SIZE, broadcast_enabled: SETTINGS.api.enable_ws, broadcast_operations_capacity: SETTINGS.pool.broadcast_operations_capacity, + genesis_timestamp: *GENESIS_TIMESTAMP, + t0: T0, + periods_per_cycle: PERIODS_PER_CYCLE, + denunciation_expire_cycle_delta: DENUNCIATION_EXPIRE_CYCLE_DELTA, }; let pool_channels = PoolChannels { @@ -504,6 +508,8 @@ async fn launch( max_block_size: MAX_BLOCK_SIZE as u64, max_block_gas: MAX_GAS_PER_BLOCK, max_operations_per_block: MAX_OPERATIONS_PER_BLOCK, + periods_per_cycle: PERIODS_PER_CYCLE, + denunciation_expire_cycle_delta: DENUNCIATION_EXPIRE_CYCLE_DELTA, }; let factory_channels = FactoryChannels { selector: selector_controller.clone(), diff --git a/massa-pool-exports/Cargo.toml b/massa-pool-exports/Cargo.toml index a30134f2a5e..9fac2de0182 100644 --- a/massa-pool-exports/Cargo.toml +++ b/massa-pool-exports/Cargo.toml @@ -10,10 +10,10 @@ tokio = { version = "1.23", features = ["sync"] } # custom modules massa_models = { path = "../massa-models" } massa_storage = { path = "../massa-storage" } -massa_time = { path = "../massa-time", optional = true } +massa_time = { path = "../massa-time"} [dev-dependencies] # for more information on what are the following features used for, see the cargo.toml at workspace level [features] -testing = [ "dep:massa_time" ] +testing = [] diff --git a/massa-pool-exports/src/config.rs b/massa-pool-exports/src/config.rs index ff67911e9cb..1405f193773 100644 --- a/massa-pool-exports/src/config.rs +++ b/massa-pool-exports/src/config.rs @@ -1,6 +1,7 @@ //! Copyright (c) 2022 MASSA LABS use massa_models::amount::Amount; +use massa_time::MassaTime; use serde::{Deserialize, Serialize}; /// Pool configuration @@ -30,4 +31,12 @@ pub struct PoolConfig { pub broadcast_enabled: bool, /// operations sender(channel) capacity pub broadcast_operations_capacity: usize, + /// genesis timestamp + pub genesis_timestamp: MassaTime, + /// period duration + pub t0: MassaTime, + /// cycle duration in periods + pub periods_per_cycle: u64, + /// denunciation expiration as cycle delta + pub denunciation_expire_cycle_delta: u64, } diff --git a/massa-pool-exports/src/controller_traits.rs b/massa-pool-exports/src/controller_traits.rs index 85c03963464..de01df45fd1 100644 --- a/massa-pool-exports/src/controller_traits.rs +++ b/massa-pool-exports/src/controller_traits.rs @@ -44,6 +44,9 @@ pub trait PoolController: Send + Sync { /// Returns a boxed clone of self. /// Useful to allow cloning `Box`. fn clone_box(&self) -> Box; + + /// Get final cs periods (updated regularly from consensus) + fn get_final_cs_periods(&self) -> &Vec; } /// Allow cloning `Box` diff --git a/massa-pool-exports/src/test_exports/config.rs b/massa-pool-exports/src/test_exports/config.rs index 65e13b29b78..6f5bc524af6 100644 --- a/massa-pool-exports/src/test_exports/config.rs +++ b/massa-pool-exports/src/test_exports/config.rs @@ -1,8 +1,9 @@ // Copyright (c) 2022 MASSA LABS use massa_models::config::{ - ENDORSEMENT_COUNT, MAX_BLOCK_SIZE, MAX_GAS_PER_BLOCK, MAX_OPERATIONS_PER_BLOCK, - OPERATION_VALIDITY_PERIODS, ROLL_PRICE, THREAD_COUNT, + DENUNCIATION_EXPIRE_CYCLE_DELTA, ENDORSEMENT_COUNT, GENESIS_TIMESTAMP, MAX_BLOCK_SIZE, + MAX_GAS_PER_BLOCK, MAX_OPERATIONS_PER_BLOCK, OPERATION_VALIDITY_PERIODS, PERIODS_PER_CYCLE, + ROLL_PRICE, T0, THREAD_COUNT, }; use crate::PoolConfig; @@ -22,6 +23,10 @@ impl Default for PoolConfig { channels_size: 1024, broadcast_enabled: false, broadcast_operations_capacity: 5000, + genesis_timestamp: *GENESIS_TIMESTAMP, + t0: T0, + periods_per_cycle: PERIODS_PER_CYCLE, + denunciation_expire_cycle_delta: DENUNCIATION_EXPIRE_CYCLE_DELTA, } } } diff --git a/massa-pool-exports/src/test_exports/mock.rs b/massa-pool-exports/src/test_exports/mock.rs index c58d9716423..fdce7357a3e 100644 --- a/massa-pool-exports/src/test_exports/mock.rs +++ b/massa-pool-exports/src/test_exports/mock.rs @@ -5,6 +5,7 @@ use std::sync::{ Arc, Mutex, }; +use massa_models::config::THREAD_COUNT; use massa_models::{ block_id::BlockId, endorsement::EndorsementId, operation::OperationId, slot::Slot, }; @@ -95,7 +96,11 @@ pub enum MockPoolControllerMessage { /// For messages with a `response_tx` field, the mock will await a response through their `response_tx` channel /// in order to simulate returning this value at the end of the call. #[derive(Clone)] -pub struct MockPoolController(Arc>>); +// pub struct MockPoolController(Arc>>); +pub struct MockPoolController { + q: Arc>>, + last_final_cs_periods: Vec, +} impl MockPoolController { /// Create a new pair (mock execution controller, mpsc receiver for emitted messages) @@ -103,7 +108,10 @@ impl MockPoolController { pub fn new_with_receiver() -> (Box, PoolEventReceiver) { let (tx, rx) = mpsc::channel(); ( - Box::new(MockPoolController(Arc::new(Mutex::new(tx)))), + Box::new(MockPoolController { + q: Arc::new(Mutex::new(tx)), + last_final_cs_periods: vec![0u64; THREAD_COUNT as usize], + }), PoolEventReceiver(rx), ) } @@ -129,7 +137,7 @@ impl PoolEventReceiver { /// See the documentation of `PoolController` for details on each function. impl PoolController for MockPoolController { fn add_endorsements(&mut self, endorsements: Storage) { - self.0 + self.q .lock() .unwrap() .send(MockPoolControllerMessage::AddEndorsements { endorsements }) @@ -137,7 +145,7 @@ impl PoolController for MockPoolController { } fn add_operations(&mut self, operations: Storage) { - self.0 + self.q .lock() .unwrap() .send(MockPoolControllerMessage::AddOperations { operations }) @@ -150,7 +158,7 @@ impl PoolController for MockPoolController { target_slot: &Slot, ) -> (Vec>, Storage) { let (response_tx, response_rx) = mpsc::channel(); - self.0 + self.q .lock() .unwrap() .send(MockPoolControllerMessage::GetBlockEndorsements { @@ -164,7 +172,7 @@ impl PoolController for MockPoolController { fn get_block_operations(&self, slot: &Slot) -> (Vec, Storage) { let (response_tx, response_rx) = mpsc::channel(); - self.0 + self.q .lock() .unwrap() .send(MockPoolControllerMessage::GetBlockOperations { @@ -177,7 +185,7 @@ impl PoolController for MockPoolController { fn get_endorsement_count(&self) -> usize { let (response_tx, response_rx) = mpsc::channel(); - self.0 + self.q .lock() .unwrap() .send(MockPoolControllerMessage::GetEndorsementCount { response_tx }) @@ -187,7 +195,7 @@ impl PoolController for MockPoolController { fn get_operation_count(&self) -> usize { let (response_tx, response_rx) = mpsc::channel(); - self.0 + self.q .lock() .unwrap() .send(MockPoolControllerMessage::GetOperationCount { response_tx }) @@ -197,7 +205,7 @@ impl PoolController for MockPoolController { fn contains_endorsements(&self, endorsements: &[EndorsementId]) -> Vec { let (response_tx, response_rx) = mpsc::channel(); - self.0 + self.q .lock() .unwrap() .send(MockPoolControllerMessage::ContainsEndorsements { @@ -210,7 +218,7 @@ impl PoolController for MockPoolController { fn contains_operations(&self, operations: &[OperationId]) -> Vec { let (response_tx, response_rx) = mpsc::channel(); - self.0 + self.q .lock() .unwrap() .send(MockPoolControllerMessage::ContainsOperations { @@ -222,7 +230,8 @@ impl PoolController for MockPoolController { } fn notify_final_cs_periods(&mut self, final_cs_periods: &[u64]) { - self.0 + self.last_final_cs_periods = final_cs_periods.to_vec(); + self.q .lock() .unwrap() .send(MockPoolControllerMessage::NotifyFinalCsPeriods { @@ -236,10 +245,14 @@ impl PoolController for MockPoolController { } fn add_denunciations(&mut self, denunciations: Storage) { - self.0 + self.q .lock() .unwrap() .send(MockPoolControllerMessage::AddDenunciations { denunciations }) .unwrap(); } + + fn get_final_cs_periods(&self) -> &Vec { + &self.last_final_cs_periods + } } diff --git a/massa-pool-worker/Cargo.toml b/massa-pool-worker/Cargo.toml index 5aae0435bd3..cc4df605e86 100644 --- a/massa-pool-worker/Cargo.toml +++ b/massa-pool-worker/Cargo.toml @@ -14,6 +14,7 @@ massa_models = { path = "../massa-models" } massa_storage = { path = "../massa-storage" } massa_pool_exports = { path = "../massa-pool-exports" } massa_execution_exports = { path = "../massa-execution-exports" } +massa_time = { path = "../massa-time" } [dev-dependencies] tokio = { version = "1.23", features = ["sync"] } diff --git a/massa-pool-worker/src/controller_impl.rs b/massa-pool-worker/src/controller_impl.rs index 32151d324da..fdc68bc3902 100644 --- a/massa-pool-worker/src/controller_impl.rs +++ b/massa-pool-worker/src/controller_impl.rs @@ -42,6 +42,10 @@ pub struct PoolControllerImpl { pub(crate) operations_input_sender: SyncSender, /// Endorsement write worker command sender pub(crate) endorsements_input_sender: SyncSender, + /// Denunciation write worker command sender + pub(crate) denunciations_input_sender: SyncSender, + /// Last final periods from Consensus + pub last_cs_final_periods: Vec, } impl PoolController for PoolControllerImpl { @@ -79,6 +83,8 @@ impl PoolController for PoolControllerImpl { /// Asynchronously notify of new final consensus periods. Simply print a warning on failure. fn notify_final_cs_periods(&mut self, final_cs_periods: &[u64]) { + self.last_cs_final_periods = final_cs_periods.to_vec().clone(); + match self .operations_input_sender .try_send(Command::NotifyFinalCsPeriods(final_cs_periods.to_vec())) @@ -110,6 +116,23 @@ impl PoolController for PoolControllerImpl { } Ok(_) => {} } + + match self + .denunciations_input_sender + .try_send(Command::NotifyFinalCsPeriods(final_cs_periods.to_vec())) + { + Err(TrySendError::Disconnected(_)) => { + warn!( + "Could not notify endorsement pool of new final slots: worker is unreachable." + ); + } + Err(TrySendError::Full(_)) => { + warn!( + "Could not notify endorsement pool of new final slots: worker channel is full." + ); + } + Ok(_) => {} + } } /// get operations for block creation @@ -158,8 +181,23 @@ impl PoolController for PoolControllerImpl { /// Add denunciation to pool fn add_denunciations(&mut self, denunciations: Storage) { - let mut lck = self.denunciation_pool.write(); - lck.add_denunciation(denunciations); + match self + .denunciations_input_sender + .try_send(Command::AddItems(denunciations)) + { + Err(TrySendError::Disconnected(_)) => { + warn!("Could not add denunciations to pool: worker is unreachable."); + } + Err(TrySendError::Full(_)) => { + warn!("Could not add denunciations to pool: worker channel is full."); + } + Ok(_) => {} + } + } + + /// Get final consensus periods + fn get_final_cs_periods(&self) -> &Vec { + &self.last_cs_final_periods } } @@ -171,10 +209,14 @@ pub struct PoolManagerImpl { pub(crate) operations_thread_handle: Option>, /// Handle used to join the endorsement thread pub(crate) endorsements_thread_handle: Option>, + /// Handle used to join the denunciation thread + pub(crate) denunciations_thread_handle: Option>, /// Operations input data mpsc (used to stop the pool thread) pub(crate) operations_input_sender: SyncSender, /// Endorsements input data mpsc (used to stop the pool thread) pub(crate) endorsements_input_sender: SyncSender, + /// Denunciations input data mpsc (used to stop the pool thread) + pub(crate) denunciations_input_sender: SyncSender, } impl PoolManager for PoolManagerImpl { diff --git a/massa-pool-worker/src/denunciation_pool.rs b/massa-pool-worker/src/denunciation_pool.rs index 0d2c23984bf..203cad22856 100644 --- a/massa-pool-worker/src/denunciation_pool.rs +++ b/massa-pool-worker/src/denunciation_pool.rs @@ -1,13 +1,21 @@ -use massa_models::prehash::{CapacityAllocator, PreHashSet}; +use massa_models::denunciation::{Denunciation, DenunciationId}; +use massa_models::prehash::{CapacityAllocator, PreHashMap, PreHashSet}; +use massa_models::slot::Slot; +use massa_models::timeslots::get_closest_slot_to_timestamp; use massa_pool_exports::PoolConfig; use massa_storage::Storage; +use massa_time::MassaTime; pub struct DenunciationPool { /// configuration config: PoolConfig, /// storage storage: Storage, + /// last consensus final periods, per thread + last_cs_final_periods: Vec, + /// internal cache + denunciations_cache: PreHashMap, } impl DenunciationPool { @@ -15,6 +23,8 @@ impl DenunciationPool { Self { config, storage: storage.clone_without_refs(), + last_cs_final_periods: vec![0u64; config.thread_count as usize], + denunciations_cache: Default::default(), } } @@ -40,26 +50,39 @@ impl DenunciationPool { .collect::>(); let mut added = PreHashSet::with_capacity(denunciation_ids.len()); - let mut removed = PreHashSet::with_capacity(denunciation_ids.len()); // populate added { let de_indexes = denunciation_storage.read_denunciations(); for de_id in denunciation_ids { - let _de = de_indexes.get(&de_id).expect( + let de = de_indexes.get(&de_id).expect( "Attempting to add denunciation to pool but it is absent from given storage", ); - // TODO: do not add denunciation if expired + let now = MassaTime::now().expect("could not get current time"); + // get closest slot according to the current absolute time + let slot_now = get_closest_slot_to_timestamp( + self.config.thread_count, + self.config.t0, + self.config.genesis_timestamp, + now, + ); + if Denunciation::is_expired( + de.get_slot(), + &slot_now, + &self.last_cs_final_periods, + self.config.periods_per_cycle, + self.config.denunciation_expire_cycle_delta, + ) { + continue; + } - // TODO: check that we do not add "duplicate" + self.denunciations_cache + .insert(de_id, de.get_slot().clone()); added.insert(de_id); } } - // populate removed - // TODO: remove from self storage - // take ownership on added denunciations self.storage.extend(denunciation_storage.split_off( &Default::default(), @@ -67,9 +90,6 @@ impl DenunciationPool { &Default::default(), &added, )); - - // drop removed endorsements from storage - self.storage.drop_denunciation_refs(&removed); } // In next PR @@ -82,4 +102,41 @@ impl DenunciationPool { todo!() } */ + + pub(crate) fn notify_final_cs_periods(&mut self, final_cs_periods: &[u64]) { + // update internal final CS period counter + self.last_cs_final_periods = final_cs_periods.to_vec(); + + // remove all denunciations that are expired + let mut removed: PreHashSet = Default::default(); + + let now = MassaTime::now().expect("could not get current time"); + // get closest slot according to the current absolute time + let slot_now = get_closest_slot_to_timestamp( + self.config.thread_count, + self.config.t0, + self.config.genesis_timestamp, + now, + ); + + for (de_id, de_slot) in self.denunciations_cache.iter() { + if Denunciation::is_expired( + de_slot, + &slot_now, + &self.last_cs_final_periods, + self.config.periods_per_cycle, + self.config.denunciation_expire_cycle_delta, + ) { + removed.insert(de_id.clone()); + } + } + + // Remove from internal cache + for de_id in removed.iter() { + self.denunciations_cache.remove(de_id); + } + + // Remove from storage + self.storage.drop_denunciation_refs(&removed); + } } diff --git a/massa-pool-worker/src/worker.rs b/massa-pool-worker/src/worker.rs index 46f3d44423a..1a0c5c4ce02 100644 --- a/massa-pool-worker/src/worker.rs +++ b/massa-pool-worker/src/worker.rs @@ -108,6 +108,50 @@ impl OperationPoolThread { } } +/// Denunciation pool writer thread. +pub(crate) struct DenunciationPoolThread { + /// Command reception channel + receiver: Receiver, + /// Shared reference to the denunciation pool + denunciation_pool: Arc>, +} + +impl DenunciationPoolThread { + /// Spawns a pool writer thread, returning a join handle. + pub(crate) fn spawn( + receiver: Receiver, + denunciation_pool: Arc>, + ) -> JoinHandle<()> { + let thread_builder = thread::Builder::new().name("denunciation-pool".into()); + thread_builder + .spawn(|| { + let this = Self { + receiver, + denunciation_pool, + }; + this.run() + }) + .expect("failed to spawn thread : operation-pool") + } + + /// Run the thread. + fn run(self) { + loop { + match self.receiver.recv() { + Err(RecvError) => break, + Ok(Command::Stop) => break, + Ok(Command::AddItems(operations)) => { + self.denunciation_pool.write().add_denunciation(operations) + } + Ok(Command::NotifyFinalCsPeriods(final_cs_periods)) => self + .denunciation_pool + .write() + .notify_final_cs_periods(&final_cs_periods), + }; + } + } +} + /// Start pool manager and controller #[allow(clippy::type_complexity)] pub fn start_pool_controller( @@ -120,6 +164,8 @@ pub fn start_pool_controller( let (operations_input_sender, operations_input_receiver) = sync_channel(config.channels_size); let (endorsements_input_sender, endorsements_input_receiver) = sync_channel(config.channels_size); + let (denunciations_input_sender, denunciations_input_receiver) = + sync_channel(config.channels_size); let operation_pool = Arc::new(RwLock::new(OperationPool::init( config, storage, @@ -136,21 +182,27 @@ pub fn start_pool_controller( _config: config, operation_pool: operation_pool.clone(), endorsement_pool: endorsement_pool.clone(), - denunciation_pool: denunciation_pool, + denunciation_pool: denunciation_pool.clone(), operations_input_sender: operations_input_sender.clone(), endorsements_input_sender: endorsements_input_sender.clone(), + denunciations_input_sender: denunciations_input_sender.clone(), + last_cs_final_periods: vec![0u64; usize::from(config.thread_count)], }; let operations_thread_handle = OperationPoolThread::spawn(operations_input_receiver, operation_pool); let endorsements_thread_handle = EndorsementPoolThread::spawn(endorsements_input_receiver, endorsement_pool); + let denunciations_thread_handle = + DenunciationPoolThread::spawn(denunciations_input_receiver, denunciation_pool); let manager = PoolManagerImpl { operations_thread_handle: Some(operations_thread_handle), endorsements_thread_handle: Some(endorsements_thread_handle), + denunciations_thread_handle: Some(denunciations_thread_handle), operations_input_sender, endorsements_input_sender, + denunciations_input_sender, }; (Box::new(manager), Box::new(controller)) } diff --git a/massa-storage/src/denunciation_indexes.rs b/massa-storage/src/denunciation_indexes.rs index c67cad18a62..660d9843f04 100644 --- a/massa-storage/src/denunciation_indexes.rs +++ b/massa-storage/src/denunciation_indexes.rs @@ -13,6 +13,7 @@ impl DenunciationIndexes { /// Insert a denunciation /// Arguments: /// - denunciation: the denunciation to insert + #[allow(unused_must_use)] pub(crate) fn insert(&mut self, denunciation: Denunciation) { let denunciation_id = DenunciationId::from(&denunciation); self.denunciations.try_insert(denunciation_id, denunciation); From 5ef5bbdb8f2ad8fa4adfeafe0bac8e7ebd2d80c9 Mon Sep 17 00:00:00 2001 From: sydhds Date: Thu, 30 Mar 2023 09:50:41 +0200 Subject: [PATCH 03/13] Stop denunciation pool in PoolManager --- massa-execution-worker/src/execution.rs | 2 +- massa-pool-exports/src/controller_traits.rs | 3 +++ massa-pool-worker/src/controller_impl.rs | 13 ++++++++++++- massa-pool-worker/src/denunciation_pool.rs | 9 ++++----- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 99b6b0adf19..f1a2d2650ad 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -39,7 +39,7 @@ use massa_storage::Storage; use parking_lot::{Mutex, RwLock}; use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::sync::Arc; -use tracing::{debug, error, info, warn}; +use tracing::{debug, info, warn}; /// Used to acquire a lock on the execution context macro_rules! context_guard { diff --git a/massa-pool-exports/src/controller_traits.rs b/massa-pool-exports/src/controller_traits.rs index de01df45fd1..ad75e5233da 100644 --- a/massa-pool-exports/src/controller_traits.rs +++ b/massa-pool-exports/src/controller_traits.rs @@ -41,6 +41,9 @@ pub trait PoolController: Send + Sync { /// Add denunciations to pool. Simply print a warning on failure. fn add_denunciations(&mut self, denunciations: Storage); + /// Get the number of denunciations in the pool + fn get_denunciation_count(&self) -> usize; + /// Returns a boxed clone of self. /// Useful to allow cloning `Box`. fn clone_box(&self) -> Box; diff --git a/massa-pool-worker/src/controller_impl.rs b/massa-pool-worker/src/controller_impl.rs index fdc68bc3902..3a75f59a2bb 100644 --- a/massa-pool-worker/src/controller_impl.rs +++ b/massa-pool-worker/src/controller_impl.rs @@ -83,7 +83,7 @@ impl PoolController for PoolControllerImpl { /// Asynchronously notify of new final consensus periods. Simply print a warning on failure. fn notify_final_cs_periods(&mut self, final_cs_periods: &[u64]) { - self.last_cs_final_periods = final_cs_periods.to_vec().clone(); + self.last_cs_final_periods = final_cs_periods.to_vec(); match self .operations_input_sender @@ -195,6 +195,11 @@ impl PoolController for PoolControllerImpl { } } + /// Get the number of denunciations in the pool + fn get_denunciation_count(&self) -> usize { + self.denunciation_pool.read().len() + } + /// Get final consensus periods fn get_final_cs_periods(&self) -> &Vec { &self.last_cs_final_periods @@ -225,6 +230,7 @@ impl PoolManager for PoolManagerImpl { info!("stopping pool workers..."); let _ = self.operations_input_sender.send(Command::Stop); let _ = self.endorsements_input_sender.send(Command::Stop); + let _ = self.denunciations_input_sender.send(Command::Stop); if let Some(join_handle) = self.operations_thread_handle.take() { join_handle .join() @@ -235,6 +241,11 @@ impl PoolManager for PoolManagerImpl { .join() .expect("endorsements pool thread panicked on try to join"); } + if let Some(join_handle) = self.denunciations_thread_handle.take() { + join_handle + .join() + .expect("denunciations pool thread panicked on try to join"); + } info!("pool workers stopped"); } } diff --git a/massa-pool-worker/src/denunciation_pool.rs b/massa-pool-worker/src/denunciation_pool.rs index 203cad22856..6068cf3bd2f 100644 --- a/massa-pool-worker/src/denunciation_pool.rs +++ b/massa-pool-worker/src/denunciation_pool.rs @@ -28,13 +28,13 @@ impl DenunciationPool { } } - // Not used yet - /* /// Get the number of stored elements pub fn len(&self) -> usize { self.storage.get_denunciation_refs().len() } + // Not used yet + /* /// Checks whether an element is stored in the pool pub fn contains(&self, id: &DenunciationId) -> bool { self.storage.get_denunciation_refs().contains(id) @@ -77,8 +77,7 @@ impl DenunciationPool { continue; } - self.denunciations_cache - .insert(de_id, de.get_slot().clone()); + self.denunciations_cache.insert(de_id, *de.get_slot()); added.insert(de_id); } } @@ -127,7 +126,7 @@ impl DenunciationPool { self.config.periods_per_cycle, self.config.denunciation_expire_cycle_delta, ) { - removed.insert(de_id.clone()); + removed.insert(*de_id); } } From 859ad17fa659ec7149f1fc19d731342caecb5ed3 Mon Sep 17 00:00:00 2001 From: sydhds Date: Thu, 30 Mar 2023 10:14:33 +0200 Subject: [PATCH 04/13] Add get_denunciation_count in mock too --- massa-pool-exports/src/test_exports/mock.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/massa-pool-exports/src/test_exports/mock.rs b/massa-pool-exports/src/test_exports/mock.rs index fdce7357a3e..98e52c5823d 100644 --- a/massa-pool-exports/src/test_exports/mock.rs +++ b/massa-pool-exports/src/test_exports/mock.rs @@ -63,6 +63,11 @@ pub enum MockPoolControllerMessage { /// Response channel response_tx: mpsc::Sender, }, + /// Get denunciation count + GetDenunciationCount { + /// Response channel + response_tx: mpsc::Sender, + }, /// Contains endorsements ContainsEndorsements { /// ids to search @@ -255,4 +260,14 @@ impl PoolController for MockPoolController { fn get_final_cs_periods(&self) -> &Vec { &self.last_final_cs_periods } + + fn get_denunciation_count(&self) -> usize { + let (response_tx, response_rx) = mpsc::channel(); + self.q + .lock() + .unwrap() + .send(MockPoolControllerMessage::GetDenunciationCount { response_tx }) + .unwrap(); + response_rx.recv().unwrap() + } } From 66e9ddb0d36e466ca015f08f4f98bddbbfcfbace Mon Sep 17 00:00:00 2001 From: sydhds Date: Thu, 30 Mar 2023 19:40:20 +0200 Subject: [PATCH 05/13] Do not use storage in DenunciationPool && Check selector in DenunciationFactory --- .../src/denunciation_factory.rs | 72 ++++++++++--- massa-factory-worker/src/tests/scenarios.rs | 10 +- massa-models/src/denunciation.rs | 23 ++-- massa-pool-exports/src/controller_traits.rs | 3 +- massa-pool-exports/src/test_exports/mock.rs | 13 +-- massa-pool-worker/src/controller_impl.rs | 7 +- massa-pool-worker/src/denunciation_pool.rs | 101 +++++------------- massa-pool-worker/src/endorsement_pool.rs | 1 - massa-pool-worker/src/lib.rs | 1 + massa-pool-worker/src/operation_pool.rs | 1 - massa-pool-worker/src/worker.rs | 19 +++- massa-storage/src/lib.rs | 88 --------------- 12 files changed, 131 insertions(+), 208 deletions(-) diff --git a/massa-factory-worker/src/denunciation_factory.rs b/massa-factory-worker/src/denunciation_factory.rs index 573ad36d472..3919753acd7 100644 --- a/massa-factory-worker/src/denunciation_factory.rs +++ b/massa-factory-worker/src/denunciation_factory.rs @@ -6,6 +6,7 @@ use crossbeam_channel::{select, Receiver}; use tracing::{debug, info, warn}; use massa_factory_exports::{FactoryChannels, FactoryConfig}; +use massa_models::address::Address; use massa_models::block_header::SecuredHeader; use massa_models::denunciation::Denunciation; use massa_models::endorsement::SecureShareEndorsement; @@ -18,7 +19,6 @@ const DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN: usize = 4096; const DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN: usize = 4096; /// Structure gathering all elements needed by the factory thread -#[allow(dead_code)] pub(crate) struct DenunciationFactoryWorker { cfg: FactoryConfig, channels: FactoryChannels, @@ -78,6 +78,23 @@ impl DenunciationFactoryWorker { return; } + // Get selected address from selector and check + // Note: If the public key of the header creator is not checked to match the PoS, + // someone can spam with headers coming from various non-PoS-drawn pubkeys + // and cause a problem + let selected_address = self.channels.selector.get_producer(key); + match selected_address { + Ok(address) => { + if address != Address::from_public_key(&secured_header.content_creator_pub_key) { + warn!("Denunciation factory received a secured header but address was not selected"); + return; + } + } + Err(e) => { + warn!("Cannot get producer from selector: {}", e); + } + } + let denunciation_: Option = match self.block_header_by_slot.entry(key) { Entry::Occupied(mut eo) => { let secured_headers = eo.get_mut(); @@ -90,11 +107,13 @@ impl DenunciationFactoryWorker { let header_1 = secured_headers.get(0).unwrap(); let header_2 = secured_headers.get(1).unwrap(); let de_ = Denunciation::try_from((header_1, header_2)); - if let Err(e) = de_ { - debug!("Denunciation factory cannot create denunciation from block headers: {}", e); - return; + match de_ { + Ok(de) => Some(de), + Err(e) => { + debug!("Denunciation factory cannot create denunciation from block headers: {}", e); + return; + } } - Some(de_.unwrap()) // Already checked for error } else { // Already 2 entries - so a Denunciation has already been created None @@ -112,9 +131,7 @@ impl DenunciationFactoryWorker { denunciation ); - let mut de_storage = self.channels.storage.clone_without_refs(); - de_storage.store_denunciation(denunciation); - self.channels.pool.add_denunciations(de_storage); + self.channels.pool.add_denunciation(denunciation); } self.cleanup_cache(); @@ -125,10 +142,10 @@ impl DenunciationFactoryWorker { &mut self, secure_share_endorsement: SecureShareEndorsement, ) { - let key = ( - secure_share_endorsement.content.slot, - secure_share_endorsement.content.index, - ); + let endo_slot = secure_share_endorsement.content.slot; + let endo_index = secure_share_endorsement.content.index; + let endo_index_usize = endo_index as usize; + let key = (endo_slot, endo_index); if self.endorsements_by_slot_index.contains_key(&key) { warn!( "Denunciation factory process an endorsement that have already been denounced: {}", @@ -137,6 +154,29 @@ impl DenunciationFactoryWorker { return; } + // Get selected address from selector and check + let selected = self.channels.selector.get_selection(endo_slot); + match selected { + Ok(selection) => { + if let Some(address) = selection.endorsements.get(endo_index_usize) { + if *address + != Address::from_public_key( + &secure_share_endorsement.content_creator_pub_key, + ) + { + warn!("Denunciation factory received a secure share endorsement but address was not selected"); + return; + } + } else { + warn!("Denunciation factory could not get selected address for endorsements at index: {}", endo_index_usize); + return; + } + } + Err(e) => { + warn!("Cannot get producer from selector: {}", e); + } + } + if self.endorsements_by_slot_index.len() > DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN { warn!( "Denunciation factory cannot process - cache full: {}", @@ -179,9 +219,7 @@ impl DenunciationFactoryWorker { denunciation ); - let mut de_storage = self.channels.storage.clone_without_refs(); - de_storage.store_denunciation(denunciation); - self.channels.pool.add_denunciations(de_storage); + self.channels.pool.add_denunciation(denunciation); } self.cleanup_cache(); @@ -199,7 +237,7 @@ impl DenunciationFactoryWorker { ); self.endorsements_by_slot_index.retain(|(slot, _index), _| { - Denunciation::is_expired( + !Denunciation::is_expired( slot, &slot_now, self.channels.pool.get_final_cs_periods(), @@ -209,7 +247,7 @@ impl DenunciationFactoryWorker { }); self.block_header_by_slot.retain(|slot, _| { - Denunciation::is_expired( + !Denunciation::is_expired( slot, &slot_now, self.channels.pool.get_final_cs_periods(), diff --git a/massa-factory-worker/src/tests/scenarios.rs b/massa-factory-worker/src/tests/scenarios.rs index c5f0dd721ff..2e11f502fff 100644 --- a/massa-factory-worker/src/tests/scenarios.rs +++ b/massa-factory-worker/src/tests/scenarios.rs @@ -130,8 +130,8 @@ fn test_denunciation_factory_block_header_denunciation() { BlockHeader::new_verifiable(header2, BlockHeaderSerializer::new(), &keypair).unwrap(); // Built it to compare with what the factory will produce - let denunciation = Denunciation::try_from((&secured_header_1, &secured_header_2)).unwrap(); - let denunciation_id = DenunciationId::from(&denunciation); + let _denunciation = Denunciation::try_from((&secured_header_1, &secured_header_2)).unwrap(); + let _denunciation_id = DenunciationId::from(&_denunciation); let test_factory = TestFactory::new(&keypair); @@ -147,11 +147,11 @@ fn test_denunciation_factory_block_header_denunciation() { // Wait for denunciation factory to create the Denunciation std::thread::sleep(Duration::from_secs(1)); - let de_indexes = test_factory.storage.read_denunciations(); - assert_eq!(de_indexes.get(&denunciation_id), Some(&denunciation)); + // let de_indexes = test_factory.storage.read_denunciations(); + // assert_eq!(de_indexes.get(&denunciation_id), Some(&denunciation)); // release RwLockReadGuard - drop(de_indexes); + // drop(de_indexes); // stop everything drop(test_factory); } diff --git a/massa-models/src/denunciation.rs b/massa-models/src/denunciation.rs index 8a7cf499f15..c97b092440a 100644 --- a/massa-models/src/denunciation.rs +++ b/massa-models/src/denunciation.rs @@ -17,7 +17,7 @@ use crate::block_header::{ use crate::endorsement::{ Endorsement, EndorsementDenunciationData, EndorsementSerializer, SecureShareEndorsement, }; -use crate::slot::{Slot, SlotDeserializer, SlotSerializer}; +use crate::slot::{Slot, SlotDeserializer, SlotSerializer, SLOT_KEY_SIZE}; use crate::prehash::PreHashed; use crate::secure_share::Id; @@ -28,11 +28,12 @@ use massa_serialization::{ }; use massa_signature::{ MassaSignatureError, PublicKey, PublicKeyDeserializer, Signature, SignatureDeserializer, + PUBLIC_KEY_SIZE_BYTES, }; /// A Variant of Denunciation enum for endorsement #[allow(dead_code)] -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct EndorsementDenunciation { public_key: PublicKey, slot: Slot, @@ -75,7 +76,7 @@ impl EndorsementDenunciation { /// A Variant of Denunciation enum for block header #[allow(dead_code)] -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct BlockHeaderDenunciation { public_key: PublicKey, slot: Slot, @@ -123,7 +124,7 @@ impl BlockHeaderDenunciation { } /// A denunciation enum -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] #[allow(missing_docs)] pub enum Denunciation { Endorsement(EndorsementDenunciation), @@ -293,11 +294,7 @@ impl Denunciation { let cycle = slot.get_cycle(periods_per_cycle); let next_cycle = slot_at_now.get_cycle(periods_per_cycle); - if (next_cycle - cycle) > denunciation_expire_cycle_delta { - return true; - } - - false + (next_cycle - cycle) > denunciation_expire_cycle_delta } } @@ -809,12 +806,12 @@ impl DenunciationId { self.0.to_bytes() } - /// endorsement id into bytes + /// denunciation id into bytes pub fn into_bytes(self) -> [u8; DENUNCIATION_ID_SIZE_BYTES] { self.0.into_bytes() } - /// endorsement id from bytes + /// denunciation id from bytes pub fn from_bytes(data: &[u8; DENUNCIATION_ID_SIZE_BYTES]) -> DenunciationId { DenunciationId(Hash::from_bytes(data)) } @@ -824,7 +821,9 @@ impl From<&Denunciation> for DenunciationId { fn from(value: &Denunciation) -> Self { match value { Denunciation::Endorsement(endo_de) => { - let mut to_hash = Vec::new(); + let mut to_hash = Vec::with_capacity( + std::mem::size_of::() + PUBLIC_KEY_SIZE_BYTES + SLOT_KEY_SIZE, + ); to_hash.extend(endo_de.public_key.to_bytes()); to_hash.extend(endo_de.slot.to_bytes_key()); to_hash.extend(endo_de.index.to_le_bytes()); diff --git a/massa-pool-exports/src/controller_traits.rs b/massa-pool-exports/src/controller_traits.rs index ad75e5233da..5cc779035b3 100644 --- a/massa-pool-exports/src/controller_traits.rs +++ b/massa-pool-exports/src/controller_traits.rs @@ -1,5 +1,6 @@ // Copyright (c) 2022 MASSA LABS +use massa_models::denunciation::Denunciation; use massa_models::{ block_id::BlockId, endorsement::EndorsementId, operation::OperationId, slot::Slot, }; @@ -39,7 +40,7 @@ pub trait PoolController: Send + Sync { fn contains_operations(&self, operations: &[OperationId]) -> Vec; /// Add denunciations to pool. Simply print a warning on failure. - fn add_denunciations(&mut self, denunciations: Storage); + fn add_denunciation(&mut self, denunciation: Denunciation); /// Get the number of denunciations in the pool fn get_denunciation_count(&self) -> usize; diff --git a/massa-pool-exports/src/test_exports/mock.rs b/massa-pool-exports/src/test_exports/mock.rs index 98e52c5823d..f4072c09daf 100644 --- a/massa-pool-exports/src/test_exports/mock.rs +++ b/massa-pool-exports/src/test_exports/mock.rs @@ -6,6 +6,7 @@ use std::sync::{ }; use massa_models::config::THREAD_COUNT; +use massa_models::denunciation::Denunciation; use massa_models::{ block_id::BlockId, endorsement::EndorsementId, operation::OperationId, slot::Slot, }; @@ -32,10 +33,10 @@ pub enum MockPoolControllerMessage { /// Storage that contains all operations operations: Storage, }, - /// Add denunciations to the pool - AddDenunciations { - /// Storage that contains all denunciations - denunciations: Storage, + /// Add denunciation to the pool + AddDenunciation { + /// The denunciation to add + denunciation: Denunciation, }, /// Get block endorsements GetBlockEndorsements { @@ -249,11 +250,11 @@ impl PoolController for MockPoolController { Box::new(self.clone()) } - fn add_denunciations(&mut self, denunciations: Storage) { + fn add_denunciation(&mut self, denunciation: Denunciation) { self.q .lock() .unwrap() - .send(MockPoolControllerMessage::AddDenunciations { denunciations }) + .send(MockPoolControllerMessage::AddDenunciation { denunciation }) .unwrap(); } diff --git a/massa-pool-worker/src/controller_impl.rs b/massa-pool-worker/src/controller_impl.rs index 3a75f59a2bb..3de6ee1c7d3 100644 --- a/massa-pool-worker/src/controller_impl.rs +++ b/massa-pool-worker/src/controller_impl.rs @@ -2,6 +2,7 @@ //! Pool controller implementation +use massa_models::denunciation::Denunciation; use massa_models::{ block_id::BlockId, endorsement::EndorsementId, operation::OperationId, slot::Slot, }; @@ -21,6 +22,8 @@ use crate::{ pub enum Command { /// Add items to the pool AddItems(Storage), + /// Add denunciation to the pool + AddDenunciation(Denunciation), /// Notify of new final consensus periods NotifyFinalCsPeriods(Vec), /// Stop the worker @@ -180,10 +183,10 @@ impl PoolController for PoolControllerImpl { } /// Add denunciation to pool - fn add_denunciations(&mut self, denunciations: Storage) { + fn add_denunciation(&mut self, denunciation: Denunciation) { match self .denunciations_input_sender - .try_send(Command::AddItems(denunciations)) + .try_send(Command::AddDenunciation(denunciation)) { Err(TrySendError::Disconnected(_)) => { warn!("Could not add denunciations to pool: worker is unreachable."); diff --git a/massa-pool-worker/src/denunciation_pool.rs b/massa-pool-worker/src/denunciation_pool.rs index 6068cf3bd2f..7fee53bd212 100644 --- a/massa-pool-worker/src/denunciation_pool.rs +++ b/massa-pool-worker/src/denunciation_pool.rs @@ -1,28 +1,25 @@ use massa_models::denunciation::{Denunciation, DenunciationId}; -use massa_models::prehash::{CapacityAllocator, PreHashMap, PreHashSet}; -use massa_models::slot::Slot; +use massa_models::prehash::PreHashMap; use massa_models::timeslots::get_closest_slot_to_timestamp; use massa_pool_exports::PoolConfig; -use massa_storage::Storage; use massa_time::MassaTime; pub struct DenunciationPool { /// configuration config: PoolConfig, /// storage - storage: Storage, + // storage: Storage, /// last consensus final periods, per thread last_cs_final_periods: Vec, /// internal cache - denunciations_cache: PreHashMap, + denunciations_cache: PreHashMap, } impl DenunciationPool { - pub fn init(config: PoolConfig, storage: &Storage) -> Self { + pub fn init(config: PoolConfig) -> Self { Self { config, - storage: storage.clone_without_refs(), last_cs_final_periods: vec![0u64; config.thread_count as usize], denunciations_cache: Default::default(), } @@ -30,7 +27,7 @@ impl DenunciationPool { /// Get the number of stored elements pub fn len(&self) -> usize { - self.storage.get_denunciation_refs().len() + self.denunciations_cache.len() } // Not used yet @@ -42,53 +39,25 @@ impl DenunciationPool { */ /// Add a list of denunciation to the pool - pub(crate) fn add_denunciation(&mut self, mut denunciation_storage: Storage) { - let denunciation_ids = denunciation_storage - .get_denunciation_refs() - .iter() - .copied() - .collect::>(); - - let mut added = PreHashSet::with_capacity(denunciation_ids.len()); - - // populate added - { - let de_indexes = denunciation_storage.read_denunciations(); - for de_id in denunciation_ids { - let de = de_indexes.get(&de_id).expect( - "Attempting to add denunciation to pool but it is absent from given storage", - ); - - let now = MassaTime::now().expect("could not get current time"); - // get closest slot according to the current absolute time - let slot_now = get_closest_slot_to_timestamp( - self.config.thread_count, - self.config.t0, - self.config.genesis_timestamp, - now, - ); - if Denunciation::is_expired( - de.get_slot(), - &slot_now, - &self.last_cs_final_periods, - self.config.periods_per_cycle, - self.config.denunciation_expire_cycle_delta, - ) { - continue; - } - - self.denunciations_cache.insert(de_id, *de.get_slot()); - added.insert(de_id); - } + pub(crate) fn add_denunciation(&mut self, denunciation: Denunciation) { + let now = MassaTime::now().expect("could not get current time"); + // get closest slot according to the current absolute time + let slot_now = get_closest_slot_to_timestamp( + self.config.thread_count, + self.config.t0, + self.config.genesis_timestamp, + now, + ); + if !Denunciation::is_expired( + denunciation.get_slot(), + &slot_now, + &self.last_cs_final_periods, + self.config.periods_per_cycle, + self.config.denunciation_expire_cycle_delta, + ) { + let de_id = DenunciationId::from(&denunciation); + self.denunciations_cache.insert(de_id, denunciation); } - - // take ownership on added denunciations - self.storage.extend(denunciation_storage.split_off( - &Default::default(), - &Default::default(), - &Default::default(), - &added, - )); } // In next PR @@ -106,9 +75,6 @@ impl DenunciationPool { // update internal final CS period counter self.last_cs_final_periods = final_cs_periods.to_vec(); - // remove all denunciations that are expired - let mut removed: PreHashSet = Default::default(); - let now = MassaTime::now().expect("could not get current time"); // get closest slot according to the current absolute time let slot_now = get_closest_slot_to_timestamp( @@ -118,24 +84,15 @@ impl DenunciationPool { now, ); - for (de_id, de_slot) in self.denunciations_cache.iter() { - if Denunciation::is_expired( - de_slot, + // remove all denunciations that are expired + self.denunciations_cache.drain_filter(|_de_id, de| { + Denunciation::is_expired( + de.get_slot(), &slot_now, &self.last_cs_final_periods, self.config.periods_per_cycle, self.config.denunciation_expire_cycle_delta, - ) { - removed.insert(*de_id); - } - } - - // Remove from internal cache - for de_id in removed.iter() { - self.denunciations_cache.remove(de_id); - } - - // Remove from storage - self.storage.drop_denunciation_refs(&removed); + ) + }); } } diff --git a/massa-pool-worker/src/endorsement_pool.rs b/massa-pool-worker/src/endorsement_pool.rs index 18aec2b248e..9db24844f8f 100644 --- a/massa-pool-worker/src/endorsement_pool.rs +++ b/massa-pool-worker/src/endorsement_pool.rs @@ -156,7 +156,6 @@ impl EndorsementPool { &Default::default(), &Default::default(), &added, - &Default::default(), )); // drop removed endorsements from storage diff --git a/massa-pool-worker/src/lib.rs b/massa-pool-worker/src/lib.rs index 678874bb469..38e44e7a6dc 100644 --- a/massa-pool-worker/src/lib.rs +++ b/massa-pool-worker/src/lib.rs @@ -7,6 +7,7 @@ #![feature(async_closure)] #![feature(map_try_insert)] #![feature(let_chains)] +#![feature(hash_drain_filter)] mod controller_impl; mod denunciation_pool; diff --git a/massa-pool-worker/src/operation_pool.rs b/massa-pool-worker/src/operation_pool.rs index ad3499beac0..6f20d0c9f10 100644 --- a/massa-pool-worker/src/operation_pool.rs +++ b/massa-pool-worker/src/operation_pool.rs @@ -179,7 +179,6 @@ impl OperationPool { &Default::default(), &added, &Default::default(), - &Default::default(), )); // Clean the removed operations from storage. diff --git a/massa-pool-worker/src/worker.rs b/massa-pool-worker/src/worker.rs index 1a0c5c4ce02..856a17506e1 100644 --- a/massa-pool-worker/src/worker.rs +++ b/massa-pool-worker/src/worker.rs @@ -19,6 +19,7 @@ use std::{ thread, thread::JoinHandle, }; +use tracing::warn; /// Endorsement pool write thread instance pub(crate) struct EndorsementPoolThread { @@ -59,6 +60,10 @@ impl EndorsementPoolThread { .endorsement_pool .write() .notify_final_cs_periods(&final_cs_periods), + _ => { + warn!("EndorsementPoolThread received an unexpected command"); + continue; + } } } } @@ -103,6 +108,10 @@ impl OperationPoolThread { .operation_pool .write() .notify_final_cs_periods(&final_cs_periods), + _ => { + warn!("OperationPoolThread received an unexpected command"); + continue; + } }; } } @@ -140,13 +149,17 @@ impl DenunciationPoolThread { match self.receiver.recv() { Err(RecvError) => break, Ok(Command::Stop) => break, - Ok(Command::AddItems(operations)) => { - self.denunciation_pool.write().add_denunciation(operations) + Ok(Command::AddDenunciation(de)) => { + self.denunciation_pool.write().add_denunciation(de) } Ok(Command::NotifyFinalCsPeriods(final_cs_periods)) => self .denunciation_pool .write() .notify_final_cs_periods(&final_cs_periods), + _ => { + warn!("DenunciationPoolThread received an unexpected command"); + continue; + } }; } } @@ -177,7 +190,7 @@ pub fn start_pool_controller( storage, denunciation_factory_tx, ))); - let denunciation_pool = Arc::new(RwLock::new(DenunciationPool::init(config, storage))); + let denunciation_pool = Arc::new(RwLock::new(DenunciationPool::init(config))); let controller = PoolControllerImpl { _config: config, operation_pool: operation_pool.clone(), diff --git a/massa-storage/src/lib.rs b/massa-storage/src/lib.rs index 55fc605558b..8ca9ddb6212 100644 --- a/massa-storage/src/lib.rs +++ b/massa-storage/src/lib.rs @@ -11,7 +11,6 @@ #![feature(map_try_insert)] mod block_indexes; -mod denunciation_indexes; mod endorsement_indexes; mod operation_indexes; @@ -19,15 +18,12 @@ mod operation_indexes; mod tests; use block_indexes::BlockIndexes; -use denunciation_indexes::DenunciationIndexes; use endorsement_indexes::EndorsementIndexes; -use massa_models::denunciation::Denunciation; use massa_models::prehash::{CapacityAllocator, PreHashMap, PreHashSet, PreHashed}; use massa_models::secure_share::Id; use massa_models::{ block::SecureShareBlock, block_id::BlockId, - denunciation::DenunciationId, endorsement::{EndorsementId, SecureShareEndorsement}, operation::{OperationId, SecureShareOperation}, }; @@ -45,8 +41,6 @@ pub struct Storage { operations: Arc>, /// global operation storage endorsements: Arc>, - /// global denunciation storage - denunciations: Arc>, /// global block reference counter block_owners: Arc>>, @@ -54,8 +48,6 @@ pub struct Storage { operation_owners: Arc>>, /// global endorsement reference counter endorsement_owners: Arc>>, - /// global denunciation reference counter - denunciation_owners: Arc>>, /// locally used block references local_used_blocks: PreHashSet, @@ -63,8 +55,6 @@ pub struct Storage { local_used_ops: PreHashSet, /// locally used endorsement references local_used_endorsements: PreHashSet, - /// locally used denunciation references - local_used_denunciations: PreHashSet, } impl Debug for Storage { @@ -113,15 +103,12 @@ impl Storage { blocks: Default::default(), operations: Default::default(), endorsements: Default::default(), - denunciations: Default::default(), block_owners: Default::default(), operation_owners: Default::default(), endorsement_owners: Default::default(), - denunciation_owners: Default::default(), local_used_blocks: Default::default(), local_used_ops: Default::default(), local_used_endorsements: Default::default(), - local_used_denunciations: Default::default(), } } @@ -131,18 +118,15 @@ impl Storage { blocks: self.blocks.clone(), operations: self.operations.clone(), endorsements: self.endorsements.clone(), - denunciations: self.denunciations.clone(), operation_owners: self.operation_owners.clone(), block_owners: self.block_owners.clone(), endorsement_owners: self.endorsement_owners.clone(), - denunciation_owners: self.denunciation_owners.clone(), // do not clone local ref lists local_used_ops: Default::default(), local_used_blocks: Default::default(), local_used_endorsements: Default::default(), - local_used_denunciations: Default::default(), } } @@ -179,7 +163,6 @@ impl Storage { blocks: &PreHashSet, operations: &PreHashSet, endorsements: &PreHashSet, - denunciations: &PreHashSet, ) -> Storage { // Make a clone of self, which has no ref ownership. let mut res = self.clone_without_refs(); @@ -214,15 +197,6 @@ impl Storage { }) .collect(); - res.local_used_denunciations = denunciations - .iter() - .map(|id| { - self.local_used_denunciations - .take(id) - .expect("split endorsement ref not owned by source") - }) - .collect(); - res } @@ -418,11 +392,6 @@ impl Storage { self.blocks.read() } - /// Gets a read reference to the denunciation index - pub fn read_denunciations(&self) -> RwLockReadGuard { - self.denunciations.read() - } - /// Claim endorsement references. /// Returns the set of operation refs that were found and claimed. pub fn claim_endorsement_refs( @@ -505,63 +474,6 @@ impl Storage { } Storage::internal_claim_refs(&ids, &mut owners, &mut self.local_used_endorsements); } - - /// Store denunciation - pub fn store_denunciation(&mut self, denunciation: Denunciation) { - let mut owners = self.denunciation_owners.write(); - let mut de_indexes = self.denunciations.write(); - let de_id = DenunciationId::from(&denunciation); - de_indexes.insert(denunciation); - let mut ids = PreHashSet::with_capacity(1); - ids.insert(de_id); - Storage::internal_claim_refs(&ids, &mut owners, &mut self.local_used_denunciations); - } - - /// get the denunciation reference ownership - pub fn get_denunciation_refs(&self) -> &PreHashSet { - &self.local_used_denunciations - } - - /// Drop local denunciation references. - /// Ignores already-absent refs. - pub fn drop_denunciation_refs(&mut self, ids: &PreHashSet) { - if ids.is_empty() { - return; - } - let mut owners = self.denunciation_owners.write(); - let mut orphaned_ids = Vec::new(); - for id in ids { - if !self.local_used_denunciations.remove(id) { - // the object was already not referenced locally - continue; - } - match owners.entry(*id) { - hash_map::Entry::Occupied(mut occ) => { - let res_count = { - let cnt = occ.get_mut(); - *cnt = cnt - .checked_sub(1) - .expect("less than 1 owner on storage object reference drop"); - *cnt - }; - if res_count == 0 { - orphaned_ids.push(*id); - occ.remove(); - } - } - hash_map::Entry::Vacant(_vac) => { - panic!("missing object in storage on storage object reference drop"); - } - } - } - // if there are orphaned objects, remove them from storage - if !orphaned_ids.is_empty() { - let mut des = self.denunciations.write(); - for id in orphaned_ids { - des.remove(&id); - } - } - } } impl Drop for Storage { From fd6e71483641eaa3efdc9ea6fce18171087ec9c2 Mon Sep 17 00:00:00 2001 From: sydhds Date: Fri, 31 Mar 2023 10:02:06 +0200 Subject: [PATCH 06/13] Rework DenunciationFactory internal caching --- massa-consensus-exports/src/channels.rs | 1 + .../src/denunciation_factory.rs | 105 +++++++++--------- massa-pool-worker/src/controller_impl.rs | 1 + 3 files changed, 57 insertions(+), 50 deletions(-) diff --git a/massa-consensus-exports/src/channels.rs b/massa-consensus-exports/src/channels.rs index 51d22d131cb..596ad9082de 100644 --- a/massa-consensus-exports/src/channels.rs +++ b/massa-consensus-exports/src/channels.rs @@ -26,5 +26,6 @@ pub struct ConsensusChannels { pub block_header_sender: tokio::sync::broadcast::Sender, /// Channel use by Websocket (if they are enable) to broadcast a new block integrated pub filled_block_sender: tokio::sync::broadcast::Sender, + /// Channel use for Denunciation factory to create denunciations pub denunciation_factory_sender: crossbeam_channel::Sender, } diff --git a/massa-factory-worker/src/denunciation_factory.rs b/massa-factory-worker/src/denunciation_factory.rs index 3919753acd7..0a5c880bae9 100644 --- a/massa-factory-worker/src/denunciation_factory.rs +++ b/massa-factory-worker/src/denunciation_factory.rs @@ -22,21 +22,15 @@ const DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN: usize = 4096; pub(crate) struct DenunciationFactoryWorker { cfg: FactoryConfig, channels: FactoryChannels, + /// Factory manager command receiver factory_receiver: Receiver<()>, consensus_receiver: Receiver, endorsement_pool_receiver: Receiver, - - // TODO: optim with PreHashSet? - // internal for endorsements (or secure share endorsements) - /// Internal storage for endorsement - - /// store at max 1 endorsement per entry, as soon as we have 2 we produce a Denunciation - endorsements_by_slot_index: HashMap<(Slot, u32), Vec>, - - // internal for block header (or secured header) - /// Internal storage for endorsement - - /// store at max 1 endorsement per entry, as soon as we have 2 we produce a Denunciation - // FIXME: Store per 'Slot' then per 'PubKey' - block_header_by_slot: HashMap>, + /// Internal cache for endorsement denunciation + /// store at most 1 endorsement per entry, as soon as we have 2 we produce a Denunciation + endorsements_by_slot_index: HashMap<(Slot, u32), EndorsementDenunciationStatus>, + /// Internal cache for block header denunciation + block_header_by_slot: HashMap, } impl DenunciationFactoryWorker { @@ -97,30 +91,28 @@ impl DenunciationFactoryWorker { let denunciation_: Option = match self.block_header_by_slot.entry(key) { Entry::Occupied(mut eo) => { - let secured_headers = eo.get_mut(); - // Store at max 2 SecuredHeader's - if secured_headers.len() == 1 { - secured_headers.push(secured_header); - - // TODO / OPTIM?: use [] ? - // safe to unwrap as we just checked the vec len - let header_1 = secured_headers.get(0).unwrap(); - let header_2 = secured_headers.get(1).unwrap(); - let de_ = Denunciation::try_from((header_1, header_2)); - match de_ { - Ok(de) => Some(de), - Err(e) => { - debug!("Denunciation factory cannot create denunciation from block headers: {}", e); - return; + match eo.get_mut() { + BlockHeaderDenunciationStatus::Accumulating(header_1_) => { + let header_1: &SecuredHeader = header_1_; + match Denunciation::try_from((header_1, &secured_header)) { + Ok(de) => { + eo.insert(BlockHeaderDenunciationStatus::DenunciationEmitted); + Some(de) + } + Err(e) => { + debug!("Denunciation factory cannot create denunciation from endorsements: {}", e); + None + } } } - } else { - // Already 2 entries - so a Denunciation has already been created - None + BlockHeaderDenunciationStatus::DenunciationEmitted => { + // Already 2 entries - so a Denunciation has already been created + None + } } } Entry::Vacant(ev) => { - ev.insert(vec![secured_header]); + ev.insert(BlockHeaderDenunciationStatus::Accumulating(secured_header)); None } }; @@ -187,28 +179,30 @@ impl DenunciationFactoryWorker { let denunciation_: Option = match self.endorsements_by_slot_index.entry(key) { Entry::Occupied(mut eo) => { - let secure_share_endorsements = eo.get_mut(); - // Store at max 2 endo - if secure_share_endorsements.len() == 1 { - secure_share_endorsements.push(secure_share_endorsement); - - // TODO / OPTIM?: use [] ? - // safe to unwrap as we just checked the vec len - let header_1 = secure_share_endorsements.get(0).unwrap(); - let header_2 = secure_share_endorsements.get(1).unwrap(); - let de_ = Denunciation::try_from((header_1, header_2)); - if let Err(e) = de_ { - debug!("Denunciation factory cannot create denunciation from block headers: {}", e); - return; + match eo.get_mut() { + EndorsementDenunciationStatus::Accumulating(secure_endo_1_) => { + let secure_endo_1: &SecureShareEndorsement = secure_endo_1_; + match Denunciation::try_from((secure_endo_1, &secure_share_endorsement)) { + Ok(de) => { + eo.insert(EndorsementDenunciationStatus::DenunciationEmitted); + Some(de) + } + Err(e) => { + debug!("Denunciation factory cannot create denunciation from endorsements: {}", e); + None + } + } + } + EndorsementDenunciationStatus::DenunciationEmitted => { + // A Denunciation has already been created, nothing to do here + None } - Some(de_.unwrap()) // Already checked for error - } else { - // Already 2 entries - so a Denunciation has already been created - None } } Entry::Vacant(ev) => { - ev.insert(vec![secure_share_endorsement]); + ev.insert(EndorsementDenunciationStatus::Accumulating( + secure_share_endorsement, + )); None } }; @@ -218,7 +212,6 @@ impl DenunciationFactoryWorker { "Created a new endorsement denunciation : {:?}", denunciation ); - self.channels.pool.add_denunciation(denunciation); } @@ -296,3 +289,15 @@ impl DenunciationFactoryWorker { } } } + +#[allow(clippy::large_enum_variant)] +enum EndorsementDenunciationStatus { + Accumulating(SecureShareEndorsement), + DenunciationEmitted, +} + +#[allow(clippy::large_enum_variant)] +enum BlockHeaderDenunciationStatus { + Accumulating(SecuredHeader), + DenunciationEmitted, +} diff --git a/massa-pool-worker/src/controller_impl.rs b/massa-pool-worker/src/controller_impl.rs index 3de6ee1c7d3..9929b1cc534 100644 --- a/massa-pool-worker/src/controller_impl.rs +++ b/massa-pool-worker/src/controller_impl.rs @@ -19,6 +19,7 @@ use crate::{ }; /// A generic command to send commands to a pool +#[allow(clippy::large_enum_variant)] pub enum Command { /// Add items to the pool AddItems(Storage), From a8dc9abe50328833bfc7c402229766820591f5ba Mon Sep 17 00:00:00 2001 From: sydhds Date: Fri, 31 Mar 2023 13:12:31 +0200 Subject: [PATCH 07/13] Add DenunciationInterest && better filtering inside DenunciationFactory --- massa-consensus-exports/src/channels.rs | 3 +- massa-consensus-worker/src/controller.rs | 3 +- massa-factory-exports/src/config.rs | 3 + .../src/denunciation_factory.rs | 159 ++++++++----- massa-factory-worker/src/run.rs | 5 +- massa-models/src/config/constants.rs | 4 +- massa-models/src/denunciation.rs | 225 +++++++++++++----- massa-node/src/main.rs | 9 +- massa-pool-worker/src/denunciation_pool.rs | 19 -- massa-pool-worker/src/endorsement_pool.rs | 20 +- massa-pool-worker/src/worker.rs | 3 +- 11 files changed, 297 insertions(+), 156 deletions(-) diff --git a/massa-consensus-exports/src/channels.rs b/massa-consensus-exports/src/channels.rs index 596ad9082de..54027dc23e3 100644 --- a/massa-consensus-exports/src/channels.rs +++ b/massa-consensus-exports/src/channels.rs @@ -1,6 +1,7 @@ use massa_execution_exports::ExecutionController; use massa_models::block::{Block, FilledBlock}; use massa_models::block_header::{BlockHeader, SecuredHeader}; +use massa_models::denunciation::DenunciationInterest; use massa_pool_exports::PoolController; use massa_pos_exports::SelectorController; use massa_protocol_exports::ProtocolCommandSender; @@ -27,5 +28,5 @@ pub struct ConsensusChannels { /// Channel use by Websocket (if they are enable) to broadcast a new block integrated pub filled_block_sender: tokio::sync::broadcast::Sender, /// Channel use for Denunciation factory to create denunciations - pub denunciation_factory_sender: crossbeam_channel::Sender, + pub denunciation_factory_sender: crossbeam_channel::Sender, } diff --git a/massa-consensus-worker/src/controller.rs b/massa-consensus-worker/src/controller.rs index db92025fe1c..dc6d0b1165f 100644 --- a/massa-consensus-worker/src/controller.rs +++ b/massa-consensus-worker/src/controller.rs @@ -3,6 +3,7 @@ use massa_consensus_exports::{ bootstrapable_graph::BootstrapableGraph, error::ConsensusError, export_active_block::ExportActiveBlock, ConsensusChannels, ConsensusController, }; +use massa_models::denunciation::DenunciationInterest; use massa_models::{ block::{BlockGraphStatus, FilledBlock}, block_header::BlockHeader, @@ -285,7 +286,7 @@ impl ConsensusController for ConsensusControllerImpl { if let Err(e) = self .channels .denunciation_factory_sender - .send(header.clone()) + .send(DenunciationInterest::try_from(&header).unwrap()) { warn!("Cannot send header to denunciation factory: {}", e); } diff --git a/massa-factory-exports/src/config.rs b/massa-factory-exports/src/config.rs index c3aff957212..d56fbab3da4 100644 --- a/massa-factory-exports/src/config.rs +++ b/massa-factory-exports/src/config.rs @@ -33,4 +33,7 @@ pub struct FactoryConfig { /// denunciation expiration as cycle delta pub denunciation_expire_cycle_delta: u64, + + /// Cycle delta to accept items in denunciation factory + pub denunciation_items_max_cycle_delta: u64, } diff --git a/massa-factory-worker/src/denunciation_factory.rs b/massa-factory-worker/src/denunciation_factory.rs index 0a5c880bae9..11a70359249 100644 --- a/massa-factory-worker/src/denunciation_factory.rs +++ b/massa-factory-worker/src/denunciation_factory.rs @@ -8,7 +8,10 @@ use tracing::{debug, info, warn}; use massa_factory_exports::{FactoryChannels, FactoryConfig}; use massa_models::address::Address; use massa_models::block_header::SecuredHeader; -use massa_models::denunciation::Denunciation; +use massa_models::denunciation::{ + BlockHeaderDenunciationInterest, Denunciation, DenunciationInterest, + EndorsementDenunciationInterest, +}; use massa_models::endorsement::SecureShareEndorsement; use massa_models::slot::Slot; use massa_models::timeslots::get_closest_slot_to_timestamp; @@ -24,8 +27,8 @@ pub(crate) struct DenunciationFactoryWorker { channels: FactoryChannels, /// Factory manager command receiver factory_receiver: Receiver<()>, - consensus_receiver: Receiver, - endorsement_pool_receiver: Receiver, + consensus_receiver: Receiver, + endorsement_pool_receiver: Receiver, /// Internal cache for endorsement denunciation /// store at most 1 endorsement per entry, as soon as we have 2 we produce a Denunciation endorsements_by_slot_index: HashMap<(Slot, u32), EndorsementDenunciationStatus>, @@ -40,8 +43,8 @@ impl DenunciationFactoryWorker { cfg: FactoryConfig, channels: FactoryChannels, factory_receiver: Receiver<()>, - consensus_receiver: Receiver, - endorsement_pool_receiver: Receiver, + consensus_receiver: Receiver, + endorsement_pool_receiver: Receiver, ) -> thread::JoinHandle<()> { thread::Builder::new() .name("denunciation-factory".into()) @@ -61,13 +64,37 @@ impl DenunciationFactoryWorker { } /// Process new secured header (~ block header) - fn process_new_secured_header(&mut self, secured_header: SecuredHeader) { - let key = secured_header.content.slot; + fn process_new_secured_header( + &mut self, + block_header_denunciation_interest: DenunciationInterest, + ) { + let de_i_orig = block_header_denunciation_interest.clone(); + let de_i = match block_header_denunciation_interest { + DenunciationInterest::Endorsement(_) => { + return; + } + DenunciationInterest::BlockHeader(de_i) => de_i, + }; + + let now = MassaTime::now().expect("could not get current time"); + + // get closest slot according to the current absolute time + let slot_now = get_closest_slot_to_timestamp( + self.cfg.thread_count, + self.cfg.t0, + self.cfg.genesis_timestamp, + now, + ); + + let cycle_of_header = de_i.slot.get_cycle(self.cfg.periods_per_cycle); + let cycle_now = slot_now.get_cycle(self.cfg.periods_per_cycle); - if self.block_header_by_slot.len() > DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN { + // Do not fulfill the cache with block header too much in the future + // Note that cache is also purged each time a slot becomes final + if cycle_now - cycle_of_header > self.cfg.denunciation_items_max_cycle_delta { warn!( - "Denunciation factory cannot process - cache full: {}", - self.block_header_by_slot.len() + "Denunciation factory received a denunciation interest way to much in the future: {:?}", + de_i ); return; } @@ -76,10 +103,10 @@ impl DenunciationFactoryWorker { // Note: If the public key of the header creator is not checked to match the PoS, // someone can spam with headers coming from various non-PoS-drawn pubkeys // and cause a problem - let selected_address = self.channels.selector.get_producer(key); + let selected_address = self.channels.selector.get_producer(de_i.slot); match selected_address { Ok(address) => { - if address != Address::from_public_key(&secured_header.content_creator_pub_key) { + if address != Address::from_public_key(&de_i.public_key) { warn!("Denunciation factory received a secured header but address was not selected"); return; } @@ -89,12 +116,12 @@ impl DenunciationFactoryWorker { } } - let denunciation_: Option = match self.block_header_by_slot.entry(key) { + let denunciation_: Option = match self.block_header_by_slot.entry(de_i.slot) { Entry::Occupied(mut eo) => { match eo.get_mut() { - BlockHeaderDenunciationStatus::Accumulating(header_1_) => { - let header_1: &SecuredHeader = header_1_; - match Denunciation::try_from((header_1, &secured_header)) { + BlockHeaderDenunciationStatus::Accumulating(de_i_1_) => { + let de_i_1: &DenunciationInterest = de_i_1_; + match Denunciation::try_from((de_i_1, &de_i_orig.clone())) { Ok(de) => { eo.insert(BlockHeaderDenunciationStatus::DenunciationEmitted); Some(de) @@ -112,7 +139,7 @@ impl DenunciationFactoryWorker { } } Entry::Vacant(ev) => { - ev.insert(BlockHeaderDenunciationStatus::Accumulating(secured_header)); + ev.insert(BlockHeaderDenunciationStatus::Accumulating(de_i_orig)); None } }; @@ -132,35 +159,50 @@ impl DenunciationFactoryWorker { /// Process new secure share endorsement (~ endorsement) fn process_new_secure_share_endorsement( &mut self, - secure_share_endorsement: SecureShareEndorsement, + endorsement_denunciation_interest: DenunciationInterest, ) { - let endo_slot = secure_share_endorsement.content.slot; - let endo_index = secure_share_endorsement.content.index; - let endo_index_usize = endo_index as usize; - let key = (endo_slot, endo_index); - if self.endorsements_by_slot_index.contains_key(&key) { + let de_i_orig = endorsement_denunciation_interest.clone(); + let de_i = match endorsement_denunciation_interest { + DenunciationInterest::Endorsement(de_i) => de_i, + DenunciationInterest::BlockHeader(de_i) => { + return; + } + }; + + let now = MassaTime::now().expect("could not get current time"); + + // get closest slot according to the current absolute time + let slot_now = get_closest_slot_to_timestamp( + self.cfg.thread_count, + self.cfg.t0, + self.cfg.genesis_timestamp, + now, + ); + + let cycle_of_header = de_i.slot.get_cycle(self.cfg.periods_per_cycle); + let cycle_now = slot_now.get_cycle(self.cfg.periods_per_cycle); + + // Do not fulfill the cache with block header too much in the future + // Note that cache is also purged each time a slot becomes final + if cycle_now - cycle_of_header > self.cfg.denunciation_items_max_cycle_delta { warn!( - "Denunciation factory process an endorsement that have already been denounced: {}", - secure_share_endorsement + "Denunciation factory received a denunciation interest way to much in the future: {:?}", + de_i ); return; } // Get selected address from selector and check - let selected = self.channels.selector.get_selection(endo_slot); + let selected = self.channels.selector.get_selection(de_i.slot); match selected { Ok(selection) => { - if let Some(address) = selection.endorsements.get(endo_index_usize) { - if *address - != Address::from_public_key( - &secure_share_endorsement.content_creator_pub_key, - ) - { + if let Some(address) = selection.endorsements.get(de_i.index as usize) { + if *address != Address::from_public_key(&de_i.public_key) { warn!("Denunciation factory received a secure share endorsement but address was not selected"); return; } } else { - warn!("Denunciation factory could not get selected address for endorsements at index: {}", endo_index_usize); + warn!("Denunciation factory could not get selected address for endorsements at index"); return; } } @@ -177,12 +219,15 @@ impl DenunciationFactoryWorker { return; } - let denunciation_: Option = match self.endorsements_by_slot_index.entry(key) { + let denunciation_: Option = match self + .endorsements_by_slot_index + .entry((de_i.slot, de_i.index)) + { Entry::Occupied(mut eo) => { match eo.get_mut() { - EndorsementDenunciationStatus::Accumulating(secure_endo_1_) => { - let secure_endo_1: &SecureShareEndorsement = secure_endo_1_; - match Denunciation::try_from((secure_endo_1, &secure_share_endorsement)) { + EndorsementDenunciationStatus::Accumulating(de_i_1_) => { + let de_i_1: &DenunciationInterest = de_i_1_; + match Denunciation::try_from((de_i_1, &de_i_orig.clone())) { Ok(de) => { eo.insert(EndorsementDenunciationStatus::DenunciationEmitted); Some(de) @@ -200,9 +245,7 @@ impl DenunciationFactoryWorker { } } Entry::Vacant(ev) => { - ev.insert(EndorsementDenunciationStatus::Accumulating( - secure_share_endorsement, - )); + ev.insert(EndorsementDenunciationStatus::Accumulating(de_i_orig)); None } }; @@ -219,20 +262,9 @@ impl DenunciationFactoryWorker { } fn cleanup_cache(&mut self) { - let now = MassaTime::now().expect("could not get current time"); - - // get closest slot according to the current absolute time - let slot_now = get_closest_slot_to_timestamp( - self.cfg.thread_count, - self.cfg.t0, - self.cfg.genesis_timestamp, - now, - ); - self.endorsements_by_slot_index.retain(|(slot, _index), _| { !Denunciation::is_expired( slot, - &slot_now, self.channels.pool.get_final_cs_periods(), self.cfg.periods_per_cycle, self.cfg.denunciation_expire_cycle_delta, @@ -242,7 +274,6 @@ impl DenunciationFactoryWorker { self.block_header_by_slot.retain(|slot, _| { !Denunciation::is_expired( slot, - &slot_now, self.channels.pool.get_final_cs_periods(), self.cfg.periods_per_cycle, self.cfg.denunciation_expire_cycle_delta, @@ -254,11 +285,11 @@ impl DenunciationFactoryWorker { fn run(&mut self) { loop { select! { - recv(self.consensus_receiver) -> secured_header_ => { - match secured_header_ { - Ok(secured_header) => { - info!("Denunciation factory receives a new block header: {}", secured_header); - self.process_new_secured_header(secured_header); + recv(self.consensus_receiver) -> de_i_ => { + match de_i_ { + Ok(de_i) => { + info!("Denunciation factory receives a new block header denunciation interest: {:?}", de_i); + self.process_new_secured_header(de_i); }, Err(e) => { warn!("Denunciation factory cannot receive from consensus receiver: {}", e); @@ -266,11 +297,11 @@ impl DenunciationFactoryWorker { } } }, - recv(self.endorsement_pool_receiver) -> secure_share_endorsement_ => { - match secure_share_endorsement_ { - Ok(secure_share_endorsement) => { - info!("Denunciation factory receives a new endorsement: {}", secure_share_endorsement); - self.process_new_secure_share_endorsement(secure_share_endorsement) + recv(self.endorsement_pool_receiver) -> de_i_ => { + match de_i_ { + Ok(de_i) => { + info!("Denunciation factory receives a new endorsement denunciation interest: {:?}", de_i); + self.process_new_secure_share_endorsement(de_i) } Err(e) => { warn!("Denunciation factory cannot receive from endorsement pool receiver: {}", e); @@ -292,12 +323,12 @@ impl DenunciationFactoryWorker { #[allow(clippy::large_enum_variant)] enum EndorsementDenunciationStatus { - Accumulating(SecureShareEndorsement), + Accumulating(DenunciationInterest), DenunciationEmitted, } #[allow(clippy::large_enum_variant)] enum BlockHeaderDenunciationStatus { - Accumulating(SecuredHeader), + Accumulating(DenunciationInterest), DenunciationEmitted, } diff --git a/massa-factory-worker/src/run.rs b/massa-factory-worker/src/run.rs index 36c7f71098c..5868fa25a7a 100644 --- a/massa-factory-worker/src/run.rs +++ b/massa-factory-worker/src/run.rs @@ -12,6 +12,7 @@ use crate::{ }; use massa_factory_exports::{FactoryChannels, FactoryConfig, FactoryManager}; use massa_models::block_header::SecuredHeader; +use massa_models::denunciation::DenunciationInterest; use massa_models::endorsement::SecureShareEndorsement; use massa_wallet::Wallet; @@ -28,8 +29,8 @@ pub fn start_factory( cfg: FactoryConfig, wallet: Arc>, channels: FactoryChannels, - denunciation_factory_consensus_receiver: Receiver, - denunciation_factory_endorsement_pool_receiver: Receiver, + denunciation_factory_consensus_receiver: Receiver, + denunciation_factory_endorsement_pool_receiver: Receiver, ) -> Box { // create block factory channel let (block_worker_tx, block_worker_rx) = mpsc::channel::<()>(); diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index fbd0ded622f..904d50caa01 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -231,7 +231,9 @@ pub const VERSIONING_THRESHOLD_TRANSITION_ACCEPTED: Amount = Amount::from_mantis // /// denunciation expiration delta (in cycle count) -pub const DENUNCIATION_EXPIRE_CYCLE_DELTA: u64 = 3; +pub const DENUNCIATION_EXPIRE_CYCLE_DELTA: u64 = 1; +/// Cycle delta to accept items in denunciation factory +pub const DENUNCIATION_ITEMS_MAX_CYCLE_DELTA: u64 = 1; // Some checks at compile time that should not be ignored! #[allow(clippy::assertions_on_constants)] diff --git a/massa-models/src/denunciation.rs b/massa-models/src/denunciation.rs index c97b092440a..f18e6c24104 100644 --- a/massa-models/src/denunciation.rs +++ b/massa-models/src/denunciation.rs @@ -59,9 +59,8 @@ impl EndorsementDenunciation { slot: &Slot, index: &u32, content_hash: &Hash, - ) -> Result { + ) -> Hash { let mut hash_data = Vec::new(); - // Public key hash_data.extend(public_key.to_bytes()); // Ser slot & index @@ -69,8 +68,7 @@ impl EndorsementDenunciation { hash_data.extend(&denunciation_data.to_bytes()); // Add content hash hash_data.extend(content_hash.to_bytes()); - - Ok(Hash::compute_from(&hash_data)) + Hash::compute_from(&hash_data) } } @@ -100,26 +98,16 @@ impl BlockHeaderDenunciation { public_key: &PublicKey, slot: &Slot, content_hash: &Hash, - ) -> Result { + ) -> Hash { let mut hash_data = Vec::new(); - // let mut buf = Vec::new(); - // let de_data_serializer = DenunciationDataSerializer::new(); - // Public key hash_data.extend(public_key.to_bytes()); - // Ser slot - // let denunciation_data = DenunciationData::BlockHeader(*slot); - // de_data_serializer.serialize(&denunciation_data, &mut buf)?; let de_data = BlockHeaderDenunciationData::new(*slot); hash_data.extend(de_data.to_bytes()); - // hash_data.extend(&buf); - // buf.clear(); - // Add content hash hash_data.extend(content_hash.to_bytes()); - - Ok(Hash::compute_from(&hash_data)) + Hash::compute_from(&hash_data) } } @@ -155,26 +143,22 @@ impl Denunciation { let content_hash = EndorsementDenunciation::compute_content_hash(&s_endorsement.content)?; - let hash_ = EndorsementDenunciation::compute_hash_for_sig_verif( + let hash = EndorsementDenunciation::compute_hash_for_sig_verif( &endo_de.public_key, &endo_de.slot, &endo_de.index, &content_hash, ); - if let Ok(hash) = hash_ { - Ok(endo_de.slot == s_endorsement.content.slot - && endo_de.index == s_endorsement.content.index - && endo_de.public_key == s_endorsement.content_creator_pub_key - && endo_de.hash_1 != content_hash - && endo_de.hash_2 != content_hash - && endo_de - .public_key - .verify_signature(&hash, &s_endorsement.signature) - .is_ok()) - } else { - Ok(false) - } + Ok(endo_de.slot == s_endorsement.content.slot + && endo_de.index == s_endorsement.content.index + && endo_de.public_key == s_endorsement.content_creator_pub_key + && endo_de.hash_1 != content_hash + && endo_de.hash_2 != content_hash + && endo_de + .public_key + .verify_signature(&hash, &s_endorsement.signature) + .is_ok()) } } } @@ -191,24 +175,20 @@ impl Denunciation { let content_hash = BlockHeaderDenunciation::compute_content_hash(&s_block_header.content)?; - let hash_ = BlockHeaderDenunciation::compute_hash_for_sig_verif( + let hash = BlockHeaderDenunciation::compute_hash_for_sig_verif( &endo_bh.public_key, &endo_bh.slot, &content_hash, ); - if let Ok(hash) = hash_ { - Ok(endo_bh.slot == s_block_header.content.slot - && endo_bh.public_key == s_block_header.content_creator_pub_key - && endo_bh.hash_1 != content_hash - && endo_bh.hash_2 != content_hash - && endo_bh - .public_key - .verify_signature(&hash, &s_block_header.signature) - .is_ok()) - } else { - Ok(false) - } + Ok(endo_bh.slot == s_block_header.content.slot + && endo_bh.public_key == s_block_header.content_creator_pub_key + && endo_bh.hash_1 != content_hash + && endo_bh.hash_2 != content_hash + && endo_bh + .public_key + .verify_signature(&hash, &s_block_header.signature) + .is_ok()) } } } @@ -223,13 +203,13 @@ impl Denunciation { &de.slot, &de.index, &de.hash_1, - )?; + ); let hash_2 = EndorsementDenunciation::compute_hash_for_sig_verif( &de.public_key, &de.slot, &de.index, &de.hash_2, - )?; + ); ( de.signature_1, @@ -244,12 +224,12 @@ impl Denunciation { &de.public_key, &de.slot, &de.hash_1, - )?; + ); let hash_2 = BlockHeaderDenunciation::compute_hash_for_sig_verif( &de.public_key, &de.slot, &de.hash_2, - )?; + ); ( de.signature_1, @@ -279,22 +259,21 @@ impl Denunciation { /// Can be used to check if block header | endorsement is not too old (at reception or too cleanup cache) pub fn is_expired( slot: &Slot, - slot_at_now: &Slot, last_cs_final_periods: &[u64], periods_per_cycle: u64, denunciation_expire_cycle_delta: u64, ) -> bool { - // Slot is final -> cannot be Denounced anymore, it's too late! + // If the Slot is final, a Denunciation can still be made for 1 cycle if slot.period <= last_cs_final_periods[slot.thread as usize] { - return true; - } + let cycle_of_slot = slot.get_cycle(periods_per_cycle); - // As we need to ensure that the Denounced has some 'Deferred credits' - // we will reject Denunciation older than 3 cycle compared to the current slot - let cycle = slot.get_cycle(periods_per_cycle); - let next_cycle = slot_at_now.get_cycle(periods_per_cycle); + let slot_final = Slot::new(last_cs_final_periods[slot.thread as usize], slot.thread); + let cycle_of_final = slot_final.get_cycle(periods_per_cycle); - (next_cycle - cycle) > denunciation_expire_cycle_delta + (cycle_of_final - cycle_of_slot) > denunciation_expire_cycle_delta + } else { + false + } } } @@ -326,7 +305,7 @@ impl TryFrom<(&SecureShareEndorsement, &SecureShareEndorsement)> for Denunciatio &s_e1.content.slot, &s_e1.content.index, &s_e1_hash_content, - )?; + ); // Check sig of s_e2 but with s_e1.public_key, s_e1.slot, s_e1.index let s_e2_hash_content = EndorsementDenunciation::compute_content_hash(&s_e2.content)?; let s_e2_hash = EndorsementDenunciation::compute_hash_for_sig_verif( @@ -334,7 +313,7 @@ impl TryFrom<(&SecureShareEndorsement, &SecureShareEndorsement)> for Denunciatio &s_e1.content.slot, &s_e1.content.index, &s_e2_hash_content, - )?; + ); s_e1.content_creator_pub_key .verify_signature(&s_e1_hash, &s_e1.signature)?; @@ -373,13 +352,13 @@ impl TryFrom<(&SecuredHeader, &SecuredHeader)> for Denunciation { &s_bh1.content_creator_pub_key, &s_bh1.content.slot, &s_bh1_hash_content, - )?; + ); let s_bh2_hash_content = BlockHeaderDenunciation::compute_content_hash(&s_bh2.content)?; let s_bh2_hash = BlockHeaderDenunciation::compute_hash_for_sig_verif( &s_bh1.content_creator_pub_key, &s_bh1.content.slot, &s_bh2_hash_content, - )?; + ); s_bh1 .content_creator_pub_key @@ -841,6 +820,111 @@ impl From<&Denunciation> for DenunciationId { // End Denunciation Id +// Denunciation interest + +/// DenunciationInterest variant for endorsement +#[derive(Debug, Clone)] +pub struct EndorsementDenunciationInterest { + pub public_key: PublicKey, + pub slot: Slot, + pub index: u32, + hash: Hash, + signature: Signature, +} + +/// DenunciationInterest variant for block header +#[derive(Debug, Clone)] +pub struct BlockHeaderDenunciationInterest { + pub public_key: PublicKey, + pub slot: Slot, + hash: Hash, + signature: Signature, +} + +/// Lightweight data for Denunciation creation +/// (avoid storing heavyweight secured header or secure share endorsement) +#[derive(Debug, Clone)] +pub enum DenunciationInterest { + Endorsement(EndorsementDenunciationInterest), + BlockHeader(BlockHeaderDenunciationInterest), +} + +impl TryFrom<&SecureShareEndorsement> for DenunciationInterest { + type Error = DenunciationError; + + fn try_from(value: &SecureShareEndorsement) -> Result { + let hash = EndorsementDenunciation::compute_content_hash(&value.content)?; + + Ok(DenunciationInterest::Endorsement( + EndorsementDenunciationInterest { + public_key: value.content_creator_pub_key, + slot: value.content.slot, + index: value.content.index, + hash, + signature: value.signature, + }, + )) + } +} + +impl TryFrom<&SecuredHeader> for DenunciationInterest { + type Error = DenunciationError; + + fn try_from(value: &SecuredHeader) -> Result { + let hash = BlockHeaderDenunciation::compute_content_hash(&value.content)?; + Ok(DenunciationInterest::BlockHeader( + BlockHeaderDenunciationInterest { + public_key: value.content_creator_pub_key, + slot: value.content.slot, + hash, + signature: value.signature, + }, + )) + } +} + +/// Create a new Denunciation from 2 SecureHeader +impl TryFrom<(&DenunciationInterest, &DenunciationInterest)> for Denunciation { + type Error = DenunciationError; + + fn try_from( + (de_i_1, de_i_2): (&DenunciationInterest, &DenunciationInterest), + ) -> Result { + // TODO: add checks before creating + match (de_i_1, de_i_2) { + ( + DenunciationInterest::BlockHeader(de_i_blkh_1), + DenunciationInterest::BlockHeader(de_i_blkh_2), + ) => Ok(Denunciation::BlockHeader(BlockHeaderDenunciation { + public_key: de_i_blkh_1.public_key, + slot: de_i_blkh_1.slot, + signature_1: de_i_blkh_1.signature, + signature_2: de_i_blkh_2.signature, + hash_1: de_i_blkh_1.hash, + hash_2: de_i_blkh_2.hash, + })), + ( + DenunciationInterest::Endorsement(de_i_endo_1), + DenunciationInterest::Endorsement(de_i_endo_2), + ) => Ok(Denunciation::Endorsement(EndorsementDenunciation { + public_key: de_i_endo_1.public_key, + slot: de_i_endo_1.slot, + index: de_i_endo_1.index, + signature_1: de_i_endo_1.signature, + signature_2: de_i_endo_2.signature, + hash_1: de_i_endo_1.hash, + hash_2: de_i_endo_2.hash, + })), + _ => { + // Different enum variant - this is invalid + Err(DenunciationError::InvalidInput) + } + } + } +} + +// End Denunciation interest + #[cfg(test)] mod tests { use super::*; @@ -1202,4 +1286,25 @@ mod tests { assert_eq!(rem.is_empty(), true); assert_eq!(denunciation, de_der_res); } + + #[test] + fn test_denunciation_interest() { + let (_, _, s_block_header_1, s_block_header_2, _) = gen_block_headers_for_denunciation(); + let denunciation: Denunciation = (&s_block_header_1, &s_block_header_2).try_into().unwrap(); + + let de_i_1 = DenunciationInterest::try_from(&s_block_header_1).unwrap(); + let de_i_2 = DenunciationInterest::try_from(&s_block_header_2).unwrap(); + let denunciation_2: Denunciation = (&de_i_1, &de_i_2).try_into().unwrap(); + + assert_eq!(denunciation, denunciation_2); + + let (_, _, s_endorsement_1, s_endorsement_2, _) = gen_endorsements_for_denunciation(); + let denunciation_3 = Denunciation::try_from((&s_endorsement_1, &s_endorsement_2)).unwrap(); + + let de_i_3 = DenunciationInterest::try_from(&s_endorsement_1).unwrap(); + let de_i_4 = DenunciationInterest::try_from(&s_endorsement_2).unwrap(); + let denunciation_4: Denunciation = (&de_i_3, &de_i_4).try_into().unwrap(); + + assert_eq!(denunciation_3, denunciation_4); + } } diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index d859a83f7d2..a1e344994da 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -46,7 +46,11 @@ use massa_models::config::constants::{ POS_SAVED_CYCLES, PROTOCOL_CONTROLLER_CHANNEL_SIZE, PROTOCOL_EVENT_CHANNEL_SIZE, ROLL_PRICE, T0, THREAD_COUNT, VERSION, }; -use massa_models::config::{CONSENSUS_BOOTSTRAP_PART_SIZE, DENUNCIATION_EXPIRE_CYCLE_DELTA}; +use massa_models::config::{ + CONSENSUS_BOOTSTRAP_PART_SIZE, DENUNCIATION_EXPIRE_CYCLE_DELTA, + DENUNCIATION_ITEMS_MAX_CYCLE_DELTA, +}; +use massa_models::denunciation::DenunciationInterest; use massa_models::endorsement::SecureShareEndorsement; use massa_network_exports::{Establisher, NetworkConfig, NetworkManager}; use massa_network_worker::start_network_controller; @@ -380,7 +384,7 @@ async fn launch( operation_sender: broadcast::channel(pool_config.broadcast_operations_capacity).0, }; let (denunciation_factory_tx, denunciation_factory_rx) = - crossbeam_channel::unbounded::(); + crossbeam_channel::unbounded::(); let (pool_manager, pool_controller) = start_pool_controller( pool_config, @@ -510,6 +514,7 @@ async fn launch( max_operations_per_block: MAX_OPERATIONS_PER_BLOCK, periods_per_cycle: PERIODS_PER_CYCLE, denunciation_expire_cycle_delta: DENUNCIATION_EXPIRE_CYCLE_DELTA, + denunciation_items_max_cycle_delta: DENUNCIATION_ITEMS_MAX_CYCLE_DELTA, }; let factory_channels = FactoryChannels { selector: selector_controller.clone(), diff --git a/massa-pool-worker/src/denunciation_pool.rs b/massa-pool-worker/src/denunciation_pool.rs index 7fee53bd212..dc76ef8c9e4 100644 --- a/massa-pool-worker/src/denunciation_pool.rs +++ b/massa-pool-worker/src/denunciation_pool.rs @@ -40,17 +40,8 @@ impl DenunciationPool { /// Add a list of denunciation to the pool pub(crate) fn add_denunciation(&mut self, denunciation: Denunciation) { - let now = MassaTime::now().expect("could not get current time"); - // get closest slot according to the current absolute time - let slot_now = get_closest_slot_to_timestamp( - self.config.thread_count, - self.config.t0, - self.config.genesis_timestamp, - now, - ); if !Denunciation::is_expired( denunciation.get_slot(), - &slot_now, &self.last_cs_final_periods, self.config.periods_per_cycle, self.config.denunciation_expire_cycle_delta, @@ -75,20 +66,10 @@ impl DenunciationPool { // update internal final CS period counter self.last_cs_final_periods = final_cs_periods.to_vec(); - let now = MassaTime::now().expect("could not get current time"); - // get closest slot according to the current absolute time - let slot_now = get_closest_slot_to_timestamp( - self.config.thread_count, - self.config.t0, - self.config.genesis_timestamp, - now, - ); - // remove all denunciations that are expired self.denunciations_cache.drain_filter(|_de_id, de| { Denunciation::is_expired( de.get_slot(), - &slot_now, &self.last_cs_final_periods, self.config.periods_per_cycle, self.config.denunciation_expire_cycle_delta, diff --git a/massa-pool-worker/src/endorsement_pool.rs b/massa-pool-worker/src/endorsement_pool.rs index 9db24844f8f..13c0910d6c2 100644 --- a/massa-pool-worker/src/endorsement_pool.rs +++ b/massa-pool-worker/src/endorsement_pool.rs @@ -1,6 +1,7 @@ //! Copyright (c) 2022 MASSA LABS use crossbeam_channel::Sender; +use massa_models::denunciation::{DenunciationError, DenunciationInterest}; use massa_models::endorsement::SecureShareEndorsement; use massa_models::{ block_id::BlockId, @@ -31,14 +32,14 @@ pub struct EndorsementPool { last_cs_final_periods: Vec, /// Queue to Denunciation factory - denunciation_factory_tx: Sender, + denunciation_factory_tx: Sender, } impl EndorsementPool { pub fn init( config: PoolConfig, storage: &Storage, - denunciation_factory_tx: Sender, + denunciation_factory_tx: Sender, ) -> Self { EndorsementPool { last_cs_final_periods: vec![0u64; config.thread_count as usize], @@ -129,9 +130,18 @@ impl EndorsementPool { } // And send endorsements to Denunciation Factory - // let de_interest = DenunciationInterest::WrappedEndorsement(endo.clone()); - if let Err(e) = self.denunciation_factory_tx.send(endo.clone()) { - warn!("Cannot send endorsement to Denunciation factory: {}", e); + match DenunciationInterest::try_from(endo) { + Ok(de_i) => { + if let Err(e) = self.denunciation_factory_tx.send(de_i) { + warn!("Cannot send endorsement to Denunciation factory: {}", e); + } + } + Err(e) => { + warn!( + "Cannot create denunciation interest from endorsement: {}", + e + ); + } } } } diff --git a/massa-pool-worker/src/worker.rs b/massa-pool-worker/src/worker.rs index 856a17506e1..5d6c2e92204 100644 --- a/massa-pool-worker/src/worker.rs +++ b/massa-pool-worker/src/worker.rs @@ -8,6 +8,7 @@ use crate::operation_pool::OperationPool; use crate::{controller_impl::PoolControllerImpl, endorsement_pool::EndorsementPool}; use crossbeam_channel::Sender; use massa_execution_exports::ExecutionController; +use massa_models::denunciation::DenunciationInterest; use massa_models::endorsement::SecureShareEndorsement; use massa_pool_exports::PoolConfig; use massa_pool_exports::{PoolChannels, PoolController, PoolManager}; @@ -172,7 +173,7 @@ pub fn start_pool_controller( storage: &Storage, execution_controller: Box, channels: PoolChannels, - denunciation_factory_tx: Sender, + denunciation_factory_tx: Sender, ) -> (Box, Box) { let (operations_input_sender, operations_input_receiver) = sync_channel(config.channels_size); let (endorsements_input_sender, endorsements_input_receiver) = From e91eb7bea136d46cb06b156fec7634f5544551b7 Mon Sep 17 00:00:00 2001 From: sydhds Date: Fri, 31 Mar 2023 14:37:13 +0200 Subject: [PATCH 08/13] Code cleanup (removed unused imports) --- Cargo.lock | 1 - massa-consensus-exports/src/channels.rs | 2 +- .../src/denunciation_factory.rs | 21 ++----------------- massa-factory-worker/src/run.rs | 2 -- massa-models/src/denunciation.rs | 3 +++ massa-node/src/main.rs | 1 - massa-pool-worker/Cargo.toml | 1 - massa-pool-worker/src/denunciation_pool.rs | 2 -- massa-pool-worker/src/endorsement_pool.rs | 3 +-- massa-pool-worker/src/worker.rs | 1 - 10 files changed, 7 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6be01072e85..3864af05c07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2828,7 +2828,6 @@ dependencies = [ "massa_pool_exports", "massa_signature", "massa_storage", - "massa_time", "num", "parking_lot", "tokio", diff --git a/massa-consensus-exports/src/channels.rs b/massa-consensus-exports/src/channels.rs index 54027dc23e3..b07cfc72859 100644 --- a/massa-consensus-exports/src/channels.rs +++ b/massa-consensus-exports/src/channels.rs @@ -1,6 +1,6 @@ use massa_execution_exports::ExecutionController; use massa_models::block::{Block, FilledBlock}; -use massa_models::block_header::{BlockHeader, SecuredHeader}; +use massa_models::block_header::BlockHeader; use massa_models::denunciation::DenunciationInterest; use massa_pool_exports::PoolController; use massa_pos_exports::SelectorController; diff --git a/massa-factory-worker/src/denunciation_factory.rs b/massa-factory-worker/src/denunciation_factory.rs index 11a70359249..752192b2dc5 100644 --- a/massa-factory-worker/src/denunciation_factory.rs +++ b/massa-factory-worker/src/denunciation_factory.rs @@ -7,20 +7,11 @@ use tracing::{debug, info, warn}; use massa_factory_exports::{FactoryChannels, FactoryConfig}; use massa_models::address::Address; -use massa_models::block_header::SecuredHeader; -use massa_models::denunciation::{ - BlockHeaderDenunciationInterest, Denunciation, DenunciationInterest, - EndorsementDenunciationInterest, -}; -use massa_models::endorsement::SecureShareEndorsement; +use massa_models::denunciation::{Denunciation, DenunciationInterest}; use massa_models::slot::Slot; use massa_models::timeslots::get_closest_slot_to_timestamp; use massa_time::MassaTime; -// TODO: rework these values -const DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN: usize = 4096; -const DENUNCIATION_FACTORY_BLOCK_HEADER_CACHE_MAX_LEN: usize = 4096; - /// Structure gathering all elements needed by the factory thread pub(crate) struct DenunciationFactoryWorker { cfg: FactoryConfig, @@ -164,7 +155,7 @@ impl DenunciationFactoryWorker { let de_i_orig = endorsement_denunciation_interest.clone(); let de_i = match endorsement_denunciation_interest { DenunciationInterest::Endorsement(de_i) => de_i, - DenunciationInterest::BlockHeader(de_i) => { + DenunciationInterest::BlockHeader(_) => { return; } }; @@ -211,14 +202,6 @@ impl DenunciationFactoryWorker { } } - if self.endorsements_by_slot_index.len() > DENUNCIATION_FACTORY_ENDORSEMENT_CACHE_MAX_LEN { - warn!( - "Denunciation factory cannot process - cache full: {}", - self.endorsements_by_slot_index.len() - ); - return; - } - let denunciation_: Option = match self .endorsements_by_slot_index .entry((de_i.slot, de_i.index)) diff --git a/massa-factory-worker/src/run.rs b/massa-factory-worker/src/run.rs index 5868fa25a7a..b72f8aa2ce0 100644 --- a/massa-factory-worker/src/run.rs +++ b/massa-factory-worker/src/run.rs @@ -11,9 +11,7 @@ use crate::{ manager::FactoryManagerImpl, }; use massa_factory_exports::{FactoryChannels, FactoryConfig, FactoryManager}; -use massa_models::block_header::SecuredHeader; use massa_models::denunciation::DenunciationInterest; -use massa_models::endorsement::SecureShareEndorsement; use massa_wallet::Wallet; /// Start factory diff --git a/massa-models/src/denunciation.rs b/massa-models/src/denunciation.rs index f18e6c24104..4ad19b17df4 100644 --- a/massa-models/src/denunciation.rs +++ b/massa-models/src/denunciation.rs @@ -823,6 +823,7 @@ impl From<&Denunciation> for DenunciationId { // Denunciation interest /// DenunciationInterest variant for endorsement +#[allow(missing_docs)] #[derive(Debug, Clone)] pub struct EndorsementDenunciationInterest { pub public_key: PublicKey, @@ -833,6 +834,7 @@ pub struct EndorsementDenunciationInterest { } /// DenunciationInterest variant for block header +#[allow(missing_docs)] #[derive(Debug, Clone)] pub struct BlockHeaderDenunciationInterest { pub public_key: PublicKey, @@ -843,6 +845,7 @@ pub struct BlockHeaderDenunciationInterest { /// Lightweight data for Denunciation creation /// (avoid storing heavyweight secured header or secure share endorsement) +#[allow(missing_docs)] #[derive(Debug, Clone)] pub enum DenunciationInterest { Endorsement(EndorsementDenunciationInterest), diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index a1e344994da..786bad84076 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -51,7 +51,6 @@ use massa_models::config::{ DENUNCIATION_ITEMS_MAX_CYCLE_DELTA, }; use massa_models::denunciation::DenunciationInterest; -use massa_models::endorsement::SecureShareEndorsement; use massa_network_exports::{Establisher, NetworkConfig, NetworkManager}; use massa_network_worker::start_network_controller; use massa_pool_exports::{PoolChannels, PoolConfig, PoolManager}; diff --git a/massa-pool-worker/Cargo.toml b/massa-pool-worker/Cargo.toml index cc4df605e86..5aae0435bd3 100644 --- a/massa-pool-worker/Cargo.toml +++ b/massa-pool-worker/Cargo.toml @@ -14,7 +14,6 @@ massa_models = { path = "../massa-models" } massa_storage = { path = "../massa-storage" } massa_pool_exports = { path = "../massa-pool-exports" } massa_execution_exports = { path = "../massa-execution-exports" } -massa_time = { path = "../massa-time" } [dev-dependencies] tokio = { version = "1.23", features = ["sync"] } diff --git a/massa-pool-worker/src/denunciation_pool.rs b/massa-pool-worker/src/denunciation_pool.rs index dc76ef8c9e4..3727d448c59 100644 --- a/massa-pool-worker/src/denunciation_pool.rs +++ b/massa-pool-worker/src/denunciation_pool.rs @@ -1,9 +1,7 @@ use massa_models::denunciation::{Denunciation, DenunciationId}; use massa_models::prehash::PreHashMap; -use massa_models::timeslots::get_closest_slot_to_timestamp; use massa_pool_exports::PoolConfig; -use massa_time::MassaTime; pub struct DenunciationPool { /// configuration diff --git a/massa-pool-worker/src/endorsement_pool.rs b/massa-pool-worker/src/endorsement_pool.rs index 13c0910d6c2..2b4e11c942f 100644 --- a/massa-pool-worker/src/endorsement_pool.rs +++ b/massa-pool-worker/src/endorsement_pool.rs @@ -1,8 +1,7 @@ //! Copyright (c) 2022 MASSA LABS use crossbeam_channel::Sender; -use massa_models::denunciation::{DenunciationError, DenunciationInterest}; -use massa_models::endorsement::SecureShareEndorsement; +use massa_models::denunciation::DenunciationInterest; use massa_models::{ block_id::BlockId, endorsement::EndorsementId, diff --git a/massa-pool-worker/src/worker.rs b/massa-pool-worker/src/worker.rs index 5d6c2e92204..38ccdb7e188 100644 --- a/massa-pool-worker/src/worker.rs +++ b/massa-pool-worker/src/worker.rs @@ -9,7 +9,6 @@ use crate::{controller_impl::PoolControllerImpl, endorsement_pool::EndorsementPo use crossbeam_channel::Sender; use massa_execution_exports::ExecutionController; use massa_models::denunciation::DenunciationInterest; -use massa_models::endorsement::SecureShareEndorsement; use massa_pool_exports::PoolConfig; use massa_pool_exports::{PoolChannels, PoolController, PoolManager}; use massa_storage::Storage; From a83806af91cf6130522267e0f96cc924f124c718 Mon Sep 17 00:00:00 2001 From: sydhds Date: Fri, 31 Mar 2023 14:38:53 +0200 Subject: [PATCH 09/13] Code cleanup (clippy warnings) --- massa-factory-worker/src/denunciation_factory.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/massa-factory-worker/src/denunciation_factory.rs b/massa-factory-worker/src/denunciation_factory.rs index 752192b2dc5..8a551900ccd 100644 --- a/massa-factory-worker/src/denunciation_factory.rs +++ b/massa-factory-worker/src/denunciation_factory.rs @@ -112,7 +112,7 @@ impl DenunciationFactoryWorker { match eo.get_mut() { BlockHeaderDenunciationStatus::Accumulating(de_i_1_) => { let de_i_1: &DenunciationInterest = de_i_1_; - match Denunciation::try_from((de_i_1, &de_i_orig.clone())) { + match Denunciation::try_from((de_i_1, &de_i_orig)) { Ok(de) => { eo.insert(BlockHeaderDenunciationStatus::DenunciationEmitted); Some(de) @@ -210,7 +210,7 @@ impl DenunciationFactoryWorker { match eo.get_mut() { EndorsementDenunciationStatus::Accumulating(de_i_1_) => { let de_i_1: &DenunciationInterest = de_i_1_; - match Denunciation::try_from((de_i_1, &de_i_orig.clone())) { + match Denunciation::try_from((de_i_1, &de_i_orig)) { Ok(de) => { eo.insert(EndorsementDenunciationStatus::DenunciationEmitted); Some(de) From 10c5535b5fbcae7df01f9ea1087aeac56514825d Mon Sep 17 00:00:00 2001 From: sydhds Date: Fri, 31 Mar 2023 17:08:49 +0200 Subject: [PATCH 10/13] Rework Denunciation::is_expired --- massa-factory-exports/src/config.rs | 4 +- .../src/test_exports/config.rs | 3 +- .../src/denunciation_factory.rs | 6 +-- massa-factory-worker/src/tests/scenarios.rs | 6 +-- massa-factory-worker/src/tests/tools.rs | 8 ++-- massa-models/src/config/constants.rs | 2 +- massa-models/src/denunciation.rs | 16 ++------ massa-node/src/main.rs | 7 ++-- massa-pool-exports/src/config.rs | 4 +- massa-pool-exports/src/test_exports/config.rs | 8 +--- massa-pool-worker/src/denunciation_pool.rs | 6 +-- massa-storage/src/denunciation_indexes.rs | 38 ------------------- 12 files changed, 27 insertions(+), 81 deletions(-) delete mode 100644 massa-storage/src/denunciation_indexes.rs diff --git a/massa-factory-exports/src/config.rs b/massa-factory-exports/src/config.rs index d56fbab3da4..5a58c2508ed 100644 --- a/massa-factory-exports/src/config.rs +++ b/massa-factory-exports/src/config.rs @@ -31,8 +31,8 @@ pub struct FactoryConfig { /// cycle duration in periods pub periods_per_cycle: u64, - /// denunciation expiration as cycle delta - pub denunciation_expire_cycle_delta: u64, + /// denunciation expiration as periods + pub denunciation_expire_periods: u64, /// Cycle delta to accept items in denunciation factory pub denunciation_items_max_cycle_delta: u64, diff --git a/massa-factory-exports/src/test_exports/config.rs b/massa-factory-exports/src/test_exports/config.rs index 1ad558f10e8..af60e84c5b0 100644 --- a/massa-factory-exports/src/test_exports/config.rs +++ b/massa-factory-exports/src/test_exports/config.rs @@ -15,7 +15,8 @@ impl Default for FactoryConfig { max_block_gas: MAX_GAS_PER_BLOCK, max_operations_per_block: MAX_OPERATIONS_PER_BLOCK, periods_per_cycle: PERIODS_PER_CYCLE, - denunciation_expire_cycle_delta: DENUNCIATION_EXPIRE_CYCLE_DELTA, + denunciation_expire_periods: DENUNCIATION_EXPIRE_PERIODS, + denunciation_items_max_cycle_delta: DENUNCIATION_ITEMS_MAX_CYCLE_DELTA, } } } diff --git a/massa-factory-worker/src/denunciation_factory.rs b/massa-factory-worker/src/denunciation_factory.rs index 8a551900ccd..51f36b76ac6 100644 --- a/massa-factory-worker/src/denunciation_factory.rs +++ b/massa-factory-worker/src/denunciation_factory.rs @@ -249,8 +249,7 @@ impl DenunciationFactoryWorker { !Denunciation::is_expired( slot, self.channels.pool.get_final_cs_periods(), - self.cfg.periods_per_cycle, - self.cfg.denunciation_expire_cycle_delta, + self.cfg.denunciation_expire_periods, ) }); @@ -258,8 +257,7 @@ impl DenunciationFactoryWorker { !Denunciation::is_expired( slot, self.channels.pool.get_final_cs_periods(), - self.cfg.periods_per_cycle, - self.cfg.denunciation_expire_cycle_delta, + self.cfg.denunciation_expire_periods, ) }); } diff --git a/massa-factory-worker/src/tests/scenarios.rs b/massa-factory-worker/src/tests/scenarios.rs index 2e11f502fff..59ca823a8ef 100644 --- a/massa-factory-worker/src/tests/scenarios.rs +++ b/massa-factory-worker/src/tests/scenarios.rs @@ -3,7 +3,7 @@ use massa_hash::Hash; use massa_models::block_header::{BlockHeader, BlockHeaderSerializer, SecuredHeader}; use massa_models::block_id::BlockId; use massa_models::config::{T0, THREAD_COUNT}; -use massa_models::denunciation::{Denunciation, DenunciationId}; +use massa_models::denunciation::{Denunciation, DenunciationId, DenunciationInterest}; use massa_models::endorsement::{Endorsement, EndorsementSerializerLW}; use massa_models::slot::Slot; use massa_models::timeslots::get_closest_slot_to_timestamp; @@ -137,11 +137,11 @@ fn test_denunciation_factory_block_header_denunciation() { test_factory .denunciation_factory_sender - .send(secured_header_1.clone()) + .send(DenunciationInterest::try_from(&secured_header_1.clone()).unwrap()) .unwrap(); test_factory .denunciation_factory_sender - .send(secured_header_2.clone()) + .send(DenunciationInterest::try_from(&secured_header_2.clone()).unwrap()) .unwrap(); // Wait for denunciation factory to create the Denunciation diff --git a/massa-factory-worker/src/tests/tools.rs b/massa-factory-worker/src/tests/tools.rs index 9234d286c1c..e0f9f26d007 100644 --- a/massa-factory-worker/src/tests/tools.rs +++ b/massa-factory-worker/src/tests/tools.rs @@ -12,7 +12,7 @@ use std::{ use massa_factory_exports::{ test_exports::create_empty_block, FactoryChannels, FactoryConfig, FactoryManager, }; -use massa_models::block_header::SecuredHeader; +use massa_models::denunciation::DenunciationInterest; use massa_models::{ address::Address, block_id::BlockId, config::ENDORSEMENT_COUNT, endorsement::SecureShareEndorsement, operation::SecureShareOperation, prehash::PreHashMap, @@ -47,8 +47,8 @@ pub struct TestFactory { genesis_blocks: Vec<(BlockId, u64)>, pub(crate) storage: Storage, keypair: KeyPair, - pub(crate) denunciation_factory_sender: Sender, - pub(crate) denunciation_factory_tx: Sender, + pub(crate) denunciation_factory_sender: Sender, + pub(crate) denunciation_factory_tx: Sender, } impl TestFactory { @@ -64,7 +64,7 @@ impl TestFactory { MockConsensusController::new_with_receiver(); let (pool_controller, pool_receiver) = MockPoolController::new_with_receiver(); let (denunciation_factory_tx, denunciation_factory_rx) = - crossbeam_channel::unbounded::(); + crossbeam_channel::unbounded::(); let (denunciation_factory_sender, denunciation_factory_receiver) = crossbeam_channel::bounded(massa_models::config::CHANNEL_SIZE); let mut storage = Storage::create_root(); diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 904d50caa01..ce35025d109 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -231,7 +231,7 @@ pub const VERSIONING_THRESHOLD_TRANSITION_ACCEPTED: Amount = Amount::from_mantis // /// denunciation expiration delta (in cycle count) -pub const DENUNCIATION_EXPIRE_CYCLE_DELTA: u64 = 1; +pub const DENUNCIATION_EXPIRE_PERIODS: u64 = PERIODS_PER_CYCLE; /// Cycle delta to accept items in denunciation factory pub const DENUNCIATION_ITEMS_MAX_CYCLE_DELTA: u64 = 1; diff --git a/massa-models/src/denunciation.rs b/massa-models/src/denunciation.rs index 4ad19b17df4..645db7104c9 100644 --- a/massa-models/src/denunciation.rs +++ b/massa-models/src/denunciation.rs @@ -260,20 +260,11 @@ impl Denunciation { pub fn is_expired( slot: &Slot, last_cs_final_periods: &[u64], - periods_per_cycle: u64, - denunciation_expire_cycle_delta: u64, + denunciation_expire_periods: u64, ) -> bool { // If the Slot is final, a Denunciation can still be made for 1 cycle - if slot.period <= last_cs_final_periods[slot.thread as usize] { - let cycle_of_slot = slot.get_cycle(periods_per_cycle); - - let slot_final = Slot::new(last_cs_final_periods[slot.thread as usize], slot.thread); - let cycle_of_final = slot_final.get_cycle(periods_per_cycle); - - (cycle_of_final - cycle_of_slot) > denunciation_expire_cycle_delta - } else { - false - } + last_cs_final_periods[slot.thread as usize].checked_sub(slot.period) + > Some(denunciation_expire_periods) } } @@ -875,6 +866,7 @@ impl TryFrom<&SecuredHeader> for DenunciationInterest { fn try_from(value: &SecuredHeader) -> Result { let hash = BlockHeaderDenunciation::compute_content_hash(&value.content)?; + Ok(DenunciationInterest::BlockHeader( BlockHeaderDenunciationInterest { public_key: value.content_creator_pub_key, diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 786bad84076..f4f3b20a52c 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -47,8 +47,7 @@ use massa_models::config::constants::{ T0, THREAD_COUNT, VERSION, }; use massa_models::config::{ - CONSENSUS_BOOTSTRAP_PART_SIZE, DENUNCIATION_EXPIRE_CYCLE_DELTA, - DENUNCIATION_ITEMS_MAX_CYCLE_DELTA, + CONSENSUS_BOOTSTRAP_PART_SIZE, DENUNCIATION_EXPIRE_PERIODS, DENUNCIATION_ITEMS_MAX_CYCLE_DELTA, }; use massa_models::denunciation::DenunciationInterest; use massa_network_exports::{Establisher, NetworkConfig, NetworkManager}; @@ -376,7 +375,7 @@ async fn launch( genesis_timestamp: *GENESIS_TIMESTAMP, t0: T0, periods_per_cycle: PERIODS_PER_CYCLE, - denunciation_expire_cycle_delta: DENUNCIATION_EXPIRE_CYCLE_DELTA, + denunciation_expire_periods: DENUNCIATION_EXPIRE_PERIODS, }; let pool_channels = PoolChannels { @@ -512,7 +511,7 @@ async fn launch( max_block_gas: MAX_GAS_PER_BLOCK, max_operations_per_block: MAX_OPERATIONS_PER_BLOCK, periods_per_cycle: PERIODS_PER_CYCLE, - denunciation_expire_cycle_delta: DENUNCIATION_EXPIRE_CYCLE_DELTA, + denunciation_expire_periods: DENUNCIATION_EXPIRE_PERIODS, denunciation_items_max_cycle_delta: DENUNCIATION_ITEMS_MAX_CYCLE_DELTA, }; let factory_channels = FactoryChannels { diff --git a/massa-pool-exports/src/config.rs b/massa-pool-exports/src/config.rs index 1405f193773..66be14d19ff 100644 --- a/massa-pool-exports/src/config.rs +++ b/massa-pool-exports/src/config.rs @@ -37,6 +37,6 @@ pub struct PoolConfig { pub t0: MassaTime, /// cycle duration in periods pub periods_per_cycle: u64, - /// denunciation expiration as cycle delta - pub denunciation_expire_cycle_delta: u64, + /// denunciation expiration (in periods) + pub denunciation_expire_periods: u64, } diff --git a/massa-pool-exports/src/test_exports/config.rs b/massa-pool-exports/src/test_exports/config.rs index 6f5bc524af6..05091831583 100644 --- a/massa-pool-exports/src/test_exports/config.rs +++ b/massa-pool-exports/src/test_exports/config.rs @@ -1,10 +1,6 @@ // Copyright (c) 2022 MASSA LABS -use massa_models::config::{ - DENUNCIATION_EXPIRE_CYCLE_DELTA, ENDORSEMENT_COUNT, GENESIS_TIMESTAMP, MAX_BLOCK_SIZE, - MAX_GAS_PER_BLOCK, MAX_OPERATIONS_PER_BLOCK, OPERATION_VALIDITY_PERIODS, PERIODS_PER_CYCLE, - ROLL_PRICE, T0, THREAD_COUNT, -}; +use massa_models::config::{DENUNCIATION_EXPIRE_PERIODS, ENDORSEMENT_COUNT, GENESIS_TIMESTAMP, MAX_BLOCK_SIZE, MAX_GAS_PER_BLOCK, MAX_OPERATIONS_PER_BLOCK, OPERATION_VALIDITY_PERIODS, PERIODS_PER_CYCLE, ROLL_PRICE, T0, THREAD_COUNT}; use crate::PoolConfig; @@ -26,7 +22,7 @@ impl Default for PoolConfig { genesis_timestamp: *GENESIS_TIMESTAMP, t0: T0, periods_per_cycle: PERIODS_PER_CYCLE, - denunciation_expire_cycle_delta: DENUNCIATION_EXPIRE_CYCLE_DELTA, + denunciation_expire_periods: DENUNCIATION_EXPIRE_PERIODS, } } } diff --git a/massa-pool-worker/src/denunciation_pool.rs b/massa-pool-worker/src/denunciation_pool.rs index 3727d448c59..e40e97a98be 100644 --- a/massa-pool-worker/src/denunciation_pool.rs +++ b/massa-pool-worker/src/denunciation_pool.rs @@ -41,8 +41,7 @@ impl DenunciationPool { if !Denunciation::is_expired( denunciation.get_slot(), &self.last_cs_final_periods, - self.config.periods_per_cycle, - self.config.denunciation_expire_cycle_delta, + self.config.denunciation_expire_periods, ) { let de_id = DenunciationId::from(&denunciation); self.denunciations_cache.insert(de_id, denunciation); @@ -69,8 +68,7 @@ impl DenunciationPool { Denunciation::is_expired( de.get_slot(), &self.last_cs_final_periods, - self.config.periods_per_cycle, - self.config.denunciation_expire_cycle_delta, + self.config.denunciation_expire_periods, ) }); } diff --git a/massa-storage/src/denunciation_indexes.rs b/massa-storage/src/denunciation_indexes.rs deleted file mode 100644 index 660d9843f04..00000000000 --- a/massa-storage/src/denunciation_indexes.rs +++ /dev/null @@ -1,38 +0,0 @@ -use massa_models::denunciation::Denunciation; -use massa_models::{denunciation::DenunciationId, prehash::PreHashMap}; - -/// Container for all endorsements and different indexes. -/// Note: The structure can evolve and store more indexes. -#[derive(Default)] -pub struct DenunciationIndexes { - /// Denunciations structure container - denunciations: PreHashMap, -} - -impl DenunciationIndexes { - /// Insert a denunciation - /// Arguments: - /// - denunciation: the denunciation to insert - #[allow(unused_must_use)] - pub(crate) fn insert(&mut self, denunciation: Denunciation) { - let denunciation_id = DenunciationId::from(&denunciation); - self.denunciations.try_insert(denunciation_id, denunciation); - } - - /// Remove a endorsement, remove from the indexes and made some clean-up in indexes if necessary. - /// Arguments: - /// * `endorsement_id`: the endorsement id to remove - pub(crate) fn remove(&mut self, denunciation_id: &DenunciationId) -> Option { - self.denunciations.remove(denunciation_id) - } - - /// Gets a reference to a stored denunciation, if any. - pub fn get(&self, id: &DenunciationId) -> Option<&Denunciation> { - self.denunciations.get(id) - } - - /// Checks whether an denunciation exists in global storage. - pub fn contains(&self, id: &DenunciationId) -> bool { - self.denunciations.contains_key(id) - } -} From c7bb69f94db67efdf90ddea9653b52bf08e59076 Mon Sep 17 00:00:00 2001 From: sydhds Date: Fri, 31 Mar 2023 17:15:09 +0200 Subject: [PATCH 11/13] Add DenunciationInterest docstrings --- massa-models/src/denunciation.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/massa-models/src/denunciation.rs b/massa-models/src/denunciation.rs index 645db7104c9..91a0e38a69a 100644 --- a/massa-models/src/denunciation.rs +++ b/massa-models/src/denunciation.rs @@ -814,21 +814,24 @@ impl From<&Denunciation> for DenunciationId { // Denunciation interest /// DenunciationInterest variant for endorsement -#[allow(missing_docs)] #[derive(Debug, Clone)] pub struct EndorsementDenunciationInterest { + /// secure share endorsement public key pub public_key: PublicKey, + /// endorsement slot pub slot: Slot, + /// endorsement index pub index: u32, hash: Hash, signature: Signature, } /// DenunciationInterest variant for block header -#[allow(missing_docs)] #[derive(Debug, Clone)] pub struct BlockHeaderDenunciationInterest { + /// secured header public key pub public_key: PublicKey, + /// block header slot pub slot: Slot, hash: Hash, signature: Signature, @@ -836,10 +839,11 @@ pub struct BlockHeaderDenunciationInterest { /// Lightweight data for Denunciation creation /// (avoid storing heavyweight secured header or secure share endorsement) -#[allow(missing_docs)] #[derive(Debug, Clone)] pub enum DenunciationInterest { + /// Endorsement variant Endorsement(EndorsementDenunciationInterest), + /// Block header variant BlockHeader(BlockHeaderDenunciationInterest), } From 72c4e4b5b797214ca2f414f8519fb36cefbe6752 Mon Sep 17 00:00:00 2001 From: sydhds Date: Mon, 3 Apr 2023 10:01:33 +0200 Subject: [PATCH 12/13] Rename DenunciationInterest to DenunciationPrecursor --- massa-consensus-exports/src/channels.rs | 4 +- massa-consensus-worker/src/controller.rs | 4 +- .../src/denunciation_factory.rs | 68 ++++++++++--------- massa-factory-worker/src/run.rs | 6 +- massa-factory-worker/src/tests/scenarios.rs | 6 +- massa-factory-worker/src/tests/tools.rs | 8 +-- massa-models/src/denunciation.rs | 55 +++++++++------ massa-node/src/main.rs | 4 +- massa-pool-worker/src/endorsement_pool.rs | 8 +-- massa-pool-worker/src/tests/tools.rs | 4 ++ massa-pool-worker/src/worker.rs | 4 +- 11 files changed, 95 insertions(+), 76 deletions(-) diff --git a/massa-consensus-exports/src/channels.rs b/massa-consensus-exports/src/channels.rs index b07cfc72859..2ce15cf6f69 100644 --- a/massa-consensus-exports/src/channels.rs +++ b/massa-consensus-exports/src/channels.rs @@ -1,7 +1,7 @@ use massa_execution_exports::ExecutionController; use massa_models::block::{Block, FilledBlock}; use massa_models::block_header::BlockHeader; -use massa_models::denunciation::DenunciationInterest; +use massa_models::denunciation::DenunciationPrecursor; use massa_pool_exports::PoolController; use massa_pos_exports::SelectorController; use massa_protocol_exports::ProtocolCommandSender; @@ -28,5 +28,5 @@ pub struct ConsensusChannels { /// Channel use by Websocket (if they are enable) to broadcast a new block integrated pub filled_block_sender: tokio::sync::broadcast::Sender, /// Channel use for Denunciation factory to create denunciations - pub denunciation_factory_sender: crossbeam_channel::Sender, + pub denunciation_factory_sender: crossbeam_channel::Sender, } diff --git a/massa-consensus-worker/src/controller.rs b/massa-consensus-worker/src/controller.rs index dc6d0b1165f..9e727a7a607 100644 --- a/massa-consensus-worker/src/controller.rs +++ b/massa-consensus-worker/src/controller.rs @@ -3,7 +3,7 @@ use massa_consensus_exports::{ bootstrapable_graph::BootstrapableGraph, error::ConsensusError, export_active_block::ExportActiveBlock, ConsensusChannels, ConsensusController, }; -use massa_models::denunciation::DenunciationInterest; +use massa_models::denunciation::DenunciationPrecursor; use massa_models::{ block::{BlockGraphStatus, FilledBlock}, block_header::BlockHeader, @@ -286,7 +286,7 @@ impl ConsensusController for ConsensusControllerImpl { if let Err(e) = self .channels .denunciation_factory_sender - .send(DenunciationInterest::try_from(&header).unwrap()) + .send(DenunciationPrecursor::try_from(&header).unwrap()) { warn!("Cannot send header to denunciation factory: {}", e); } diff --git a/massa-factory-worker/src/denunciation_factory.rs b/massa-factory-worker/src/denunciation_factory.rs index 51f36b76ac6..f4427657be0 100644 --- a/massa-factory-worker/src/denunciation_factory.rs +++ b/massa-factory-worker/src/denunciation_factory.rs @@ -7,7 +7,7 @@ use tracing::{debug, info, warn}; use massa_factory_exports::{FactoryChannels, FactoryConfig}; use massa_models::address::Address; -use massa_models::denunciation::{Denunciation, DenunciationInterest}; +use massa_models::denunciation::{Denunciation, DenunciationPrecursor}; use massa_models::slot::Slot; use massa_models::timeslots::get_closest_slot_to_timestamp; use massa_time::MassaTime; @@ -18,8 +18,8 @@ pub(crate) struct DenunciationFactoryWorker { channels: FactoryChannels, /// Factory manager command receiver factory_receiver: Receiver<()>, - consensus_receiver: Receiver, - endorsement_pool_receiver: Receiver, + consensus_receiver: Receiver, + endorsement_pool_receiver: Receiver, /// Internal cache for endorsement denunciation /// store at most 1 endorsement per entry, as soon as we have 2 we produce a Denunciation endorsements_by_slot_index: HashMap<(Slot, u32), EndorsementDenunciationStatus>, @@ -34,8 +34,8 @@ impl DenunciationFactoryWorker { cfg: FactoryConfig, channels: FactoryChannels, factory_receiver: Receiver<()>, - consensus_receiver: Receiver, - endorsement_pool_receiver: Receiver, + consensus_receiver: Receiver, + endorsement_pool_receiver: Receiver, ) -> thread::JoinHandle<()> { thread::Builder::new() .name("denunciation-factory".into()) @@ -57,14 +57,14 @@ impl DenunciationFactoryWorker { /// Process new secured header (~ block header) fn process_new_secured_header( &mut self, - block_header_denunciation_interest: DenunciationInterest, + block_header_denunciation_interest: DenunciationPrecursor, ) { let de_i_orig = block_header_denunciation_interest.clone(); let de_i = match block_header_denunciation_interest { - DenunciationInterest::Endorsement(_) => { + DenunciationPrecursor::Endorsement(_) => { return; } - DenunciationInterest::BlockHeader(de_i) => de_i, + DenunciationPrecursor::BlockHeader(de_i) => de_i, }; let now = MassaTime::now().expect("could not get current time"); @@ -77,16 +77,17 @@ impl DenunciationFactoryWorker { now, ); - let cycle_of_header = de_i.slot.get_cycle(self.cfg.periods_per_cycle); - let cycle_now = slot_now.get_cycle(self.cfg.periods_per_cycle); + let last_final_periods = self.channels.pool.get_final_cs_periods(); + if de_i.slot.period + < last_final_periods[de_i.slot.thread as usize] + .saturating_sub(self.cfg.denunciation_expire_periods) + { + // too old - cannot be denounced anymore + return; + } - // Do not fulfill the cache with block header too much in the future - // Note that cache is also purged each time a slot becomes final - if cycle_now - cycle_of_header > self.cfg.denunciation_items_max_cycle_delta { - warn!( - "Denunciation factory received a denunciation interest way to much in the future: {:?}", - de_i - ); + if de_i.slot.period.saturating_sub(slot_now.period) > self.cfg.denunciation_expire_periods { + // too much in the future - ignored return; } @@ -111,7 +112,7 @@ impl DenunciationFactoryWorker { Entry::Occupied(mut eo) => { match eo.get_mut() { BlockHeaderDenunciationStatus::Accumulating(de_i_1_) => { - let de_i_1: &DenunciationInterest = de_i_1_; + let de_i_1: &DenunciationPrecursor = de_i_1_; match Denunciation::try_from((de_i_1, &de_i_orig)) { Ok(de) => { eo.insert(BlockHeaderDenunciationStatus::DenunciationEmitted); @@ -150,12 +151,12 @@ impl DenunciationFactoryWorker { /// Process new secure share endorsement (~ endorsement) fn process_new_secure_share_endorsement( &mut self, - endorsement_denunciation_interest: DenunciationInterest, + endorsement_denunciation_interest: DenunciationPrecursor, ) { let de_i_orig = endorsement_denunciation_interest.clone(); let de_i = match endorsement_denunciation_interest { - DenunciationInterest::Endorsement(de_i) => de_i, - DenunciationInterest::BlockHeader(_) => { + DenunciationPrecursor::Endorsement(de_i) => de_i, + DenunciationPrecursor::BlockHeader(_) => { return; } }; @@ -170,16 +171,17 @@ impl DenunciationFactoryWorker { now, ); - let cycle_of_header = de_i.slot.get_cycle(self.cfg.periods_per_cycle); - let cycle_now = slot_now.get_cycle(self.cfg.periods_per_cycle); + let last_final_periods = self.channels.pool.get_final_cs_periods(); + if de_i.slot.period + < last_final_periods[de_i.slot.thread as usize] + .saturating_sub(self.cfg.denunciation_expire_periods) + { + // too old - cannot be denounced anymore + return; + } - // Do not fulfill the cache with block header too much in the future - // Note that cache is also purged each time a slot becomes final - if cycle_now - cycle_of_header > self.cfg.denunciation_items_max_cycle_delta { - warn!( - "Denunciation factory received a denunciation interest way to much in the future: {:?}", - de_i - ); + if de_i.slot.period.saturating_sub(slot_now.period) > self.cfg.denunciation_expire_periods { + // too much in the future - ignored return; } @@ -209,7 +211,7 @@ impl DenunciationFactoryWorker { Entry::Occupied(mut eo) => { match eo.get_mut() { EndorsementDenunciationStatus::Accumulating(de_i_1_) => { - let de_i_1: &DenunciationInterest = de_i_1_; + let de_i_1: &DenunciationPrecursor = de_i_1_; match Denunciation::try_from((de_i_1, &de_i_orig)) { Ok(de) => { eo.insert(EndorsementDenunciationStatus::DenunciationEmitted); @@ -304,12 +306,12 @@ impl DenunciationFactoryWorker { #[allow(clippy::large_enum_variant)] enum EndorsementDenunciationStatus { - Accumulating(DenunciationInterest), + Accumulating(DenunciationPrecursor), DenunciationEmitted, } #[allow(clippy::large_enum_variant)] enum BlockHeaderDenunciationStatus { - Accumulating(DenunciationInterest), + Accumulating(DenunciationPrecursor), DenunciationEmitted, } diff --git a/massa-factory-worker/src/run.rs b/massa-factory-worker/src/run.rs index b72f8aa2ce0..53de8408457 100644 --- a/massa-factory-worker/src/run.rs +++ b/massa-factory-worker/src/run.rs @@ -11,7 +11,7 @@ use crate::{ manager::FactoryManagerImpl, }; use massa_factory_exports::{FactoryChannels, FactoryConfig, FactoryManager}; -use massa_models::denunciation::DenunciationInterest; +use massa_models::denunciation::DenunciationPrecursor; use massa_wallet::Wallet; /// Start factory @@ -27,8 +27,8 @@ pub fn start_factory( cfg: FactoryConfig, wallet: Arc>, channels: FactoryChannels, - denunciation_factory_consensus_receiver: Receiver, - denunciation_factory_endorsement_pool_receiver: Receiver, + denunciation_factory_consensus_receiver: Receiver, + denunciation_factory_endorsement_pool_receiver: Receiver, ) -> Box { // create block factory channel let (block_worker_tx, block_worker_rx) = mpsc::channel::<()>(); diff --git a/massa-factory-worker/src/tests/scenarios.rs b/massa-factory-worker/src/tests/scenarios.rs index 59ca823a8ef..e7a2157672a 100644 --- a/massa-factory-worker/src/tests/scenarios.rs +++ b/massa-factory-worker/src/tests/scenarios.rs @@ -3,7 +3,7 @@ use massa_hash::Hash; use massa_models::block_header::{BlockHeader, BlockHeaderSerializer, SecuredHeader}; use massa_models::block_id::BlockId; use massa_models::config::{T0, THREAD_COUNT}; -use massa_models::denunciation::{Denunciation, DenunciationId, DenunciationInterest}; +use massa_models::denunciation::{Denunciation, DenunciationId, DenunciationPrecursor}; use massa_models::endorsement::{Endorsement, EndorsementSerializerLW}; use massa_models::slot::Slot; use massa_models::timeslots::get_closest_slot_to_timestamp; @@ -137,11 +137,11 @@ fn test_denunciation_factory_block_header_denunciation() { test_factory .denunciation_factory_sender - .send(DenunciationInterest::try_from(&secured_header_1.clone()).unwrap()) + .send(DenunciationPrecursor::try_from(&secured_header_1.clone()).unwrap()) .unwrap(); test_factory .denunciation_factory_sender - .send(DenunciationInterest::try_from(&secured_header_2.clone()).unwrap()) + .send(DenunciationPrecursor::try_from(&secured_header_2.clone()).unwrap()) .unwrap(); // Wait for denunciation factory to create the Denunciation diff --git a/massa-factory-worker/src/tests/tools.rs b/massa-factory-worker/src/tests/tools.rs index e0f9f26d007..6fc3bb9140b 100644 --- a/massa-factory-worker/src/tests/tools.rs +++ b/massa-factory-worker/src/tests/tools.rs @@ -12,7 +12,7 @@ use std::{ use massa_factory_exports::{ test_exports::create_empty_block, FactoryChannels, FactoryConfig, FactoryManager, }; -use massa_models::denunciation::DenunciationInterest; +use massa_models::denunciation::DenunciationPrecursor; use massa_models::{ address::Address, block_id::BlockId, config::ENDORSEMENT_COUNT, endorsement::SecureShareEndorsement, operation::SecureShareOperation, prehash::PreHashMap, @@ -47,8 +47,8 @@ pub struct TestFactory { genesis_blocks: Vec<(BlockId, u64)>, pub(crate) storage: Storage, keypair: KeyPair, - pub(crate) denunciation_factory_sender: Sender, - pub(crate) denunciation_factory_tx: Sender, + pub(crate) denunciation_factory_sender: Sender, + pub(crate) denunciation_factory_tx: Sender, } impl TestFactory { @@ -64,7 +64,7 @@ impl TestFactory { MockConsensusController::new_with_receiver(); let (pool_controller, pool_receiver) = MockPoolController::new_with_receiver(); let (denunciation_factory_tx, denunciation_factory_rx) = - crossbeam_channel::unbounded::(); + crossbeam_channel::unbounded::(); let (denunciation_factory_sender, denunciation_factory_receiver) = crossbeam_channel::bounded(massa_models::config::CHANNEL_SIZE); let mut storage = Storage::create_root(); diff --git a/massa-models/src/denunciation.rs b/massa-models/src/denunciation.rs index 91a0e38a69a..f1f11f87f6c 100644 --- a/massa-models/src/denunciation.rs +++ b/massa-models/src/denunciation.rs @@ -723,6 +723,17 @@ impl Deserializer for DenunciationDeserializer { // End Ser / Der // Denunciation Id +// TODO: replace with +// #[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] +// pub enum DenunciationKey { +// Header { +// slot: Slot +// }, +// Endorsement { +// slot: Slot, +// index: u32 +// } +// } /// Endorsement ID size in bytes pub const DENUNCIATION_ID_SIZE_BYTES: usize = massa_hash::HASH_SIZE_BYTES; @@ -815,7 +826,7 @@ impl From<&Denunciation> for DenunciationId { /// DenunciationInterest variant for endorsement #[derive(Debug, Clone)] -pub struct EndorsementDenunciationInterest { +pub struct EndorsementDenunciationPrecursor { /// secure share endorsement public key pub public_key: PublicKey, /// endorsement slot @@ -828,7 +839,7 @@ pub struct EndorsementDenunciationInterest { /// DenunciationInterest variant for block header #[derive(Debug, Clone)] -pub struct BlockHeaderDenunciationInterest { +pub struct BlockHeaderDenunciationPrecursor { /// secured header public key pub public_key: PublicKey, /// block header slot @@ -840,21 +851,22 @@ pub struct BlockHeaderDenunciationInterest { /// Lightweight data for Denunciation creation /// (avoid storing heavyweight secured header or secure share endorsement) #[derive(Debug, Clone)] -pub enum DenunciationInterest { +pub enum DenunciationPrecursor { /// Endorsement variant - Endorsement(EndorsementDenunciationInterest), + Endorsement(EndorsementDenunciationPrecursor), /// Block header variant - BlockHeader(BlockHeaderDenunciationInterest), + BlockHeader(BlockHeaderDenunciationPrecursor), } -impl TryFrom<&SecureShareEndorsement> for DenunciationInterest { +impl TryFrom<&SecureShareEndorsement> for DenunciationPrecursor { type Error = DenunciationError; fn try_from(value: &SecureShareEndorsement) -> Result { + // TODO: find a way to avoid recomputing a hash let hash = EndorsementDenunciation::compute_content_hash(&value.content)?; - Ok(DenunciationInterest::Endorsement( - EndorsementDenunciationInterest { + Ok(DenunciationPrecursor::Endorsement( + EndorsementDenunciationPrecursor { public_key: value.content_creator_pub_key, slot: value.content.slot, index: value.content.index, @@ -865,14 +877,15 @@ impl TryFrom<&SecureShareEndorsement> for DenunciationInterest { } } -impl TryFrom<&SecuredHeader> for DenunciationInterest { +impl TryFrom<&SecuredHeader> for DenunciationPrecursor { type Error = DenunciationError; fn try_from(value: &SecuredHeader) -> Result { + // TODO: find a way to avoid recomputing a hash let hash = BlockHeaderDenunciation::compute_content_hash(&value.content)?; - Ok(DenunciationInterest::BlockHeader( - BlockHeaderDenunciationInterest { + Ok(DenunciationPrecursor::BlockHeader( + BlockHeaderDenunciationPrecursor { public_key: value.content_creator_pub_key, slot: value.content.slot, hash, @@ -883,17 +896,17 @@ impl TryFrom<&SecuredHeader> for DenunciationInterest { } /// Create a new Denunciation from 2 SecureHeader -impl TryFrom<(&DenunciationInterest, &DenunciationInterest)> for Denunciation { +impl TryFrom<(&DenunciationPrecursor, &DenunciationPrecursor)> for Denunciation { type Error = DenunciationError; fn try_from( - (de_i_1, de_i_2): (&DenunciationInterest, &DenunciationInterest), + (de_i_1, de_i_2): (&DenunciationPrecursor, &DenunciationPrecursor), ) -> Result { // TODO: add checks before creating match (de_i_1, de_i_2) { ( - DenunciationInterest::BlockHeader(de_i_blkh_1), - DenunciationInterest::BlockHeader(de_i_blkh_2), + DenunciationPrecursor::BlockHeader(de_i_blkh_1), + DenunciationPrecursor::BlockHeader(de_i_blkh_2), ) => Ok(Denunciation::BlockHeader(BlockHeaderDenunciation { public_key: de_i_blkh_1.public_key, slot: de_i_blkh_1.slot, @@ -903,8 +916,8 @@ impl TryFrom<(&DenunciationInterest, &DenunciationInterest)> for Denunciation { hash_2: de_i_blkh_2.hash, })), ( - DenunciationInterest::Endorsement(de_i_endo_1), - DenunciationInterest::Endorsement(de_i_endo_2), + DenunciationPrecursor::Endorsement(de_i_endo_1), + DenunciationPrecursor::Endorsement(de_i_endo_2), ) => Ok(Denunciation::Endorsement(EndorsementDenunciation { public_key: de_i_endo_1.public_key, slot: de_i_endo_1.slot, @@ -1291,8 +1304,8 @@ mod tests { let (_, _, s_block_header_1, s_block_header_2, _) = gen_block_headers_for_denunciation(); let denunciation: Denunciation = (&s_block_header_1, &s_block_header_2).try_into().unwrap(); - let de_i_1 = DenunciationInterest::try_from(&s_block_header_1).unwrap(); - let de_i_2 = DenunciationInterest::try_from(&s_block_header_2).unwrap(); + let de_i_1 = DenunciationPrecursor::try_from(&s_block_header_1).unwrap(); + let de_i_2 = DenunciationPrecursor::try_from(&s_block_header_2).unwrap(); let denunciation_2: Denunciation = (&de_i_1, &de_i_2).try_into().unwrap(); assert_eq!(denunciation, denunciation_2); @@ -1300,8 +1313,8 @@ mod tests { let (_, _, s_endorsement_1, s_endorsement_2, _) = gen_endorsements_for_denunciation(); let denunciation_3 = Denunciation::try_from((&s_endorsement_1, &s_endorsement_2)).unwrap(); - let de_i_3 = DenunciationInterest::try_from(&s_endorsement_1).unwrap(); - let de_i_4 = DenunciationInterest::try_from(&s_endorsement_2).unwrap(); + let de_i_3 = DenunciationPrecursor::try_from(&s_endorsement_1).unwrap(); + let de_i_4 = DenunciationPrecursor::try_from(&s_endorsement_2).unwrap(); let denunciation_4: Denunciation = (&de_i_3, &de_i_4).try_into().unwrap(); assert_eq!(denunciation_3, denunciation_4); diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index f4f3b20a52c..3bb35b24d14 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -49,7 +49,7 @@ use massa_models::config::constants::{ use massa_models::config::{ CONSENSUS_BOOTSTRAP_PART_SIZE, DENUNCIATION_EXPIRE_PERIODS, DENUNCIATION_ITEMS_MAX_CYCLE_DELTA, }; -use massa_models::denunciation::DenunciationInterest; +use massa_models::denunciation::DenunciationPrecursor; use massa_network_exports::{Establisher, NetworkConfig, NetworkManager}; use massa_network_worker::start_network_controller; use massa_pool_exports::{PoolChannels, PoolConfig, PoolManager}; @@ -382,7 +382,7 @@ async fn launch( operation_sender: broadcast::channel(pool_config.broadcast_operations_capacity).0, }; let (denunciation_factory_tx, denunciation_factory_rx) = - crossbeam_channel::unbounded::(); + crossbeam_channel::unbounded::(); let (pool_manager, pool_controller) = start_pool_controller( pool_config, diff --git a/massa-pool-worker/src/endorsement_pool.rs b/massa-pool-worker/src/endorsement_pool.rs index 2b4e11c942f..2d47bbe0dda 100644 --- a/massa-pool-worker/src/endorsement_pool.rs +++ b/massa-pool-worker/src/endorsement_pool.rs @@ -1,7 +1,7 @@ //! Copyright (c) 2022 MASSA LABS use crossbeam_channel::Sender; -use massa_models::denunciation::DenunciationInterest; +use massa_models::denunciation::DenunciationPrecursor; use massa_models::{ block_id::BlockId, endorsement::EndorsementId, @@ -31,14 +31,14 @@ pub struct EndorsementPool { last_cs_final_periods: Vec, /// Queue to Denunciation factory - denunciation_factory_tx: Sender, + denunciation_factory_tx: Sender, } impl EndorsementPool { pub fn init( config: PoolConfig, storage: &Storage, - denunciation_factory_tx: Sender, + denunciation_factory_tx: Sender, ) -> Self { EndorsementPool { last_cs_final_periods: vec![0u64; config.thread_count as usize], @@ -129,7 +129,7 @@ impl EndorsementPool { } // And send endorsements to Denunciation Factory - match DenunciationInterest::try_from(endo) { + match DenunciationPrecursor::try_from(endo) { Ok(de_i) => { if let Err(e) = self.denunciation_factory_tx.send(de_i) { warn!("Cannot send endorsement to Denunciation factory: {}", e); diff --git a/massa-pool-worker/src/tests/tools.rs b/massa-pool-worker/src/tests/tools.rs index 4d6e8d9f81b..6fd79d3432c 100644 --- a/massa-pool-worker/src/tests/tools.rs +++ b/massa-pool-worker/src/tests/tools.rs @@ -5,6 +5,7 @@ use massa_execution_exports::test_exports::{ MockExecutionController, MockExecutionControllerMessage, }; use massa_hash::Hash; +use massa_models::denunciation::DenunciationPrecursor; use massa_models::{ address::Address, amount::Amount, @@ -95,11 +96,14 @@ where let storage: Storage = Storage::create_root(); let operation_sender = broadcast::channel(5000).0; let (execution_controller, execution_receiver) = MockExecutionController::new_with_receiver(); + let (denunciation_factory_tx, _denunciation_factory_rx) = + crossbeam_channel::unbounded::(); let (pool_manager, pool_controller) = start_pool_controller( cfg, &storage, execution_controller, PoolChannels { operation_sender }, + denunciation_factory_tx, ); test(pool_manager, pool_controller, execution_receiver, storage) diff --git a/massa-pool-worker/src/worker.rs b/massa-pool-worker/src/worker.rs index 38ccdb7e188..43ec9dbff6c 100644 --- a/massa-pool-worker/src/worker.rs +++ b/massa-pool-worker/src/worker.rs @@ -8,7 +8,7 @@ use crate::operation_pool::OperationPool; use crate::{controller_impl::PoolControllerImpl, endorsement_pool::EndorsementPool}; use crossbeam_channel::Sender; use massa_execution_exports::ExecutionController; -use massa_models::denunciation::DenunciationInterest; +use massa_models::denunciation::DenunciationPrecursor; use massa_pool_exports::PoolConfig; use massa_pool_exports::{PoolChannels, PoolController, PoolManager}; use massa_storage::Storage; @@ -172,7 +172,7 @@ pub fn start_pool_controller( storage: &Storage, execution_controller: Box, channels: PoolChannels, - denunciation_factory_tx: Sender, + denunciation_factory_tx: Sender, ) -> (Box, Box) { let (operations_input_sender, operations_input_receiver) = sync_channel(config.channels_size); let (endorsements_input_sender, endorsements_input_receiver) = From 4f12d7565534e0d395c3be63e3ade89d378fa08c Mon Sep 17 00:00:00 2001 From: sydhds Date: Mon, 3 Apr 2023 17:00:06 +0200 Subject: [PATCH 13/13] Cargo fmt pass --- massa-pool-exports/src/test_exports/config.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/massa-pool-exports/src/test_exports/config.rs b/massa-pool-exports/src/test_exports/config.rs index 05091831583..6a6ada8d0a9 100644 --- a/massa-pool-exports/src/test_exports/config.rs +++ b/massa-pool-exports/src/test_exports/config.rs @@ -1,6 +1,10 @@ // Copyright (c) 2022 MASSA LABS -use massa_models::config::{DENUNCIATION_EXPIRE_PERIODS, ENDORSEMENT_COUNT, GENESIS_TIMESTAMP, MAX_BLOCK_SIZE, MAX_GAS_PER_BLOCK, MAX_OPERATIONS_PER_BLOCK, OPERATION_VALIDITY_PERIODS, PERIODS_PER_CYCLE, ROLL_PRICE, T0, THREAD_COUNT}; +use massa_models::config::{ + DENUNCIATION_EXPIRE_PERIODS, ENDORSEMENT_COUNT, GENESIS_TIMESTAMP, MAX_BLOCK_SIZE, + MAX_GAS_PER_BLOCK, MAX_OPERATIONS_PER_BLOCK, OPERATION_VALIDITY_PERIODS, PERIODS_PER_CYCLE, + ROLL_PRICE, T0, THREAD_COUNT, +}; use crate::PoolConfig;