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

feat: gather v0 block signatures from stackerdb #4807

Merged
merged 11 commits into from
May 31, 2024
Merged
1 change: 1 addition & 0 deletions .github/workflows/bitcoin-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ jobs:
- tests::nakamoto_integrations::follower_bootup
- tests::nakamoto_integrations::forked_tenure_is_ignored
- tests::signer::v0::block_proposal_rejection
- tests::signer::v0::miner_gather_signatures
- tests::signer::v1::dkg
- tests::signer::v1::sign_request_rejected
# TODO: enable these once v1 signer is fixed
Expand Down
7 changes: 6 additions & 1 deletion stacks-signer/src/monitoring/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,12 @@ impl MonitoringServer {
public_key,
format!("http://{}", config.node_host),
);
server.update_metrics()?;
if let Err(e) = server.update_metrics() {
warn!(
"Monitoring: Error updating metrics when starting server: {:?}",
e
);
};
server.main_loop()
}

Expand Down
13 changes: 10 additions & 3 deletions stacks-signer/src/v0/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ impl Signer {
"block_id" => %block_proposal.block.block_id(),
);
let block_info = BlockInfo::from(block_proposal.clone());
crate::monitoring::increment_block_proposals_received();
stacks_client
.submit_block_for_validation(block_info.block.clone())
.unwrap_or_else(|e| {
Expand Down Expand Up @@ -312,11 +313,17 @@ impl Signer {
};
// Submit a proposal response to the .signers contract for miners
debug!("{self}: Broadcasting a block response to stacks node: {response:?}");
if let Err(e) = self
match self
.stackerdb
.send_message_with_retry::<SignerMessage>(response.into())
.send_message_with_retry::<SignerMessage>(response.clone().into())
{
warn!("{self}: Failed to send block rejection to stacker-db: {e:?}",);
Ok(_) => {
let accepted = matches!(response, BlockResponse::Accepted(..));
crate::monitoring::increment_block_responses_sent(accepted);
}
Err(e) => {
warn!("{self}: Failed to send block rejection to stacker-db: {e:?}",);
}
}
self.signer_db
.insert_block(&block_info)
Expand Down
7 changes: 3 additions & 4 deletions stackslib/src/chainstate/nakamoto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,10 +516,9 @@ impl NakamotoBlockHeader {
// `last_index` is used to prevent out-of-order signatures
let mut last_index = None;

let total_weight = signers.iter().map(|s| s.weight).fold(0, |w, acc| {
acc.checked_add(w)
.expect("FATAL: Total signer weight > u32::MAX")
});
let total_weight = reward_set
.total_signing_weight()
.map_err(|_| ChainstateError::NoRegisteredSigners(0))?;

// HashMap of <PublicKey, (Signer, Index)>
let signers_by_pk: HashMap<_, _> = signers
Expand Down
17 changes: 17 additions & 0 deletions stackslib/src/chainstate/stacks/boot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,23 @@ impl RewardSet {
pub fn metadata_deserialize(from: &str) -> Result<RewardSet, String> {
serde_json::from_str(from).map_err(|e| e.to_string())
}

/// Return the total `weight` of all signers in the reward set.
/// If there are no reward set signers, a ChainstateError is returned.
pub fn total_signing_weight(&self) -> Result<u32, String> {
let Some(ref reward_set_signers) = self.signers else {
return Err(format!(
"Unable to calculate total weight - No signers in reward set"
));
};
Ok(reward_set_signers
.iter()
.map(|s| s.weight)
.fold(0, |s, acc| {
acc.checked_add(s)
.expect("FATAL: Total signer weight > u32::MAX")
}))
}
}

impl RewardSetData {
Expand Down
2 changes: 1 addition & 1 deletion testnet/stacks-node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ name = "stacks-events"
path = "src/stacks_events.rs"

[features]
monitoring_prom = ["stacks/monitoring_prom", "libsigner/monitoring_prom"]
monitoring_prom = ["stacks/monitoring_prom", "libsigner/monitoring_prom", "stacks-signer/monitoring_prom"]
slog_json = ["stacks/slog_json", "stacks-common/slog_json", "clarity/slog_json"]
prod-genesis-chainstate = []
default = []
96 changes: 40 additions & 56 deletions testnet/stacks-node/src/nakamoto_node/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,15 @@ impl BlockMinerThread {
self.mined_blocks.push(new_block);
}

let sort_db = SortitionDB::open(
let Ok(sort_db) = SortitionDB::open(
&self.config.get_burn_db_file_path(),
true,
self.burnchain.pox_constants.clone(),
)
.expect("FATAL: could not open sortition DB");
) else {
error!("Failed to open sortition DB. Will try mining again.");
continue;
};

let wait_start = Instant::now();
while wait_start.elapsed() < self.config.miner.wait_on_interim_blocks {
thread::sleep(Duration::from_millis(ABORT_TRY_AGAIN_MS));
Expand Down Expand Up @@ -277,19 +280,6 @@ impl BlockMinerThread {
})
})?;

let reward_cycle = self
.burnchain
.pox_constants
.block_height_to_reward_cycle(
self.burnchain.first_block_height,
self.burn_block.block_height,
)
.ok_or_else(|| {
NakamotoNodeError::SigningCoordinatorFailure(
"Building on a burn block that is before the first burn block".into(),
)
})?;

let reward_info = match sort_db.get_preprocessed_reward_set_of(&tip.sortition_id) {
Ok(x) => x,
Err(e) => {
Expand All @@ -308,20 +298,14 @@ impl BlockMinerThread {
// NOTE: this is a placeholder until the API can be fixed
let aggregate_public_key = Point::new();
let miner_privkey_as_scalar = Scalar::from(miner_privkey.as_slice().clone());
let mut coordinator = SignCoordinator::new(
&reward_set,
reward_cycle,
miner_privkey_as_scalar,
// TODO: placeholder until the signer is working
aggregate_public_key,
&stackerdbs,
&self.config,
)
.map_err(|e| {
NakamotoNodeError::SigningCoordinatorFailure(format!(
"Failed to initialize the signing coordinator. Cannot mine! {e:?}"
))
})?;
let mut coordinator =
SignCoordinator::new(&reward_set, miner_privkey_as_scalar, &self.config).map_err(
|e| {
NakamotoNodeError::SigningCoordinatorFailure(format!(
"Failed to initialize the signing coordinator. Cannot mine! {e:?}"
))
},
)?;

*attempts += 1;
let signature = coordinator.begin_sign_v1(
Expand All @@ -338,7 +322,7 @@ impl BlockMinerThread {
Ok((aggregate_public_key, signature))
}

/// Gather signatures from the signers for the block
/// Gather a list of signatures from the signers for the block
fn gather_signatures(
&mut self,
new_block: &mut NakamotoBlock,
Expand All @@ -356,22 +340,27 @@ impl BlockMinerThread {
true,
self.burnchain.pox_constants.clone(),
)
.expect("FATAL: could not open sortition DB");
.map_err(|e| {
NakamotoNodeError::SigningCoordinatorFailure(format!(
"Failed to open sortition DB. Cannot mine! {e:?}"
))
})?;

let tip = SortitionDB::get_block_snapshot_consensus(
sort_db.conn(),
&new_block.header.consensus_hash,
)
.expect("FATAL: could not retrieve chain tip")
.expect("FATAL: could not retrieve chain tip");

let reward_cycle = self
.burnchain
.pox_constants
.block_height_to_reward_cycle(
self.burnchain.first_block_height,
self.burn_block.block_height,
)
.expect("FATAL: building on a burn block that is before the first burn block");
.map_err(|e| {
NakamotoNodeError::SigningCoordinatorFailure(format!(
"Failed to retrieve chain tip: {:?}",
e
))
})
.and_then(|result| {
result.ok_or_else(|| {
NakamotoNodeError::SigningCoordinatorFailure("Failed to retrieve chain tip".into())
})
})?;

let reward_info = match sort_db.get_preprocessed_reward_set_of(&tip.sortition_id) {
Ok(x) => x,
Expand All @@ -389,19 +378,14 @@ impl BlockMinerThread {
};

let miner_privkey_as_scalar = Scalar::from(miner_privkey.as_slice().clone());
let mut coordinator = SignCoordinator::new(
&reward_set,
reward_cycle,
miner_privkey_as_scalar,
Point::new(),
&stackerdbs,
&self.config,
)
.map_err(|e| {
NakamotoNodeError::SigningCoordinatorFailure(format!(
"Failed to initialize the signing coordinator. Cannot mine! {e:?}"
))
})?;
let mut coordinator =
SignCoordinator::new(&reward_set, miner_privkey_as_scalar, &self.config).map_err(
|e| {
NakamotoNodeError::SigningCoordinatorFailure(format!(
"Failed to initialize the signing coordinator. Cannot mine! {e:?}"
))
},
)?;

*attempts += 1;
let signature = coordinator.begin_sign_v0(
Expand Down
Loading