Skip to content

Commit e2f0e25

Browse files
committed
First pass fix
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 464b796 commit e2f0e25

File tree

2 files changed

+51
-100
lines changed

2 files changed

+51
-100
lines changed

stacks-signer/src/signerdb.rs

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -733,18 +733,6 @@ impl SignerDb {
733733
try_deserialize(result)
734734
}
735735

736-
/// Return the last accepted block the signer (highest stacks height). It will tie break a match based on which was more recently signed.
737-
pub fn get_signer_last_accepted_block(&self) -> Result<Option<BlockInfo>, DBError> {
738-
let query = "SELECT block_info FROM blocks WHERE state IN (?1, ?2) ORDER BY stacks_height DESC, signed_group DESC, signed_self DESC LIMIT 1";
739-
let args = params![
740-
&BlockState::GloballyAccepted.to_string(),
741-
&BlockState::LocallyAccepted.to_string()
742-
];
743-
let result: Option<String> = query_row(&self.db, query, args)?;
744-
745-
try_deserialize(result)
746-
}
747-
748736
/// Return the last accepted block in a tenure (identified by its consensus hash).
749737
pub fn get_last_accepted_block(
750738
&self,
@@ -1769,69 +1757,4 @@ mod tests {
17691757
< block_infos[0].proposed_time
17701758
);
17711759
}
1772-
1773-
#[test]
1774-
fn signer_last_accepted_block() {
1775-
let db_path = tmp_db_path();
1776-
let mut db = SignerDb::new(db_path).expect("Failed to create signer db");
1777-
1778-
let (mut block_info_1, _block_proposal_1) = create_block_override(|b| {
1779-
b.block.header.miner_signature = MessageSignature([0x01; 65]);
1780-
b.block.header.chain_length = 1;
1781-
b.burn_height = 1;
1782-
});
1783-
1784-
let (mut block_info_2, _block_proposal_2) = create_block_override(|b| {
1785-
b.block.header.miner_signature = MessageSignature([0x02; 65]);
1786-
b.block.header.chain_length = 2;
1787-
b.burn_height = 1;
1788-
});
1789-
1790-
let (mut block_info_3, _block_proposal_3) = create_block_override(|b| {
1791-
b.block.header.miner_signature = MessageSignature([0x02; 65]);
1792-
b.block.header.chain_length = 2;
1793-
b.burn_height = 4;
1794-
});
1795-
block_info_3
1796-
.mark_locally_accepted(false)
1797-
.expect("Failed to mark block as locally accepted");
1798-
1799-
db.insert_block(&block_info_1)
1800-
.expect("Unable to insert block into db");
1801-
db.insert_block(&block_info_2)
1802-
.expect("Unable to insert block into db");
1803-
1804-
assert!(db.get_signer_last_accepted_block().unwrap().is_none());
1805-
1806-
block_info_1
1807-
.mark_globally_accepted()
1808-
.expect("Failed to mark block as globally accepted");
1809-
db.insert_block(&block_info_1)
1810-
.expect("Unable to insert block into db");
1811-
1812-
assert_eq!(
1813-
db.get_signer_last_accepted_block().unwrap().unwrap(),
1814-
block_info_1
1815-
);
1816-
1817-
block_info_2
1818-
.mark_globally_accepted()
1819-
.expect("Failed to mark block as globally accepted");
1820-
block_info_2.signed_self = Some(get_epoch_time_secs());
1821-
db.insert_block(&block_info_2)
1822-
.expect("Unable to insert block into db");
1823-
1824-
assert_eq!(
1825-
db.get_signer_last_accepted_block().unwrap().unwrap(),
1826-
block_info_2
1827-
);
1828-
1829-
db.insert_block(&block_info_3)
1830-
.expect("Unable to insert block into db");
1831-
1832-
assert_eq!(
1833-
db.get_signer_last_accepted_block().unwrap().unwrap(),
1834-
block_info_3
1835-
);
1836-
}
18371760
}

stacks-signer/src/v0/signer.rs

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -592,26 +592,17 @@ impl Signer {
592592
) -> Option<BlockResponse> {
593593
let signer_signature_hash = proposed_block.header.signer_signature_hash();
594594
let proposed_block_consensus_hash = proposed_block.header.consensus_hash;
595-
596-
match self.signer_db.get_signer_last_accepted_block() {
597-
Ok(Some(last_block_info)) => {
598-
if proposed_block.header.chain_length <= last_block_info.block.header.chain_length {
599-
// We do not allow reorgs at any time within the same consensus hash OR of globally accepted blocks
600-
let non_reorgable_block = last_block_info.block.header.consensus_hash
601-
== proposed_block_consensus_hash
602-
|| last_block_info.state == BlockState::GloballyAccepted;
603-
// Is the reorg timeout requirement exceeded?
604-
let reorg_timeout_exceeded = last_block_info
605-
.signed_self
606-
.map(|signed_over_time| {
607-
signed_over_time.saturating_add(
608-
self.proposal_config
609-
.tenure_last_block_proposal_timeout
610-
.as_secs(),
611-
) <= get_epoch_time_secs()
612-
})
613-
.unwrap_or(false);
614-
if non_reorgable_block || !reorg_timeout_exceeded {
595+
// If the tenure change block confirms the expected parent block, it should confirm at least one more block than the last accepted block in the parent tenure.
596+
if let Some(tenure_change) = proposed_block.get_tenure_change_tx_payload() {
597+
match SortitionsView::get_tenure_last_block_info(
598+
&tenure_change.prev_tenure_consensus_hash,
599+
&self.signer_db,
600+
self.proposal_config.tenure_last_block_proposal_timeout,
601+
) {
602+
Ok(Some(last_block_info)) => {
603+
if proposed_block.header.chain_length
604+
<= last_block_info.block.header.chain_length
605+
{
615606
warn!(
616607
"Miner's block proposal does not confirm as many blocks as we expect";
617608
"proposed_block_consensus_hash" => %proposed_block_consensus_hash,
@@ -625,17 +616,54 @@ impl Signer {
625616
));
626617
}
627618
}
628-
None
619+
Ok(_) => {
620+
// We have no information about the parent consensus hash. Just assume its valid.
621+
}
622+
Err(e) => {
623+
warn!("{self}: Failed to check block against signer db: {e}";
624+
"signer_sighash" => %signer_signature_hash,
625+
"block_id" => %proposed_block.block_id()
626+
);
627+
return Some(
628+
self.create_block_rejection(RejectCode::ConnectivityIssues, proposed_block),
629+
);
630+
}
629631
}
630-
Ok(_) => None,
632+
}
633+
634+
// Ensure that the block proposal confirms the expected number of blocks in the current tenure
635+
// (This may be redundant for a tenure change block, but we could have had two valid tenure change blocks in a row)
636+
match self
637+
.signer_db
638+
.get_last_accepted_block(&proposed_block_consensus_hash)
639+
{
640+
Ok(Some(last_block_info)) => {
641+
if proposed_block.header.chain_length <= last_block_info.block.header.chain_length {
642+
warn!(
643+
"Miner's block proposal does not confirm as many blocks as we expect";
644+
"proposed_block_consensus_hash" => %proposed_block_consensus_hash,
645+
"proposed_block_signer_sighash" => %signer_signature_hash,
646+
"proposed_chain_length" => proposed_block.header.chain_length,
647+
"expected_at_least" => last_block_info.block.header.chain_length + 1,
648+
);
649+
return Some(self.create_block_rejection(
650+
RejectCode::SortitionViewMismatch,
651+
proposed_block,
652+
));
653+
}
654+
}
655+
Ok(_) => {}
631656
Err(e) => {
632657
warn!("{self}: Failed to check block against signer db: {e}";
633658
"signer_sighash" => %signer_signature_hash,
634659
"block_id" => %proposed_block.block_id()
635660
);
636-
Some(self.create_block_rejection(RejectCode::ConnectivityIssues, proposed_block))
661+
return Some(
662+
self.create_block_rejection(RejectCode::ConnectivityIssues, proposed_block),
663+
);
637664
}
638665
}
666+
None
639667
}
640668

641669
/// Handle the block validate ok response. Returns our block response if we have one

0 commit comments

Comments
 (0)