Skip to content

Commit 209fb60

Browse files
committed
Merge branch 'develop' of https://github.com/stacks-network/stacks-core into fix/remove-stale-signers
2 parents a81f719 + 9e9d97e commit 209fb60

File tree

13 files changed

+196
-43
lines changed

13 files changed

+196
-43
lines changed

.github/workflows/bitcoin-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ jobs:
130130
- tests::signer::v0::continue_after_fast_block_no_sortition
131131
- tests::signer::v0::block_validation_response_timeout
132132
- tests::signer::v0::tenure_extend_after_bad_commit
133+
- tests::signer::v0::block_proposal_max_age_rejections
133134
- tests::nakamoto_integrations::burn_ops_integration_test
134135
- tests::nakamoto_integrations::check_block_heights
135136
- tests::nakamoto_integrations::clarity_burn_state

clarity/src/vm/contexts.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ impl EventBatch {
499499

500500
impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> {
501501
#[cfg(any(test, feature = "testing"))]
502-
pub fn new(database: ClarityDatabase<'a>, epoch: StacksEpochId) -> OwnedEnvironment<'a, '_> {
502+
pub fn new(database: ClarityDatabase<'a>, epoch: StacksEpochId) -> OwnedEnvironment<'a, 'a> {
503503
OwnedEnvironment {
504504
context: GlobalContext::new(
505505
false,
@@ -513,7 +513,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> {
513513
}
514514

515515
#[cfg(any(test, feature = "testing"))]
516-
pub fn new_toplevel(mut database: ClarityDatabase<'a>) -> OwnedEnvironment<'a, '_> {
516+
pub fn new_toplevel(mut database: ClarityDatabase<'a>) -> OwnedEnvironment<'a, 'a> {
517517
database.begin();
518518
let epoch = database.get_clarity_epoch_version().unwrap();
519519
let version = ClarityVersion::default_for_epoch(epoch);
@@ -540,7 +540,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> {
540540
mut database: ClarityDatabase<'a>,
541541
epoch: StacksEpochId,
542542
use_mainnet: bool,
543-
) -> OwnedEnvironment<'a, '_> {
543+
) -> OwnedEnvironment<'a, 'a> {
544544
use crate::vm::tests::test_only_mainnet_to_chain_id;
545545
let cost_track = LimitedCostTracker::new_max_limit(&mut database, epoch, use_mainnet)
546546
.expect("FAIL: problem instantiating cost tracking");
@@ -557,7 +557,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> {
557557
chain_id: u32,
558558
database: ClarityDatabase<'a>,
559559
epoch_id: StacksEpochId,
560-
) -> OwnedEnvironment<'a, '_> {
560+
) -> OwnedEnvironment<'a, 'a> {
561561
OwnedEnvironment {
562562
context: GlobalContext::new(
563563
mainnet,
@@ -576,7 +576,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> {
576576
database: ClarityDatabase<'a>,
577577
cost_tracker: LimitedCostTracker,
578578
epoch_id: StacksEpochId,
579-
) -> OwnedEnvironment<'a, '_> {
579+
) -> OwnedEnvironment<'a, 'a> {
580580
OwnedEnvironment {
581581
context: GlobalContext::new(mainnet, chain_id, database, cost_tracker, epoch_id),
582582
call_stack: CallStack::new(),
@@ -1546,7 +1546,7 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> {
15461546
database: ClarityDatabase<'a>,
15471547
cost_track: LimitedCostTracker,
15481548
epoch_id: StacksEpochId,
1549-
) -> GlobalContext {
1549+
) -> GlobalContext<'a, 'hooks> {
15501550
GlobalContext {
15511551
database,
15521552
cost_track,

clarity/src/vm/database/key_value_wrapper.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ where
205205
}
206206

207207
impl<'a> RollbackWrapper<'a> {
208-
pub fn new(store: &'a mut dyn ClarityBackingStore) -> RollbackWrapper {
208+
pub fn new(store: &'a mut dyn ClarityBackingStore) -> RollbackWrapper<'a> {
209209
RollbackWrapper {
210210
store,
211211
lookup_map: HashMap::new(),
@@ -218,7 +218,7 @@ impl<'a> RollbackWrapper<'a> {
218218
pub fn from_persisted_log(
219219
store: &'a mut dyn ClarityBackingStore,
220220
log: RollbackWrapperPersistedLog,
221-
) -> RollbackWrapper {
221+
) -> RollbackWrapper<'a> {
222222
RollbackWrapper {
223223
store,
224224
lookup_map: log.lookup_map,

stacks-signer/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
99

1010
## Added
1111

12+
- Introduced the `block_proposal_max_age_secs` configuration option for signers, enabling them to automatically ignore block proposals that exceed the specified age in seconds.
13+
1214
## Changed
1315
- Improvements to the stale signer cleanup logic: deletes the prior signer if it has no remaining unprocessed blocks in its database
1416

stacks-signer/src/chainstate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ impl SortitionsView {
367367
tenure_extend.burn_view_consensus_hash != sortition_consensus_hash;
368368
let extend_timestamp = signer_db.calculate_tenure_extend_timestamp(
369369
self.config.tenure_idle_timeout,
370-
&block,
370+
block,
371371
false,
372372
);
373373
let epoch_time = get_epoch_time_secs();

stacks-signer/src/client/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ pub(crate) mod tests {
414414
tenure_last_block_proposal_timeout: config.tenure_last_block_proposal_timeout,
415415
block_proposal_validation_timeout: config.block_proposal_validation_timeout,
416416
tenure_idle_timeout: config.tenure_idle_timeout,
417+
block_proposal_max_age_secs: config.block_proposal_max_age_secs,
417418
}
418419
}
419420

stacks-signer/src/config.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const BLOCK_PROPOSAL_VALIDATION_TIMEOUT_MS: u64 = 120_000;
3939
const DEFAULT_FIRST_PROPOSAL_BURN_BLOCK_TIMING_SECS: u64 = 60;
4040
const DEFAULT_TENURE_LAST_BLOCK_PROPOSAL_TIMEOUT_SECS: u64 = 30;
4141
const TENURE_IDLE_TIMEOUT_SECS: u64 = 300;
42+
const DEFAULT_BLOCK_PROPOSAL_MAX_AGE_SECS: u64 = 600;
4243

4344
#[derive(thiserror::Error, Debug)]
4445
/// An error occurred parsing the provided configuration
@@ -138,6 +139,8 @@ pub struct SignerConfig {
138139
pub block_proposal_validation_timeout: Duration,
139140
/// How much idle time must pass before allowing a tenure extend
140141
pub tenure_idle_timeout: Duration,
142+
/// The maximum age of a block proposal in seconds that will be processed by the signer
143+
pub block_proposal_max_age_secs: u64,
141144
}
142145

143146
/// The parsed configuration for the signer
@@ -176,6 +179,8 @@ pub struct GlobalConfig {
176179
pub block_proposal_validation_timeout: Duration,
177180
/// How much idle time must pass before allowing a tenure extend
178181
pub tenure_idle_timeout: Duration,
182+
/// The maximum age of a block proposal that will be processed by the signer
183+
pub block_proposal_max_age_secs: u64,
179184
}
180185

181186
/// Internal struct for loading up the config file
@@ -213,6 +218,8 @@ struct RawConfigFile {
213218
pub block_proposal_validation_timeout_ms: Option<u64>,
214219
/// How much idle time (in seconds) must pass before a tenure extend is allowed
215220
pub tenure_idle_timeout_secs: Option<u64>,
221+
/// The maximum age of a block proposal (in secs) that will be processed by the signer.
222+
pub block_proposal_max_age_secs: Option<u64>,
216223
}
217224

218225
impl RawConfigFile {
@@ -310,6 +317,10 @@ impl TryFrom<RawConfigFile> for GlobalConfig {
310317
.unwrap_or(TENURE_IDLE_TIMEOUT_SECS),
311318
);
312319

320+
let block_proposal_max_age_secs = raw_data
321+
.block_proposal_max_age_secs
322+
.unwrap_or(DEFAULT_BLOCK_PROPOSAL_MAX_AGE_SECS);
323+
313324
Ok(Self {
314325
node_host: raw_data.node_host,
315326
endpoint,
@@ -326,6 +337,7 @@ impl TryFrom<RawConfigFile> for GlobalConfig {
326337
tenure_last_block_proposal_timeout,
327338
block_proposal_validation_timeout,
328339
tenure_idle_timeout,
340+
block_proposal_max_age_secs,
329341
})
330342
}
331343
}

stacks-signer/src/runloop.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ impl<Signer: SignerTrait<T>, T: StacksMessageCodec + Clone + Send + Debug> RunLo
286286
tenure_last_block_proposal_timeout: self.config.tenure_last_block_proposal_timeout,
287287
block_proposal_validation_timeout: self.config.block_proposal_validation_timeout,
288288
tenure_idle_timeout: self.config.tenure_idle_timeout,
289+
block_proposal_max_age_secs: self.config.block_proposal_max_age_secs,
289290
}))
290291
}
291292

stacks-signer/src/v0/signer.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ pub struct Signer {
9292
pub block_proposal_validation_timeout: Duration,
9393
/// The current submitted block proposal and its submission time
9494
pub submitted_block_proposal: Option<(BlockProposal, Instant)>,
95+
/// Maximum age of a block proposal in seconds before it is dropped without processing
96+
pub block_proposal_max_age_secs: u64,
9597
}
9698

9799
impl std::fmt::Display for Signer {
@@ -284,6 +286,7 @@ impl From<SignerConfig> for Signer {
284286
proposal_config,
285287
submitted_block_proposal: None,
286288
block_proposal_validation_timeout: signer_config.block_proposal_validation_timeout,
289+
block_proposal_max_age_secs: signer_config.block_proposal_max_age_secs,
287290
}
288291
}
289292
}
@@ -344,6 +347,24 @@ impl Signer {
344347
return;
345348
}
346349

350+
if block_proposal
351+
.block
352+
.header
353+
.timestamp
354+
.saturating_add(self.block_proposal_max_age_secs)
355+
< get_epoch_time_secs()
356+
{
357+
// Block is too old. Drop it with a warning. Don't even bother broadcasting to the node.
358+
warn!("{self}: Received a block proposal that is more than {} secs old. Ignoring...", self.block_proposal_max_age_secs;
359+
"signer_sighash" => %block_proposal.block.header.signer_signature_hash(),
360+
"block_id" => %block_proposal.block.block_id(),
361+
"block_height" => block_proposal.block.header.chain_length,
362+
"burn_height" => block_proposal.burn_height,
363+
"timestamp" => block_proposal.block.header.timestamp,
364+
);
365+
return;
366+
}
367+
347368
// TODO: should add a check to ignore an old burn block height if we know its outdated. Would require us to store the burn block height we last saw on the side.
348369
// the signer needs to be able to determine whether or not the block they're about to sign would conflict with an already-signed Stacks block
349370
let signer_signature_hash = block_proposal.block.header.signer_signature_hash();

stackslib/src/burnchains/bitcoin/indexer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ impl BitcoinIndexer {
924924
return Ok(());
925925
}
926926
warn!(
927-
"Header at height {} is not wihtin 2 hours of now (is at {})",
927+
"Header at height {} is not within 2 hours of now (is at {})",
928928
highest_header_height, highest_header.block_header.header.time
929929
);
930930
self.drop_headers(highest_header_height.saturating_sub(1))?;

0 commit comments

Comments
 (0)