Skip to content

Commit 8cf4092

Browse files
committed
Do not accept signatures, block proposals, or block responses for blocks in a different reward cycle
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent bbde40f commit 8cf4092

File tree

2 files changed

+60
-36
lines changed

2 files changed

+60
-36
lines changed

stacks-signer/src/signerdb.rs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -972,22 +972,6 @@ impl SignerDb {
972972
Ok(Some(broadcasted))
973973
}
974974

975-
/// Get the current state of a given block in the database
976-
pub fn get_block_state(
977-
&self,
978-
block_sighash: &Sha512Trunc256Sum,
979-
) -> Result<Option<BlockState>, DBError> {
980-
let qry = "SELECT state FROM blocks WHERE signer_signature_hash = ?1 LIMIT 1";
981-
let args = params![block_sighash];
982-
let state_opt: Option<String> = query_row(&self.db, qry, args)?;
983-
let Some(state) = state_opt else {
984-
return Ok(None);
985-
};
986-
Ok(Some(
987-
BlockState::try_from(state.as_str()).map_err(|_| DBError::Corruption)?,
988-
))
989-
}
990-
991975
/// Return the start time (epoch time in seconds) and the processing time in milliseconds of the tenure (idenfitied by consensus_hash).
992976
fn get_tenure_times(&self, tenure: &ConsensusHash) -> Result<(u64, u64), DBError> {
993977
let query = "SELECT tenure_change, proposed_time, validation_time_ms FROM blocks WHERE consensus_hash = ?1 AND state = ?2 ORDER BY stacks_height DESC";
@@ -1145,13 +1129,6 @@ mod tests {
11451129
.expect("Unable to get block from db");
11461130

11471131
assert_eq!(BlockInfo::from(block_proposal_2.clone()), block_info);
1148-
// test getting the block state
1149-
let block_state = db
1150-
.get_block_state(&block_proposal_1.block.header.signer_signature_hash())
1151-
.unwrap()
1152-
.expect("Unable to get block state from db");
1153-
1154-
assert_eq!(block_state, BlockInfo::from(block_proposal_1.clone()).state);
11551132
}
11561133

11571134
#[test]

stacks-signer/src/v0/signer.rs

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,17 @@ impl SignerTrait<SignerMessage> for Signer {
128128
debug!("{self}: No event received");
129129
return;
130130
};
131+
if self.reward_cycle > current_reward_cycle
132+
&& !matches!(
133+
event,
134+
SignerEvent::StatusCheck | SignerEvent::NewBurnBlock { .. }
135+
)
136+
{
137+
// The reward cycle has not yet started for this signer instance
138+
// Do not process any events other than status checks or new burn blocks
139+
debug!("{self}: Signer reward cycle has not yet started. Ignoring event.");
140+
return;
141+
}
131142
match event {
132143
SignerEvent::BlockValidationResponse(block_validate_response) => {
133144
debug!("{self}: Received a block proposal result from the stacks node...");
@@ -449,6 +460,15 @@ impl Signer {
449460
.block_lookup(&signer_signature_hash)
450461
.expect("Failed to connect to signer DB")
451462
{
463+
// Redundant check, but just in case the block proposal reward cycle was incorrectly overwritten, check again
464+
if block_info.reward_cycle != self.reward_cycle {
465+
// We are not signing for this reward cycle. Ignore the block.
466+
debug!(
467+
"{self}: Received a block proposal for a different reward cycle. Ignore it.";
468+
"requested_reward_cycle" => block_proposal.reward_cycle
469+
);
470+
return;
471+
}
452472
let Some(block_response) = self.determine_response(&block_info) else {
453473
// We are still waiting for a response for this block. Do nothing.
454474
debug!("{self}: Received a block proposal for a block we are already validating.";
@@ -659,6 +679,14 @@ impl Signer {
659679
// For mutability reasons, we need to take the block_info out of the map and add it back after processing
660680
let mut block_info = match self.signer_db.block_lookup(&signer_signature_hash) {
661681
Ok(Some(block_info)) => {
682+
if block_info.reward_cycle != self.reward_cycle {
683+
// We are not signing for this reward cycle. Ignore the block.
684+
debug!(
685+
"{self}: Received a block validation for a block from a different reward cycle. Ignore it.";
686+
"requested_reward_cycle" => block_info.reward_cycle
687+
);
688+
return None;
689+
}
662690
if block_info.is_locally_finalized() {
663691
debug!("{self}: Received block validation for a block that is already marked as {}. Ignoring...", block_info.state);
664692
return None;
@@ -744,6 +772,14 @@ impl Signer {
744772
}
745773
let mut block_info = match self.signer_db.block_lookup(&signer_signature_hash) {
746774
Ok(Some(block_info)) => {
775+
if block_info.reward_cycle != self.reward_cycle {
776+
// We are not signing for this reward cycle. Ignore the block.
777+
debug!(
778+
"{self}: Received a block validation for a block from a different reward cycle. Ignore it.";
779+
"requested_reward_cycle" => block_info.reward_cycle
780+
);
781+
return None;
782+
}
747783
if block_info.is_locally_finalized() {
748784
debug!("{self}: Received block validation for a block that is already marked as {}. Ignoring...", block_info.state);
749785
return None;
@@ -916,6 +952,14 @@ impl Signer {
916952

917953
let mut block_info = match self.signer_db.block_lookup(block_hash) {
918954
Ok(Some(block_info)) => {
955+
if block_info.reward_cycle != self.reward_cycle {
956+
// We are not signing for this reward cycle. Ignore the block.
957+
debug!(
958+
"{self}: Received a block rejection for a block from a different reward cycle. Ignore it.";
959+
"requested_reward_cycle" => block_info.reward_cycle
960+
);
961+
return;
962+
}
919963
if block_info.state == BlockState::GloballyRejected
920964
|| block_info.state == BlockState::GloballyAccepted
921965
{
@@ -1018,14 +1062,23 @@ impl Signer {
10181062
"{self}: Received a block-accept signature: ({block_hash}, {signature}, {})",
10191063
metadata.server_version
10201064
);
1021-
1022-
// Have we already processed this block?
1023-
match self.signer_db.get_block_state(block_hash) {
1024-
Ok(Some(state)) => {
1025-
if state == BlockState::GloballyAccepted || state == BlockState::GloballyRejected {
1026-
debug!("{self}: Received block signature for a block that is already marked as {}. Ignoring...", state);
1065+
let mut block_info = match self.signer_db.block_lookup(block_hash) {
1066+
Ok(Some(block_info)) => {
1067+
if block_info.reward_cycle != self.reward_cycle {
1068+
// We are not signing for this reward cycle. Ignore the block.
1069+
debug!(
1070+
"{self}: Received a block signature for a block from a different reward cycle. Ignore it.";
1071+
"requested_reward_cycle" => block_info.reward_cycle
1072+
);
10271073
return;
10281074
}
1075+
if block_info.state == BlockState::GloballyRejected
1076+
|| block_info.state == BlockState::GloballyAccepted
1077+
{
1078+
debug!("{self}: Received block signature for a block that is already marked as {}. Ignoring...", block_info.state);
1079+
return;
1080+
}
1081+
block_info
10291082
}
10301083
Ok(None) => {
10311084
debug!("{self}: Received block signature for a block we have not seen before. Ignoring...");
@@ -1035,7 +1088,7 @@ impl Signer {
10351088
warn!("{self}: Failed to load block state: {e:?}",);
10361089
return;
10371090
}
1038-
}
1091+
};
10391092

10401093
// recover public key
10411094
let Ok(public_key) = Secp256k1PublicKey::recover_to_pubkey(block_hash.bits(), signature)
@@ -1102,12 +1155,6 @@ impl Signer {
11021155
}
11031156

11041157
// have enough signatures to broadcast!
1105-
let Ok(Some(mut block_info)) = self.signer_db.block_lookup(block_hash).inspect_err(|e| {
1106-
warn!("{self}: Failed to load block {block_hash}: {e:?})");
1107-
}) else {
1108-
warn!("{self}: No such block {block_hash}");
1109-
return;
1110-
};
11111158
// move block to LOCALLY accepted state.
11121159
// It is only considered globally accepted IFF we receive a new block event confirming it OR see the chain tip of the node advance to it.
11131160
if let Err(e) = block_info.mark_locally_accepted(true) {

0 commit comments

Comments
 (0)