Skip to content

Commit

Permalink
Merge branch 'develop' into fix/5642
Browse files Browse the repository at this point in the history
  • Loading branch information
jcnelson authored Feb 6, 2025
2 parents 5e6f6bd + 760891f commit 447ba1f
Show file tree
Hide file tree
Showing 18 changed files with 659 additions and 93 deletions.
17 changes: 9 additions & 8 deletions .github/workflows/pr-differences-mutants.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
name: PR Differences Mutants

on:
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
paths:
- '**.rs'
# Disabling PR mutants (issue #5806)
# pull_request:
# types:
# - opened
# - reopened
# - synchronize
# - ready_for_review
# paths:
# - '**.rs'
workflow_dispatch:

concurrency:
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE

### Fixed

- Error responses to /v2/transactions/fees are once again expressed as JSON ([#4145](https://github.com/stacks-network/stacks-core/issues/4145)).

## [3.1.0.0.5]

### Added
Expand Down
8 changes: 7 additions & 1 deletion stacks-signer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE

## [Unreleased]

### Added
## Added

- Introduced the `reorg_attempts_activity_timeout_ms` configuration option for signers which is used to determine the length of time after the last block of a tenure is confirmed that an incoming miner's attempts to reorg it are considered valid miner activity.

### Changed

- Increase default `block_proposal_timeout_ms` from 10 minutes to 4 hours. Until #5729 is implemented, there is no value in rejecting a late block from a miner, since a late block is better than no block at all.

- Signers no longer view any block proposal by a miner in their DB as indicative of valid miner activity.

## [3.1.0.0.5.0]

### Added
Expand Down
40 changes: 32 additions & 8 deletions stacks-signer/src/chainstate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,23 +89,25 @@ impl SortitionState {
if self.miner_status != SortitionMinerStatus::Valid {
return Ok(false);
}
// if we've already seen a proposed block from this miner. It cannot have timed out.
let has_blocks = signer_db.has_proposed_block_in_tenure(&self.consensus_hash)?;
if has_blocks {
// if we've already signed a block in this tenure, the miner can't have timed out.
let has_block = signer_db.has_signed_block_in_tenure(&self.consensus_hash)?;
if has_block {
return Ok(false);
}
let Some(received_ts) = signer_db.get_burn_block_receive_time(&self.burn_block_hash)?
else {
return Ok(false);
};
let received_time = UNIX_EPOCH + Duration::from_secs(received_ts);
let Ok(elapsed) = std::time::SystemTime::now().duration_since(received_time) else {
let last_activity = signer_db
.get_last_activity_time(&self.consensus_hash)?
.map(|time| UNIX_EPOCH + Duration::from_secs(time))
.unwrap_or(received_time);

let Ok(elapsed) = std::time::SystemTime::now().duration_since(last_activity) else {
return Ok(false);
};
if elapsed > timeout {
return Ok(true);
}
Ok(false)
Ok(elapsed > timeout)
}
}

Expand All @@ -122,6 +124,9 @@ pub struct ProposalEvalConfig {
pub tenure_last_block_proposal_timeout: Duration,
/// How much idle time must pass before allowing a tenure extend
pub tenure_idle_timeout: Duration,
/// Time following the last block of the previous tenure's global acceptance that a signer will consider an attempt by
/// the new miner to reorg it as valid towards miner activity
pub reorg_attempts_activity_timeout: Duration,
}

impl From<&SignerConfig> for ProposalEvalConfig {
Expand All @@ -131,6 +136,7 @@ impl From<&SignerConfig> for ProposalEvalConfig {
block_proposal_timeout: value.block_proposal_timeout,
tenure_last_block_proposal_timeout: value.tenure_last_block_proposal_timeout,
tenure_idle_timeout: value.tenure_idle_timeout,
reorg_attempts_activity_timeout: value.reorg_attempts_activity_timeout,
}
}
}
Expand Down Expand Up @@ -545,8 +551,10 @@ impl SortitionsView {
signer_db: &mut SignerDb,
client: &StacksClient,
tenure_last_block_proposal_timeout: Duration,
reorg_attempts_activity_timeout: Duration,
) -> Result<bool, ClientError> {
// 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.
// NOTE: returns the locally accepted block if it is not timed out, otherwise it will return the last globally accepted block.
let last_block_info = Self::get_tenure_last_block_info(
&tenure_change.prev_tenure_consensus_hash,
signer_db,
Expand All @@ -566,6 +574,21 @@ impl SortitionsView {
"proposed_chain_length" => block.header.chain_length,
"expected_at_least" => info.block.header.chain_length + 1,
);
if info.signed_group.map_or(true, |signed_time| {
signed_time + reorg_attempts_activity_timeout.as_secs() > get_epoch_time_secs()
}) {
// Note if there is no signed_group time, this is a locally accepted block (i.e. tenure_last_block_proposal_timeout has not been exceeded).
// Treat any attempt to reorg a locally accepted block as valid miner activity.
// If the call returns a globally accepted block, check its globally accepted time against a quarter of the block_proposal_timeout
// to give the miner some extra buffer time to wait for its chain tip to advance
// The miner may just be slow, so count this invalid block proposal towards valid miner activity.
if let Err(e) = signer_db.update_last_activity_time(
&tenure_change.tenure_consensus_hash,
get_epoch_time_secs(),
) {
warn!("Failed to update last activity time: {e}");
}
}
return Ok(false);
}
}
Expand Down Expand Up @@ -631,6 +654,7 @@ impl SortitionsView {
signer_db,
client,
self.config.tenure_last_block_proposal_timeout,
self.config.reorg_attempts_activity_timeout,
)?;
if !confirms_expected_parent {
return Ok(false);
Expand Down
1 change: 1 addition & 0 deletions stacks-signer/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ pub(crate) mod tests {
block_proposal_validation_timeout: config.block_proposal_validation_timeout,
tenure_idle_timeout: config.tenure_idle_timeout,
block_proposal_max_age_secs: config.block_proposal_max_age_secs,
reorg_attempts_activity_timeout: config.reorg_attempts_activity_timeout,
}
}

Expand Down
19 changes: 18 additions & 1 deletion stacks-signer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ use stacks_common::util::hash::Hash160;
use crate::client::SignerSlotID;

const EVENT_TIMEOUT_MS: u64 = 5000;
const BLOCK_PROPOSAL_TIMEOUT_MS: u64 = 600_000;
const BLOCK_PROPOSAL_TIMEOUT_MS: u64 = 14_400_000;
const BLOCK_PROPOSAL_VALIDATION_TIMEOUT_MS: u64 = 120_000;
const DEFAULT_FIRST_PROPOSAL_BURN_BLOCK_TIMING_SECS: u64 = 60;
const DEFAULT_TENURE_LAST_BLOCK_PROPOSAL_TIMEOUT_SECS: u64 = 30;
const DEFAULT_DRY_RUN: bool = false;
const TENURE_IDLE_TIMEOUT_SECS: u64 = 120;
const DEFAULT_REORG_ATTEMPTS_ACTIVITY_TIMEOUT_MS: u64 = 200_000;

#[derive(thiserror::Error, Debug)]
/// An error occurred parsing the provided configuration
Expand Down Expand Up @@ -163,6 +164,9 @@ pub struct SignerConfig {
pub tenure_idle_timeout: Duration,
/// The maximum age of a block proposal in seconds that will be processed by the signer
pub block_proposal_max_age_secs: u64,
/// Time following the last block of the previous tenure's global acceptance that a signer will consider an attempt by
/// the new miner to reorg it as valid towards miner activity
pub reorg_attempts_activity_timeout: Duration,
/// The running mode for the signer (dry-run or normal)
pub signer_mode: SignerConfigMode,
}
Expand Down Expand Up @@ -205,6 +209,9 @@ pub struct GlobalConfig {
pub tenure_idle_timeout: Duration,
/// The maximum age of a block proposal that will be processed by the signer
pub block_proposal_max_age_secs: u64,
/// Time following the last block of the previous tenure's global acceptance that a signer will consider an attempt by
/// the new miner to reorg it as valid towards miner activity
pub reorg_attempts_activity_timeout: Duration,
/// Is this signer binary going to be running in dry-run mode?
pub dry_run: bool,
}
Expand Down Expand Up @@ -246,6 +253,9 @@ struct RawConfigFile {
pub tenure_idle_timeout_secs: Option<u64>,
/// The maximum age of a block proposal (in secs) that will be processed by the signer.
pub block_proposal_max_age_secs: Option<u64>,
/// Time (in millisecs) following a block's global acceptance that a signer will consider an attempt by a miner
/// to reorg the block as valid towards miner activity
pub reorg_attempts_activity_timeout_ms: Option<u64>,
/// Is this signer binary going to be running in dry-run mode?
pub dry_run: Option<bool>,
}
Expand Down Expand Up @@ -349,6 +359,12 @@ impl TryFrom<RawConfigFile> for GlobalConfig {
.block_proposal_max_age_secs
.unwrap_or(DEFAULT_BLOCK_PROPOSAL_MAX_AGE_SECS);

let reorg_attempts_activity_timeout = Duration::from_millis(
raw_data
.reorg_attempts_activity_timeout_ms
.unwrap_or(DEFAULT_REORG_ATTEMPTS_ACTIVITY_TIMEOUT_MS),
);

let dry_run = raw_data.dry_run.unwrap_or(DEFAULT_DRY_RUN);

Ok(Self {
Expand All @@ -368,6 +384,7 @@ impl TryFrom<RawConfigFile> for GlobalConfig {
block_proposal_validation_timeout,
tenure_idle_timeout,
block_proposal_max_age_secs,
reorg_attempts_activity_timeout,
dry_run,
})
}
Expand Down
1 change: 1 addition & 0 deletions stacks-signer/src/runloop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ impl<Signer: SignerTrait<T>, T: StacksMessageCodec + Clone + Send + Debug> RunLo
block_proposal_validation_timeout: self.config.block_proposal_validation_timeout,
tenure_idle_timeout: self.config.tenure_idle_timeout,
block_proposal_max_age_secs: self.config.block_proposal_max_age_secs,
reorg_attempts_activity_timeout: self.config.reorg_attempts_activity_timeout,
}))
}

Expand Down
Loading

0 comments on commit 447ba1f

Please sign in to comment.