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

Test/4976 signer set handoff #5037

Merged
merged 13 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/bitcoin-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ jobs:
- tests::signer::v0::bitcoind_forking_test
- tests::signer::v0::multiple_miners
- tests::signer::v0::mock_sign_epoch_25
- tests::signer::v0::signer_set_rollover
- tests::signer::v0::miner_forking
- tests::nakamoto_integrations::stack_stx_burn_op_integration_test
- tests::nakamoto_integrations::check_block_heights
Expand Down
2 changes: 1 addition & 1 deletion libsigner/src/runloop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ impl<

// start receiving events and doing stuff with them
let runloop_thread = thread::Builder::new()
.name("signer_runloop".to_string())
.name(format!("signer_runloop:{}", bind_addr.port()))
.stack_size(THREAD_STACK_SIZE)
.spawn(move || {
signer_loop.main_loop(event_recv, command_receiver, result_sender, stop_signaler)
Expand Down
3 changes: 2 additions & 1 deletion stacks-signer/src/chainstate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,12 @@ impl SortitionsView {
let last_in_tenure = signer_db
.get_last_signed_block_in_tenure(&block.header.consensus_hash)
.map_err(|e| ClientError::InvalidResponse(e.to_string()))?;
if last_in_tenure.is_some() {
if let Some(last_in_tenure) = last_in_tenure {
warn!(
"Miner block proposal contains a tenure change, but we've already signed a block in this tenure. Considering proposal invalid.";
"proposed_block_consensus_hash" => %block.header.consensus_hash,
"proposed_block_signer_sighash" => %block.header.signer_signature_hash(),
"last_in_tenure_signer_sighash" => %last_in_tenure.block.header.signer_signature_hash(),
);
return Ok(false);
}
Expand Down
5 changes: 4 additions & 1 deletion stacks-signer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ pub struct SpawnedSigner<S: Signer<T> + Send, T: SignerEventTrait> {
pub cmd_send: Sender<RunLoopCommand>,
/// The result receiver for interacting with the running signer
pub res_recv: Receiver<Vec<SignerResult>>,
/// The spawned signer's config
pub config: GlobalConfig,
/// Phantom data for the signer type
_phantom: std::marker::PhantomData<S>,
}
Expand Down Expand Up @@ -136,7 +138,7 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SpawnedSigner
{
crate::monitoring::start_serving_monitoring_metrics(config.clone()).ok();
}
let runloop = RunLoop::new(config);
let runloop = RunLoop::new(config.clone());
let mut signer: RunLoopSigner<S, T> =
libsigner::Signer::new(runloop, ev, cmd_recv, res_send);
let running_signer = signer.spawn(endpoint).expect("Failed to spawn signer");
Expand All @@ -145,6 +147,7 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SpawnedSigner
cmd_send,
res_recv,
_phantom: std::marker::PhantomData,
config,
}
}
}
2 changes: 1 addition & 1 deletion stackslib/src/chainstate/nakamoto/coordinator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ pub fn load_nakamoto_reward_set<U: RewardSetProvider>(
"burnchain_height" => %anchor_block_sn.block_height);

let reward_set = provider.get_reward_set_nakamoto(
prepare_end_height.saturating_sub(1),
prepare_end_height,
chain_state,
burnchain,
sort_db,
Expand Down
2 changes: 2 additions & 0 deletions testnet/stacks-node/src/event_dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ pub struct MinedNakamotoBlockEvent {
pub signer_signature_hash: Sha512Trunc256Sum,
pub tx_events: Vec<TransactionEvent>,
pub signer_bitvec: String,
pub signer_signature: Vec<MessageSignature>,
}

impl InnerStackerDBChannel {
Expand Down Expand Up @@ -1269,6 +1270,7 @@ impl EventDispatcher {
tx_events,
miner_signature: block.header.miner_signature.clone(),
signer_signature_hash: block.header.signer_signature_hash(),
signer_signature: block.header.signer_signature.clone(),
signer_bitvec,
})
.unwrap();
Expand Down
33 changes: 16 additions & 17 deletions testnet/stacks-node/src/nakamoto_node/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,18 +299,16 @@ impl BlockMinerThread {
}
}

let (reward_set, signer_signature) = match self.gather_signatures(
&mut new_block,
self.burn_block.block_height,
&mut stackerdbs,
&mut attempts,
) {
Ok(x) => x,
Err(e) => {
error!("Error while gathering signatures: {e:?}. Will try mining again.");
continue;
}
};
let (reward_set, signer_signature) =
match self.gather_signatures(&mut new_block, &mut stackerdbs, &mut attempts) {
Ok(x) => x,
Err(e) => {
error!(
"Error while gathering signatures: {e:?}. Will try mining again."
);
continue;
}
};

new_block.header.signer_signature = signer_signature;
if let Err(e) = self.broadcast(new_block.clone(), reward_set, &stackerdbs) {
Expand Down Expand Up @@ -383,10 +381,13 @@ impl BlockMinerThread {

let burn_election_height = self.burn_election_block.block_height;

let reward_cycle = self
.burnchain
.block_height_to_reward_cycle(burn_election_height)
.expect("FATAL: no reward cycle for sortition");

let reward_info = match load_nakamoto_reward_set(
self.burnchain
.pox_reward_cycle(burn_election_height)
.expect("FATAL: no reward cycle for sortition"),
reward_cycle,
&self.burn_election_block.sortition_id,
&self.burnchain,
&mut chain_state,
Expand Down Expand Up @@ -421,7 +422,6 @@ impl BlockMinerThread {
fn gather_signatures(
&mut self,
new_block: &mut NakamotoBlock,
burn_block_height: u64,
stackerdbs: &mut StackerDBs,
attempts: &mut u64,
) -> Result<(RewardSet, Vec<MessageSignature>), NakamotoNodeError> {
Expand Down Expand Up @@ -476,7 +476,6 @@ impl BlockMinerThread {
*attempts += 1;
let signature = coordinator.begin_sign_v0(
new_block,
burn_block_height,
*attempts,
&tip,
&self.burnchain,
Expand Down
5 changes: 3 additions & 2 deletions testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,6 @@ impl SignCoordinator {
pub fn begin_sign_v0(
&mut self,
block: &NakamotoBlock,
burn_block_height: u64,
block_attempt: u64,
burn_tip: &BlockSnapshot,
burnchain: &Burnchain,
Expand All @@ -653,7 +652,7 @@ impl SignCoordinator {

let block_proposal = BlockProposal {
block: block.clone(),
burn_height: burn_block_height,
burn_height: burn_tip.block_height,
reward_cycle: reward_cycle_id,
};

Expand Down Expand Up @@ -780,6 +779,8 @@ impl SignCoordinator {
"signature" => %signature,
"block_signer_signature_hash" => %block_sighash,
"slot_id" => slot_id,
"reward_cycle_id" => reward_cycle_id,
"response_hash" => %response_hash
);
continue;
}
Expand Down
21 changes: 18 additions & 3 deletions testnet/stacks-node/src/tests/nakamoto_integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ use crate::tests::neon_integrations::{
};
use crate::tests::{
get_chain_info, make_contract_publish, make_contract_publish_versioned, make_stacks_transfer,
set_random_binds, to_addr,
to_addr,
};
use crate::{tests, BitcoinRegtestController, BurnchainController, Config, ConfigFile, Keychain};

Expand Down Expand Up @@ -1042,6 +1042,7 @@ pub fn boot_to_epoch_3_reward_set_calculation_boundary(
stacker_sks: &[StacksPrivateKey],
signer_sks: &[StacksPrivateKey],
btc_regtest_controller: &mut BitcoinRegtestController,
num_stacking_cycles: Option<u64>,
) {
assert_eq!(stacker_sks.len(), signer_sks.len());

Expand Down Expand Up @@ -1072,7 +1073,7 @@ pub fn boot_to_epoch_3_reward_set_calculation_boundary(
.get_burnchain()
.block_height_to_reward_cycle(block_height)
.unwrap();
let lock_period = 12;
let lock_period: u128 = num_stacking_cycles.unwrap_or(12_u64).into();
debug!("Test Cycle Info";
"prepare_phase_len" => {prepare_phase_len},
"reward_cycle_len" => {reward_cycle_len},
Expand Down Expand Up @@ -1185,13 +1186,15 @@ pub fn boot_to_epoch_3_reward_set(
stacker_sks: &[StacksPrivateKey],
signer_sks: &[StacksPrivateKey],
btc_regtest_controller: &mut BitcoinRegtestController,
num_stacking_cycles: Option<u64>,
) {
boot_to_epoch_3_reward_set_calculation_boundary(
naka_conf,
blocks_processed,
stacker_sks,
signer_sks,
btc_regtest_controller,
num_stacking_cycles,
);
let epoch_3_reward_set_calculation =
btc_regtest_controller.get_headers_height().wrapping_add(1);
Expand Down Expand Up @@ -4986,6 +4989,18 @@ fn signer_chainstate() {
// query for prometheus metrics
#[cfg(feature = "monitoring_prom")]
{
let (chainstate, _) = StacksChainState::open(
naka_conf.is_mainnet(),
naka_conf.burnchain.chain_id,
&naka_conf.get_chainstate_path_str(),
None,
)
.unwrap();
let block_height_pre_3_0 =
NakamotoChainState::get_canonical_block_header(chainstate.db(), &sortdb)
.unwrap()
.unwrap()
.stacks_block_height;
let prom_http_origin = format!("http://{}", prom_bind);
let client = reqwest::blocking::Client::new();
let res = client
Expand Down Expand Up @@ -7239,7 +7254,7 @@ fn mock_mining() {
let mock_miner_timeout = Instant::now();
while follower_naka_mined_blocks.load(Ordering::SeqCst) <= follower_naka_mined_blocks_before
{
if mock_miner_timeout.elapsed() >= Duration::from_secs(30) {
if mock_miner_timeout.elapsed() >= Duration::from_secs(60) {
panic!(
"Timed out waiting for mock miner block {}",
follower_naka_mined_blocks_before + 1
Expand Down
39 changes: 26 additions & 13 deletions testnet/stacks-node/src/tests/signer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use stacks_common::codec::StacksMessageCodec;
use stacks_common::consts::SIGNER_SLOTS_PER_USER;
use stacks_common::types::StacksEpochId;
use stacks_common::util::hash::{hex_bytes, Sha512Trunc256Sum};
use stacks_signer::client::{SignerSlotID, StacksClient};
use stacks_signer::client::{ClientError, SignerSlotID, StacksClient};
use stacks_signer::config::{build_signer_config_tomls, GlobalConfig as SignerConfig, Network};
use stacks_signer::runloop::{SignerResult, StateInfo};
use stacks_signer::{Signer, SpawnedSigner};
Expand All @@ -64,7 +64,8 @@ use crate::tests::nakamoto_integrations::{
naka_neon_integration_conf, next_block_and_mine_commit, POX_4_DEFAULT_STACKER_BALANCE,
};
use crate::tests::neon_integrations::{
next_block_and_wait, run_until_burnchain_height, test_observer, wait_for_runloop,
get_chain_info, next_block_and_wait, run_until_burnchain_height, test_observer,
wait_for_runloop,
};
use crate::tests::to_addr;
use crate::{BitcoinRegtestController, BurnchainController};
Expand Down Expand Up @@ -100,6 +101,8 @@ pub struct SignerTest<S> {
pub stacks_client: StacksClient,
// Unique number used to isolate files created during the test
pub run_stamp: u16,
/// The number of cycles to stack for
pub num_stacking_cycles: u64,
}

impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<SpawnedSigner<S, T>> {
Expand All @@ -126,7 +129,7 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<Sp
initial_balances: Vec<(StacksAddress, u64)>,
wait_on_signers: Option<Duration>,
mut signer_config_modifier: F,
node_config_modifier: G,
mut node_config_modifier: G,
btc_miner_pubkeys: &[Secp256k1PublicKey],
) -> Self {
// Generate Signer Data
Expand All @@ -136,6 +139,8 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<Sp

let (mut naka_conf, _miner_account) = naka_neon_integration_conf(None);

node_config_modifier(&mut naka_conf);

// Add initial balances to the config
for (address, amount) in initial_balances.iter() {
naka_conf
Expand Down Expand Up @@ -191,15 +196,15 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<Sp
.unwrap(),
)
.unwrap();
&[pk]
vec![pk]
} else {
btc_miner_pubkeys
btc_miner_pubkeys.to_vec()
};
let node = setup_stx_btc_node(
naka_conf,
&signer_stacks_private_keys,
&signer_configs,
btc_miner_pubkeys,
btc_miner_pubkeys.as_slice(),
node_config_modifier,
);
let config = signer_configs.first().unwrap();
Expand All @@ -211,6 +216,7 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<Sp
signer_stacks_private_keys,
stacks_client,
run_stamp,
num_stacking_cycles: 12_u64,
signer_configs,
}
}
Expand Down Expand Up @@ -472,15 +478,15 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<Sp
}

fn get_current_reward_cycle(&self) -> u64 {
let block_height = self
let block_height = get_chain_info(&self.running_nodes.conf).burn_block_height;
let rc = self
.running_nodes
.btc_regtest_controller
.get_headers_height();
self.running_nodes
.btc_regtest_controller
.get_burnchain()
.block_height_to_reward_cycle(block_height)
.unwrap()
.unwrap();
info!("Get current reward cycle: block_height = {block_height}, rc = {rc}");
rc
}

fn get_signer_index(&self, reward_cycle: u64) -> SignerSlotID {
Expand All @@ -499,20 +505,27 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<Sp
.expect("FATAL: signer not registered")
}

fn get_signer_indices(&self, reward_cycle: u64) -> Vec<SignerSlotID> {
fn get_signer_slots(
&self,
reward_cycle: u64,
) -> Result<Vec<(StacksAddress, u128)>, ClientError> {
let valid_signer_set =
u32::try_from(reward_cycle % 2).expect("FATAL: reward_cycle % 2 exceeds u32::MAX");
let signer_stackerdb_contract_id = boot_code_id(SIGNERS_NAME, false);

self.stacks_client
.get_stackerdb_signer_slots(&signer_stackerdb_contract_id, valid_signer_set)
}

fn get_signer_indices(&self, reward_cycle: u64) -> Vec<SignerSlotID> {
self.get_signer_slots(reward_cycle)
.expect("FATAL: failed to get signer slots from stackerdb")
.iter()
.enumerate()
.map(|(pos, _)| {
SignerSlotID(u32::try_from(pos).expect("FATAL: number of signers exceeds u32::MAX"))
})
.collect()
.collect::<Vec<_>>()
}

/// Get the wsts public keys for the given reward cycle
Expand Down
Loading