Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mid term double stake protection #3646

Merged
merged 8 commits into from
Mar 6, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions massa-consensus-worker/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ pub struct ConsensusState {
pub wishlist: PreHashMap<BlockId, Option<SecuredHeader>>,
/// previous blockclique notified to Execution
pub prev_blockclique: PreHashMap<BlockId, Slot>,
/// Blocks for each slots (used for multi-stake). Blocks
/// should be saved in this map when we receive the header or directly full block
pub nonfinal_active_blocks_per_slot: HashMap<Slot, PreHashSet<BlockId>>,
}

impl ConsensusState {
Expand Down
37 changes: 34 additions & 3 deletions massa-consensus-worker/src/state/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use massa_models::{
use massa_signature::PublicKey;
use massa_storage::Storage;
use massa_time::MassaTime;
use tracing::log::{debug, info};
use tracing::log::{debug, info, warn};

use super::ConsensusState;

Expand Down Expand Up @@ -112,6 +112,22 @@ impl ConsensusState {
block_id
)));
};
// Verify that we haven't already received 2 blocks for this slot
let entry = self
.nonfinal_active_blocks_per_slot
.entry(header.content.slot)
.or_default();
if !entry.contains(&header.id) {
if entry.len() > 1 && !self.wishlist.contains_key(&block_id) {
warn!(
"received more than 2 blocks for slot {}",
header.content.slot
);
return Ok(BTreeSet::new());
} else {
entry.insert(block_id);
}
}
self.check_block_header_and_store(block_id, header, current_slot)?;
return Ok(BTreeSet::new());
}
Expand Down Expand Up @@ -140,7 +156,22 @@ impl ConsensusState {
.get(&block_id)
.cloned()
.expect("incoming block not found in storage");

// Verify that we haven't already received 2 blocks for this slot
let entry = self
.nonfinal_active_blocks_per_slot
.entry(stored_block.content.header.content.slot)
.or_default();
if !entry.contains(&stored_block.id) {
if entry.len() > 1 && !self.wishlist.contains_key(&block_id) {
warn!(
"received more than 2 blocks for slot {}",
stored_block.content.header.content.slot
);
return Ok(BTreeSet::default());
} else {
entry.insert(block_id);
}
}
match self.check_block_and_store(
block_id,
slot,
Expand All @@ -149,7 +180,7 @@ impl ConsensusState {
current_slot,
)? {
Some(block_infos) => block_infos,
None => return Ok(BTreeSet::default()),
None => return Ok(BTreeSet::new()),
}
}

Expand Down
20 changes: 19 additions & 1 deletion massa-consensus-worker/src/state/prune.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ impl ConsensusState {
});
}

// Keep only a certain (`config.max_future_processing_blocks`) number of blocks that are discarded
// Keep only a certain (`config.max_discarded_blocks`) number of blocks that are discarded
// to avoid too big memory consumption
fn prune_discarded(&mut self) -> Result<(), ConsensusError> {
if self.discarded_index.len() <= self.config.max_discarded_blocks {
Expand Down Expand Up @@ -332,6 +332,21 @@ impl ConsensusState {
Ok(())
}

fn prune_nonfinal_blocks_per_slot(&mut self) {
damip marked this conversation as resolved.
Show resolved Hide resolved
let keys = self
.nonfinal_active_blocks_per_slot
.keys()
.cloned()
.collect::<Vec<_>>();
for (thread, (_, period)) in self.latest_final_blocks_periods.iter().enumerate() {
for key in &keys {
if key.thread == thread as u8 && key.period <= *period {
self.nonfinal_active_blocks_per_slot.remove(&key);
}
}
}
}

pub fn prune(&mut self) -> Result<(), ConsensusError> {
let before = self.max_cliques.len();
// Step 1: discard final blocks that are not useful to the graph anymore and return them
Expand All @@ -346,6 +361,9 @@ impl ConsensusState {
// Step 4: prune discarded
self.prune_discarded()?;

// Step 5: prune nonfinal blocks per slot
self.prune_nonfinal_blocks_per_slot();

let after = self.max_cliques.len();
if before != after {
debug!(
Expand Down
1 change: 1 addition & 0 deletions massa-consensus-worker/src/worker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub fn start_consensus_worker(
config.stats_timespan,
),
prev_blockclique: Default::default(),
nonfinal_active_blocks_per_slot: Default::default(),
}));

let shared_state_cloned = shared_state.clone();
Expand Down