Skip to content

Commit 8489211

Browse files
committed
Fix validation queue race condition by ensuring that the sortition view hasn't updated between validation sumbission and approval
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent c79fa6c commit 8489211

File tree

5 files changed

+197
-92
lines changed

5 files changed

+197
-92
lines changed

stacks-signer/src/chainstate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ impl SortitionsView {
466466

467467
/// Get the last block from the given tenure
468468
/// Returns the last locally accepted block if it is not timed out, otherwise it will return the last globally accepted block.
469-
fn get_tenure_last_block_info(
469+
pub fn get_tenure_last_block_info(
470470
consensus_hash: &ConsensusHash,
471471
signer_db: &SignerDb,
472472
tenure_last_block_proposal_timeout: Duration,

stacks-signer/src/signerdb.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use blockstack_lib::util_lib::db::{
2424
Error as DBError,
2525
};
2626
use clarity::types::chainstate::{BurnchainHeaderHash, StacksAddress};
27+
use clarity::util::secp256k1::Secp256k1PublicKey;
2728
use libsigner::BlockProposal;
2829
use rusqlite::{
2930
params, Connection, Error as SqliteError, OpenFlags, OptionalExtension, Transaction,
@@ -157,28 +158,31 @@ pub struct BlockInfo {
157158
pub signed_group: Option<u64>,
158159
/// The block state relative to the signer's view of the stacks blockchain
159160
pub state: BlockState,
161+
/// The miner pubkey that proposed this block
162+
pub miner_pubkey: Secp256k1PublicKey,
160163
/// Extra data specific to v0, v1, etc.
161164
pub ext: ExtraBlockInfo,
162165
}
163166

164-
impl From<BlockProposal> for BlockInfo {
165-
fn from(value: BlockProposal) -> Self {
167+
impl BlockInfo {
168+
/// Create a new block info from the provided proposal and corresponding miner pubkey
169+
pub fn new(block_proposal: BlockProposal, miner_pubkey: Secp256k1PublicKey) -> Self {
166170
Self {
167-
block: value.block,
168-
burn_block_height: value.burn_height,
169-
reward_cycle: value.reward_cycle,
171+
block: block_proposal.block,
172+
burn_block_height: block_proposal.burn_height,
173+
reward_cycle: block_proposal.reward_cycle,
170174
vote: None,
171175
valid: None,
172176
signed_over: false,
173177
proposed_time: get_epoch_time_secs(),
174178
signed_self: None,
175179
signed_group: None,
176180
ext: ExtraBlockInfo::default(),
181+
miner_pubkey,
177182
state: BlockState::Unprocessed,
178183
}
179184
}
180-
}
181-
impl BlockInfo {
185+
182186
/// Mark this block as locally accepted, valid, signed over, and records either the self or group signed timestamp in the block info if it wasn't
183187
/// already set.
184188
pub fn mark_locally_accepted(&mut self, group_signed: bool) -> Result<(), String> {
@@ -853,7 +857,7 @@ mod tests {
853857
use std::path::PathBuf;
854858

855859
use blockstack_lib::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockHeader};
856-
use clarity::util::secp256k1::MessageSignature;
860+
use clarity::util::secp256k1::{MessageSignature, Secp256k1PrivateKey};
857861
use libsigner::BlockProposal;
858862

859863
use super::*;
@@ -879,7 +883,13 @@ mod tests {
879883
reward_cycle: 42,
880884
};
881885
overrides(&mut block_proposal);
882-
(BlockInfo::from(block_proposal.clone()), block_proposal)
886+
(
887+
BlockInfo::new(
888+
block_proposal.clone(),
889+
Secp256k1PublicKey::from_private(&Secp256k1PrivateKey::new()),
890+
),
891+
block_proposal,
892+
)
883893
}
884894

885895
fn create_block() -> (BlockInfo, BlockProposal) {
@@ -896,6 +906,7 @@ mod tests {
896906
fn test_basic_signer_db_with_path(db_path: impl AsRef<Path>) {
897907
let mut db = SignerDb::new(db_path).expect("Failed to create signer db");
898908
let (block_info, block_proposal) = create_block();
909+
let miner_pubkey = block_info.miner_pubkey;
899910
let reward_cycle = block_info.reward_cycle;
900911
db.insert_block(&block_info)
901912
.expect("Unable to insert block into db");
@@ -907,7 +918,10 @@ mod tests {
907918
.unwrap()
908919
.expect("Unable to get block from db");
909920

910-
assert_eq!(BlockInfo::from(block_proposal.clone()), block_info);
921+
assert_eq!(
922+
BlockInfo::new(block_proposal.clone(), miner_pubkey),
923+
block_info
924+
);
911925

912926
// Test looking up a block from a different reward cycle
913927
let block_info = db
@@ -927,7 +941,10 @@ mod tests {
927941
.unwrap()
928942
.expect("Unable to get block state from db");
929943

930-
assert_eq!(block_state, BlockInfo::from(block_proposal.clone()).state);
944+
assert_eq!(
945+
block_state,
946+
BlockInfo::new(block_proposal.clone(), miner_pubkey).state
947+
);
931948
}
932949

933950
#[test]
@@ -947,6 +964,7 @@ mod tests {
947964
let db_path = tmp_db_path();
948965
let mut db = SignerDb::new(db_path).expect("Failed to create signer db");
949966
let (block_info, block_proposal) = create_block();
967+
let miner_pubkey = block_info.miner_pubkey;
950968
let reward_cycle = block_info.reward_cycle;
951969
db.insert_block(&block_info)
952970
.expect("Unable to insert block into db");
@@ -959,7 +977,10 @@ mod tests {
959977
.unwrap()
960978
.expect("Unable to get block from db");
961979

962-
assert_eq!(BlockInfo::from(block_proposal.clone()), block_info);
980+
assert_eq!(
981+
BlockInfo::new(block_proposal.clone(), miner_pubkey),
982+
block_info
983+
);
963984

964985
let old_block_info = block_info;
965986
let old_block_proposal = block_proposal;

stacks-signer/src/tests/chainstate.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ fn reorg_timing_testing(
247247
reward_cycle: 1,
248248
};
249249
let mut header_clone = block_proposal_1.block.header.clone();
250-
let mut block_info_1 = BlockInfo::from(block_proposal_1);
250+
let mut block_info_1 = BlockInfo::new(block_proposal_1, block_pk);
251251
block_info_1.mark_locally_accepted(false).unwrap();
252252
signer_db.insert_block(&block_info_1).unwrap();
253253

@@ -457,8 +457,12 @@ fn check_sortition_timeout() {
457457
fs::create_dir_all(signer_db_dir).unwrap();
458458
let mut signer_db = SignerDb::new(signer_db_path).unwrap();
459459

460+
let block_sk = StacksPrivateKey::from_seed(&[0, 1]);
461+
let block_pk = StacksPublicKey::from_private(&block_sk);
462+
let block_pkh = Hash160::from_node_public_key(&block_pk);
463+
460464
let mut sortition = SortitionState {
461-
miner_pkh: Hash160([0; 20]),
465+
miner_pkh: block_pkh,
462466
miner_pubkey: None,
463467
prior_sortition: ConsensusHash([0; 20]),
464468
parent_tenure_id: ConsensusHash([0; 20]),
@@ -514,7 +518,7 @@ fn check_sortition_timeout() {
514518
reward_cycle: 1,
515519
};
516520

517-
let mut block_info = BlockInfo::from(block_proposal);
521+
let mut block_info = BlockInfo::new(block_proposal, block_pk);
518522
block_info.signed_over = true;
519523
signer_db.insert_block(&block_info).unwrap();
520524

0 commit comments

Comments
 (0)