Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add timestamp calculation to all block responses #5470

1 change: 1 addition & 0 deletions stacks-signer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
### Changed

- Add tenure extend timestamp to signer block responses
- Added tenure_idle_timeout_secs configuration option for determining when a tenure extend will be accepted

## [3.0.0.0.1.0]

Expand Down
3 changes: 3 additions & 0 deletions stacks-signer/src/chainstate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ pub struct ProposalEvalConfig {
/// Time to wait for the last block of a tenure to be globally accepted or rejected before considering
/// a new miner's block at the same height as valid.
pub tenure_last_block_proposal_timeout: Duration,
/// How much idle time must pass before allowing a tenure extend
pub tenure_idle_timeout: Duration,
}

impl From<&SignerConfig> for ProposalEvalConfig {
Expand All @@ -130,6 +132,7 @@ impl From<&SignerConfig> for ProposalEvalConfig {
first_proposal_burn_block_timing: value.first_proposal_burn_block_timing,
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,
}
}
}
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 @@ -413,6 +413,7 @@ pub(crate) mod tests {
block_proposal_timeout: config.block_proposal_timeout,
tenure_last_block_proposal_timeout: config.tenure_last_block_proposal_timeout,
block_proposal_validation_timeout: config.block_proposal_validation_timeout,
tenure_idle_timeout: config.tenure_idle_timeout,
}
}

Expand Down
14 changes: 14 additions & 0 deletions stacks-signer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const BLOCK_PROPOSAL_TIMEOUT_MS: u64 = 600_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 TENURE_IDLE_TIMEOUT_SECS: u64 = 300;

#[derive(thiserror::Error, Debug)]
/// An error occurred parsing the provided configuration
Expand Down Expand Up @@ -135,6 +136,8 @@ pub struct SignerConfig {
pub tenure_last_block_proposal_timeout: Duration,
/// How much time to wait for a block proposal validation response before marking the block invalid
pub block_proposal_validation_timeout: Duration,
/// How much idle time must pass before allowing a tenure extend
pub tenure_idle_timeout: Duration,
}

/// The parsed configuration for the signer
Expand Down Expand Up @@ -171,6 +174,8 @@ pub struct GlobalConfig {
/// How long to wait for a response from a block proposal validation response from the node
/// before marking that block as invalid and rejecting it
pub block_proposal_validation_timeout: Duration,
/// How much idle time must pass before allowing a tenure extend
pub tenure_idle_timeout: Duration,
}

/// Internal struct for loading up the config file
Expand Down Expand Up @@ -206,6 +211,8 @@ struct RawConfigFile {
/// How long to wait (in millisecs) for a response from a block proposal validation response from the node
/// before marking that block as invalid and rejecting it
pub block_proposal_validation_timeout_ms: Option<u64>,
/// How much idle time (in seconds) must pass before a tenure extend is allowed
pub tenure_idle_timeout_secs: Option<u64>,
}

impl RawConfigFile {
Expand Down Expand Up @@ -297,6 +304,12 @@ impl TryFrom<RawConfigFile> for GlobalConfig {
.unwrap_or(BLOCK_PROPOSAL_VALIDATION_TIMEOUT_MS),
);

let tenure_idle_timeout = Duration::from_secs(
raw_data
.tenure_idle_timeout_secs
.unwrap_or(TENURE_IDLE_TIMEOUT_SECS),
);

Ok(Self {
node_host: raw_data.node_host,
endpoint,
Expand All @@ -312,6 +325,7 @@ impl TryFrom<RawConfigFile> for GlobalConfig {
chain_id: raw_data.chain_id,
tenure_last_block_proposal_timeout,
block_proposal_validation_timeout,
tenure_idle_timeout,
})
}
}
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 @@ -285,6 +285,7 @@ impl<Signer: SignerTrait<T>, T: StacksMessageCodec + Clone + Send + Debug> RunLo
block_proposal_timeout: self.config.block_proposal_timeout,
tenure_last_block_proposal_timeout: self.config.tenure_last_block_proposal_timeout,
block_proposal_validation_timeout: self.config.block_proposal_validation_timeout,
tenure_idle_timeout: self.config.tenure_idle_timeout,
}))
}

Expand Down
151 changes: 151 additions & 0 deletions stacks-signer/src/signerdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ pub struct BlockInfo {
pub signed_group: Option<u64>,
/// The block state relative to the signer's view of the stacks blockchain
pub state: BlockState,
/// Consumed processing time in milliseconds to validate this block
pub validation_time_ms: Option<u64>,
/// Extra data specific to v0, v1, etc.
pub ext: ExtraBlockInfo,
}
Expand All @@ -175,6 +177,7 @@ impl From<BlockProposal> for BlockInfo {
signed_group: None,
ext: ExtraBlockInfo::default(),
state: BlockState::Unprocessed,
validation_time_ms: None,
}
}
}
Expand Down Expand Up @@ -809,6 +812,20 @@ impl SignerDb {
BlockState::try_from(state.as_str()).map_err(|_| DBError::Corruption)?,
))
}

/// Return the all globally accepted block in a tenure (identified by its consensus hash).
pub fn get_globally_accepted_blocks(
&self,
tenure: &ConsensusHash,
) -> Result<Vec<BlockInfo>, DBError> {
let query = "SELECT block_info FROM blocks WHERE consensus_hash = ?1 AND json_extract(block_info, '$.state') = ?2 ORDER BY stacks_height DESC";
obycode marked this conversation as resolved.
Show resolved Hide resolved
let args = params![tenure, &BlockState::GloballyAccepted.to_string()];
let result: Vec<String> = query_rows(&self.db, query, args)?;
result
.iter()
.map(|info| serde_json::from_str(info).map_err(DBError::from))
.collect()
}
}

fn try_deserialize<T>(s: Option<String>) -> Result<Option<T>, DBError>
Expand Down Expand Up @@ -1185,6 +1202,7 @@ mod tests {
12345
);
}

#[test]
fn state_machine() {
let (mut block, _) = create_block();
Expand Down Expand Up @@ -1226,4 +1244,137 @@ mod tests {
assert!(!block.check_state(BlockState::GloballyAccepted));
assert!(block.check_state(BlockState::GloballyRejected));
}

#[test]
fn get_accepted_blocks() {
let db_path = tmp_db_path();
let mut db = SignerDb::new(db_path).expect("Failed to create signer db");
let consensus_hash_1 = ConsensusHash([0x01; 20]);
let consensus_hash_2 = ConsensusHash([0x02; 20]);
let consensus_hash_3 = ConsensusHash([0x03; 20]);
let (mut block_info_1, _block_proposal) = create_block_override(|b| {
b.block.header.consensus_hash = consensus_hash_1;
b.block.header.miner_signature = MessageSignature([0x01; 65]);
b.block.header.chain_length = 1;
b.burn_height = 1;
});
let (mut block_info_2, _block_proposal) = create_block_override(|b| {
b.block.header.consensus_hash = consensus_hash_1;
b.block.header.miner_signature = MessageSignature([0x02; 65]);
b.block.header.chain_length = 2;
b.burn_height = 2;
});
let (mut block_info_3, _block_proposal) = create_block_override(|b| {
b.block.header.consensus_hash = consensus_hash_1;
b.block.header.miner_signature = MessageSignature([0x03; 65]);
b.block.header.chain_length = 3;
b.burn_height = 3;
});
let (mut block_info_4, _block_proposal) = create_block_override(|b| {
b.block.header.consensus_hash = consensus_hash_2;
b.block.header.miner_signature = MessageSignature([0x03; 65]);
b.block.header.chain_length = 3;
b.burn_height = 4;
});
block_info_1.mark_globally_accepted().unwrap();
block_info_2.mark_locally_accepted(false).unwrap();
block_info_3.mark_locally_accepted(false).unwrap();
block_info_4.mark_globally_accepted().unwrap();

db.insert_block(&block_info_1).unwrap();
db.insert_block(&block_info_2).unwrap();
db.insert_block(&block_info_3).unwrap();
db.insert_block(&block_info_4).unwrap();

// Verify tenure consensus_hash_1
let block_info = db
.get_last_accepted_block(&consensus_hash_1)
.unwrap()
.unwrap();
assert_eq!(block_info, block_info_3);
let block_info = db
.get_last_globally_accepted_block(&consensus_hash_1)
.unwrap()
.unwrap();
assert_eq!(block_info, block_info_1);

// Verify tenure consensus_hash_2
let block_info = db
.get_last_accepted_block(&consensus_hash_2)
.unwrap()
.unwrap();
assert_eq!(block_info, block_info_4);
let block_info = db
.get_last_globally_accepted_block(&consensus_hash_2)
.unwrap()
.unwrap();
assert_eq!(block_info, block_info_4);

// Verify tenure consensus_hash_3
assert!(db
.get_last_accepted_block(&consensus_hash_3)
.unwrap()
.is_none());
assert!(db
.get_last_globally_accepted_block(&consensus_hash_3)
.unwrap()
.is_none());
}

#[test]
fn get_all_globally_accepted_blocks() {
let db_path = tmp_db_path();
let mut db = SignerDb::new(db_path).expect("Failed to create signer db");
let consensus_hash_1 = ConsensusHash([0x01; 20]);
let consensus_hash_2 = ConsensusHash([0x02; 20]);
let consensus_hash_3 = ConsensusHash([0x03; 20]);
let (mut block_info_1, _block_proposal) = create_block_override(|b| {
b.block.header.consensus_hash = consensus_hash_1;
b.block.header.miner_signature = MessageSignature([0x01; 65]);
b.block.header.chain_length = 1;
b.burn_height = 1;
});
let (mut block_info_2, _block_proposal) = create_block_override(|b| {
b.block.header.consensus_hash = consensus_hash_1;
b.block.header.miner_signature = MessageSignature([0x02; 65]);
b.block.header.chain_length = 2;
b.burn_height = 2;
});
let (mut block_info_3, _block_proposal) = create_block_override(|b| {
b.block.header.consensus_hash = consensus_hash_1;
b.block.header.miner_signature = MessageSignature([0x03; 65]);
b.block.header.chain_length = 3;
b.burn_height = 3;
});
let (mut block_info_4, _block_proposal) = create_block_override(|b| {
b.block.header.consensus_hash = consensus_hash_2;
b.block.header.miner_signature = MessageSignature([0x03; 65]);
b.block.header.chain_length = 3;
b.burn_height = 4;
});
block_info_1.mark_globally_accepted().unwrap();
block_info_2.mark_locally_accepted(false).unwrap();
block_info_3.mark_globally_accepted().unwrap();
block_info_4.mark_globally_accepted().unwrap();

db.insert_block(&block_info_1).unwrap();
db.insert_block(&block_info_2).unwrap();
db.insert_block(&block_info_3).unwrap();
db.insert_block(&block_info_4).unwrap();

// Verify tenure consensus_hash_1
let block_infos = db.get_globally_accepted_blocks(&consensus_hash_1).unwrap();
assert_eq!(block_infos, vec![block_info_3, block_info_1]);

// Verify tenure consensus_hash_2
let block_infos = db.get_globally_accepted_blocks(&consensus_hash_2).unwrap();
assert_eq!(block_infos.len(), 1);
assert_eq!(block_infos, vec![block_info_4]);

// Verify tenure consensus_hash_3
assert!(db
.get_globally_accepted_blocks(&consensus_hash_3)
.unwrap()
.is_empty());
}
}
1 change: 1 addition & 0 deletions stacks-signer/src/tests/chainstate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ fn setup_test_environment(
first_proposal_burn_block_timing: Duration::from_secs(30),
block_proposal_timeout: Duration::from_secs(5),
tenure_last_block_proposal_timeout: Duration::from_secs(30),
tenure_idle_timeout: Duration::from_secs(300),
},
};

Expand Down
Loading