diff --git a/signer/src/api/new_block.rs b/signer/src/api/new_block.rs index ae3a971ba..2a1765561 100644 --- a/signer/src/api/new_block.rs +++ b/signer/src/api/new_block.rs @@ -667,6 +667,7 @@ mod tests { num_deposit_requests_per_block: 1, num_withdraw_requests_per_block: 1, num_signers_per_request: 0, + consecutive_blocks: false, }; let db = ctx.inner_storage(); let test_data = TestData::generate(&mut rng, &[], &test_params); @@ -739,6 +740,7 @@ mod tests { num_deposit_requests_per_block: 1, num_withdraw_requests_per_block: 1, num_signers_per_request: 0, + consecutive_blocks: false, }; let db = ctx.inner_storage(); let test_data = TestData::generate(&mut rng, &[], &test_params); @@ -787,6 +789,7 @@ mod tests { num_deposit_requests_per_block: 2, num_withdraw_requests_per_block: 2, num_signers_per_request: 0, + consecutive_blocks: false, }; let db = ctx.inner_storage(); @@ -859,6 +862,7 @@ mod tests { num_deposit_requests_per_block: 2, num_withdraw_requests_per_block: 2, num_signers_per_request: 0, + consecutive_blocks: false, }; let db = ctx.inner_storage(); @@ -920,6 +924,7 @@ mod tests { num_deposit_requests_per_block: 2, num_withdraw_requests_per_block: 2, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_params); diff --git a/signer/src/config/mod.rs b/signer/src/config/mod.rs index d8d6e02f8..91e69ca88 100644 --- a/signer/src/config/mod.rs +++ b/signer/src/config/mod.rs @@ -281,6 +281,9 @@ pub struct SignerConfig { /// How many bitcoin blocks back from the chain tip the signer will /// look for requests. pub context_window: u16, + /// How many bitcoin blocks back from the chain tip the signer will + /// look for deposit decisions to retry to propagate. + pub deposit_decisions_retry_window: u16, /// The maximum duration of a signing round before the coordinator will /// time out and return an error. #[serde(deserialize_with = "duration_seconds_deserializer")] @@ -449,6 +452,7 @@ impl Settings { // after https://github.com/stacks-network/sbtc/issues/1004 gets // done. cfg_builder = cfg_builder.set_default("signer.context_window", 1000)?; + cfg_builder = cfg_builder.set_default("signer.deposit_decisions_retry_window", 3)?; cfg_builder = cfg_builder.set_default("signer.dkg_max_duration", 120)?; cfg_builder = cfg_builder.set_default("signer.bitcoin_presign_request_max_duration", 30)?; cfg_builder = cfg_builder.set_default("signer.signer_round_max_duration", 30)?; @@ -577,6 +581,7 @@ mod tests { assert_eq!(settings.signer.sbtc_bitcoin_start_height, Some(101)); assert_eq!(settings.signer.bootstrap_signatures_required, 2); assert_eq!(settings.signer.context_window, 1000); + assert_eq!(settings.signer.deposit_decisions_retry_window, 3); assert!(settings.signer.prometheus_exporter_endpoint.is_none()); assert_eq!( settings.signer.bitcoin_presign_request_max_duration, @@ -883,6 +888,7 @@ mod tests { .remove(parameter); }; remove_parameter("context_window"); + remove_parameter("deposit_decisions_retry_window"); remove_parameter("signer_round_max_duration"); remove_parameter("bitcoin_presign_request_max_duration"); remove_parameter("dkg_max_duration"); @@ -895,6 +901,7 @@ mod tests { let settings = Settings::new(Some(&new_config.path())).unwrap(); assert_eq!(settings.signer.context_window, 1000); + assert_eq!(settings.signer.deposit_decisions_retry_window, 3); assert_eq!( settings.signer.bitcoin_presign_request_max_duration, Duration::from_secs(30) diff --git a/signer/src/main.rs b/signer/src/main.rs index cb3a84070..ad27bec3d 100644 --- a/signer/src/main.rs +++ b/signer/src/main.rs @@ -370,6 +370,7 @@ async fn run_request_decider(ctx: impl Context) -> Result<(), Error> { network, context: ctx.clone(), context_window: config.signer.context_window, + deposit_decisions_retry_window: config.signer.deposit_decisions_retry_window, blocklist_checker: BlocklistClient::new(&ctx), signer_private_key: config.signer.private_key, }; diff --git a/signer/src/message.rs b/signer/src/message.rs index e7f0eeaa3..26f7631fe 100644 --- a/signer/src/message.rs +++ b/signer/src/message.rs @@ -7,6 +7,7 @@ use crate::bitcoin::validation::TxRequestIds; use crate::keys::PublicKey; use crate::stacks::contracts::ContractCall; use crate::stacks::contracts::StacksTx; +use crate::storage::model; use crate::storage::model::BitcoinBlockHash; use crate::storage::model::StacksTxId; @@ -139,6 +140,17 @@ pub struct SignerDepositDecision { pub can_sign: bool, } +impl From for SignerDepositDecision { + fn from(signer: model::DepositSigner) -> Self { + Self { + txid: signer.txid.into(), + output_index: signer.output_index, + can_accept: signer.can_accept, + can_sign: signer.can_sign, + } + } +} + /// Represents a decision related to signer withdrawal. #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "testing", derive(fake::Dummy))] diff --git a/signer/src/request_decider.rs b/signer/src/request_decider.rs index 6c22babe9..f30745317 100644 --- a/signer/src/request_decider.rs +++ b/signer/src/request_decider.rs @@ -48,6 +48,9 @@ pub struct RequestDeciderEventLoop { pub signer_private_key: PrivateKey, /// How many bitcoin blocks back from the chain tip the signer will look for requests. pub context_window: u16, + /// How many bitcoin blocks back from the chain tip the signer will look for deposit + /// decisions to retry to propagate. + pub deposit_decisions_retry_window: u16, } /// This function defines which messages this event loop is interested @@ -129,6 +132,23 @@ where let span = tracing::Span::current(); span.record("chain_tip", tracing::field::display(chain_tip)); + // We retry the deposit decisions because some signers' bitcoin nodes might have + // been running behind and ignored the previous messages. + let deposit_decisions_to_retry = db + .get_deposit_signer_decisions( + &chain_tip, + self.deposit_decisions_retry_window, + &signer_public_key, + ) + .await?; + + let _ = self + .handle_deposit_decisions_to_retry(deposit_decisions_to_retry, &chain_tip) + .await + .inspect_err( + |error| tracing::warn!(%error, "error handling deposit decisions to retry"), + ); + let deposit_requests = db .get_pending_deposit_requests(&chain_tip, self.context_window, &signer_public_key) .await?; @@ -248,6 +268,24 @@ where Ok(()) } + /// Send the given deposit decisions to the other signers for redundancy. + #[tracing::instrument(skip_all)] + pub async fn handle_deposit_decisions_to_retry( + &mut self, + decisions: Vec, + chain_tip: &BitcoinBlockHash, + ) -> Result<(), Error> { + for decision in decisions.into_iter().map(SignerDepositDecision::from) { + let _ = self + .send_message(decision, chain_tip) + .await + .inspect_err(|error| { + tracing::warn!(%error, "error sending deposit decision to retry, skipping"); + }); + } + Ok(()) + } + #[tracing::instrument(skip_all)] async fn handle_pending_withdrawal_request( &mut self, @@ -470,6 +508,7 @@ mod tests { num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 5, num_signers_per_request: 0, + consecutive_blocks: false, }; let context = TestContext::builder() @@ -480,6 +519,7 @@ mod tests { testing::request_decider::TestEnvironment { context, context_window: 6, + deposit_decisions_retry_window: 1, num_signers: 7, signing_threshold: 5, test_model_parameters, diff --git a/signer/src/stacks/wallet.rs b/signer/src/stacks/wallet.rs index 4f3e5036d..a16e38c81 100644 --- a/signer/src/stacks/wallet.rs +++ b/signer/src/stacks/wallet.rs @@ -677,6 +677,7 @@ mod tests { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_params); test_data.write_to(&db).await; diff --git a/signer/src/storage/in_memory.rs b/signer/src/storage/in_memory.rs index 7d0dae4e4..d976e585f 100644 --- a/signer/src/storage/in_memory.rs +++ b/signer/src/storage/in_memory.rs @@ -908,6 +908,43 @@ impl super::DbRead for SharedStore { .get(sighash) .map(|s| (s.will_sign, s.aggregate_key))) } + + async fn get_deposit_signer_decisions( + &self, + chain_tip: &model::BitcoinBlockHash, + context_window: u16, + signer_public_key: &PublicKey, + ) -> Result, Error> { + let store = self.lock().await; + let deposit_requests = store.get_deposit_requests(chain_tip, context_window); + let voted: HashSet<(model::BitcoinTxId, u32)> = store + .signer_to_deposit_request + .get(signer_public_key) + .cloned() + .unwrap_or(Vec::new()) + .into_iter() + .collect(); + + let result = deposit_requests + .into_iter() + .filter_map(|request| { + if !voted.contains(&(request.txid, request.output_index)) { + return None; + } + store + .deposit_request_to_signers + .get(&(request.txid, request.output_index)) + .and_then(|signers| { + signers + .iter() + .find(|signer| signer.signer_pub_key == *signer_public_key) + .cloned() + }) + }) + .collect(); + + Ok(result) + } } impl super::DbWrite for SharedStore { diff --git a/signer/src/storage/mod.rs b/signer/src/storage/mod.rs index 9b8af4e42..f8881af3a 100644 --- a/signer/src/storage/mod.rs +++ b/signer/src/storage/mod.rs @@ -124,6 +124,15 @@ pub trait DbRead { output_index: u32, ) -> impl Future, Error>> + Send; + /// Get all the deposit decisions for the given signer in the given window + /// of blocks. + fn get_deposit_signer_decisions( + &self, + chain_tip: &model::BitcoinBlockHash, + context_window: u16, + signer_public_key: &PublicKey, + ) -> impl Future, Error>> + Send; + /// Returns whether the given `signer_public_key` can provide signature /// shares for the deposit transaction. /// diff --git a/signer/src/storage/postgres.rs b/signer/src/storage/postgres.rs index 0bae1bd1d..33db234de 100644 --- a/signer/src/storage/postgres.rs +++ b/signer/src/storage/postgres.rs @@ -488,7 +488,7 @@ impl PgStore { JOIN sbtc_signer.bitcoin_transactions AS bt USING (txid) WHERE prevout_type = 'signers_input' ) - SELECT + SELECT bo.txid , bb.block_height FROM sbtc_signer.bitcoin_tx_outputs AS bo @@ -1796,7 +1796,7 @@ impl super::DbRead for PgStore { sqlx::query_as::<_, model::SweptDepositRequest>( " WITH RECURSIVE bitcoin_blockchain AS ( - SELECT + SELECT block_hash , block_height FROM bitcoin_blockchain_of($1, $2) @@ -1810,9 +1810,9 @@ impl super::DbRead for PgStore { JOIN bitcoin_blockchain as bb ON bb.block_hash = stacks_blocks.bitcoin_anchor WHERE stacks_blocks.block_hash = $3 - + UNION ALL - + SELECT parent.block_hash , parent.block_height @@ -1841,7 +1841,7 @@ impl super::DbRead for PgStore { LEFT JOIN completed_deposit_events AS cde ON cde.bitcoin_txid = deposit_req.txid AND cde.output_index = deposit_req.output_index - LEFT JOIN stacks_blockchain AS sb + LEFT JOIN stacks_blockchain AS sb ON sb.block_hash = cde.block_hash GROUP BY bc_trx.txid @@ -1921,6 +1921,40 @@ impl super::DbRead for PgStore { .await .map_err(Error::SqlxQuery) } + + async fn get_deposit_signer_decisions( + &self, + chain_tip: &model::BitcoinBlockHash, + context_window: u16, + signer_public_key: &PublicKey, + ) -> Result, Error> { + sqlx::query_as::<_, model::DepositSigner>( + r#" + WITH target_block AS ( + SELECT blocks.block_hash, blocks.created_at + FROM sbtc_signer.bitcoin_blockchain_of($1, $2) chain + JOIN sbtc_signer.bitcoin_blocks blocks USING (block_hash) + ORDER BY chain.block_height ASC + LIMIT 1 + ) + SELECT + ds.txid, + ds.output_index, + ds.signer_pub_key, + ds.can_sign, + ds.can_accept + FROM sbtc_signer.deposit_signers ds + WHERE ds.signer_pub_key = $3 + AND ds.created_at >= (SELECT created_at FROM target_block) + "#, + ) + .bind(chain_tip) + .bind(i32::from(context_window)) + .bind(signer_public_key) + .fetch_all(&self.0) + .await + .map_err(Error::SqlxQuery) + } } impl super::DbWrite for PgStore { diff --git a/signer/src/testing/request_decider.rs b/signer/src/testing/request_decider.rs index a44e21241..c6fa4b07c 100644 --- a/signer/src/testing/request_decider.rs +++ b/signer/src/testing/request_decider.rs @@ -42,6 +42,7 @@ impl RequestDeciderEventLoopHarness { context: C, network: SignerNetwork, context_window: u16, + deposit_decisions_retry_window: u16, signer_private_key: PrivateKey, ) -> Self { Self { @@ -51,6 +52,7 @@ impl RequestDeciderEventLoopHarness { blocklist_checker: Some(()), signer_private_key, context_window, + deposit_decisions_retry_window, }, context, } @@ -122,6 +124,8 @@ pub struct TestEnvironment { pub context: C, /// Bitcoin context window pub context_window: u16, + /// Deposit decisions retry window + pub deposit_decisions_retry_window: u16, /// Num signers pub num_signers: usize, /// Signing threshold @@ -156,6 +160,7 @@ where self.context.clone(), signer_network, self.context_window, + self.deposit_decisions_retry_window, coordinator_signer_info.signer_private_key, ); @@ -238,6 +243,7 @@ where self.context.clone(), signer_network, self.context_window, + self.deposit_decisions_retry_window, coordinator_signer_info.signer_private_key, ); @@ -315,6 +321,7 @@ where ctx, net, self.context_window, + self.deposit_decisions_retry_window, signer_info.signer_private_key, ); diff --git a/signer/src/testing/storage/model.rs b/signer/src/testing/storage/model.rs index 41e7a8e61..c2046a820 100644 --- a/signer/src/testing/storage/model.rs +++ b/signer/src/testing/storage/model.rs @@ -64,10 +64,14 @@ impl TestData { R: rand::RngCore, { let mut test_data = Self::new(); - + let mut parent: Option = None; for _ in 0..params.num_bitcoin_blocks { - let (next_chunk, _) = test_data.new_block(rng, signer_keys, params, None); + let (next_chunk, block_ref) = + test_data.new_block(rng, signer_keys, params, parent.as_ref()); test_data.push(next_chunk); + if params.consecutive_blocks { + parent = Some(block_ref); + } } test_data @@ -114,7 +118,6 @@ impl TestData { .collect(); let bitcoin_blocks = vec![block.clone()]; - ( Self { bitcoin_blocks, @@ -515,6 +518,8 @@ pub struct Params { pub num_withdraw_requests_per_block: usize, /// The number of signers to hallucinate per request pub num_signers_per_request: usize, + /// Wheter to generate consecutive blocks or not + pub consecutive_blocks: bool, } impl BitcoinBlockRef { diff --git a/signer/src/transaction_coordinator.rs b/signer/src/transaction_coordinator.rs index c4f6893ed..473ab2b4c 100644 --- a/signer/src/transaction_coordinator.rs +++ b/signer/src/transaction_coordinator.rs @@ -1840,6 +1840,7 @@ mod tests { num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 5, num_signers_per_request: 7, + consecutive_blocks: false, }; let context = TestContext::builder() diff --git a/signer/src/transaction_signer.rs b/signer/src/transaction_signer.rs index f3cdf5076..ebba4a02d 100644 --- a/signer/src/transaction_signer.rs +++ b/signer/src/transaction_signer.rs @@ -1001,6 +1001,7 @@ mod tests { num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 5, num_signers_per_request: 0, + consecutive_blocks: false, }; let context = TestContext::builder() diff --git a/signer/tests/integration/emily.rs b/signer/tests/integration/emily.rs index d572e3fd9..d1cccc320 100644 --- a/signer/tests/integration/emily.rs +++ b/signer/tests/integration/emily.rs @@ -80,6 +80,7 @@ where num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(rng, &signer_keys, &test_model_parameters); test_data.write_to(&storage).await; diff --git a/signer/tests/integration/postgres.rs b/signer/tests/integration/postgres.rs index 1f3e747a1..14d22dc4f 100644 --- a/signer/tests/integration/postgres.rs +++ b/signer/tests/integration/postgres.rs @@ -14,6 +14,7 @@ use futures::future::join_all; use futures::StreamExt; use rand::seq::IteratorRandom; use rand::seq::SliceRandom; +use time::OffsetDateTime; use signer::bitcoin::validation::DepositConfirmationStatus; use signer::bitcoin::MockBitcoinInteract; @@ -81,6 +82,7 @@ async fn should_be_able_to_query_bitcoin_blocks() { num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 5, num_signers_per_request: 0, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, 7); @@ -326,6 +328,7 @@ async fn should_return_the_same_pending_deposit_requests_as_in_memory_store() { num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 5, num_signers_per_request: 0, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); let test_data = TestData::generate(&mut rng, &signer_set, &test_model_params); @@ -490,6 +493,7 @@ async fn should_return_the_same_pending_withdraw_requests_as_in_memory_store() { num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 1, num_signers_per_request: 0, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -566,6 +570,7 @@ async fn should_return_the_same_pending_accepted_deposit_requests_as_in_memory_s num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 5, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let threshold = 4; @@ -634,6 +639,7 @@ async fn should_return_the_same_pending_accepted_withdraw_requests_as_in_memory_ // the threshold in order for the test to succeed with accepted // requests. num_signers_per_request: num_signers, + consecutive_blocks: false, }; let threshold = 4; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -771,6 +777,7 @@ async fn should_return_only_accepted_pending_deposits_that_are_within_reclaim_bo num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 5, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let threshold = 4; @@ -955,6 +962,7 @@ async fn should_return_the_same_last_key_rotation_as_in_memory_store() { num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 1, num_signers_per_request: 7, + consecutive_blocks: false, }; let num_signers = 7; let threshold = 4; @@ -1381,6 +1389,119 @@ async fn fetching_deposit_request_votes() { signer::testing::storage::drop_db(store).await; } +#[tokio::test] +async fn fetching_deposit_signer_decisions() { + let pg_store = testing::storage::new_test_database().await; + let mut rng = rand::rngs::StdRng::seed_from_u64(51); + + // This is just a sql test, where we use the `TestData` struct to help + // populate the database with test data. We set all the other + // unnecessary parameters to zero. + let num_signers = 3; + let test_model_params = testing::storage::model::Params { + num_bitcoin_blocks: 5, + num_stacks_blocks_per_bitcoin_block: 0, + num_deposit_requests_per_block: 1, + num_withdraw_requests_per_block: 0, + num_signers_per_request: num_signers, + consecutive_blocks: true, + }; + + let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); + + let mut test_data = TestData::generate(&mut rng, &signer_set, &test_model_params); + test_data.write_to(&pg_store).await; + + let signer_pub_key = signer_set.first().unwrap(); + + // We'll register each block with a 2 minute interval + // i.e. times -> [-15, -13, -11, -9, -7] + let mut new_time = OffsetDateTime::now_utc() - time::Duration::minutes(15); + // Update Bitcoin blocks + for block in test_data.bitcoin_blocks.iter() { + let new_time_str = new_time + .format(&time::format_description::well_known::Rfc3339) + .unwrap(); + sqlx::query( + r#" + UPDATE sbtc_signer.bitcoin_blocks + SET created_at = $1::timestamptz + WHERE block_hash = $2"#, + ) + .bind(new_time_str) // Bind as string + .bind(block.block_hash) + .execute(pg_store.pool()) + .await + .unwrap(); + + new_time += time::Duration::minutes(2); + } + + // Rotate deposits to test edge case: + // Move first deposit to be processed last (latest timestamp) + // This tests that a deposit decision can still be returned + // even when its associated block falls outside the context window + test_data.deposit_requests.rotate_left(1); + + // Now we'll update the deposits decisions. Each decision will be + // updated so that it will arrive 1 minute after its corresponding block. + // With the exception of the first one, which will be updated to arrive last. + // Block times: [-15, -13, -11, -9, -7] + // Decision times: [-12, -10, -8, -6, -4] + // ^ ^ ^ ^ ^ + // | | | | first deposit (moved to last) + // | | | fifth deposit + // | | forth deposit + // | third deposit + // second deposit + new_time = OffsetDateTime::now_utc() - time::Duration::minutes(12); + for deposit in test_data.deposit_requests.iter() { + let new_time_str = new_time + .format(&time::format_description::well_known::Rfc3339) + .unwrap(); + + sqlx::query( + r#" + UPDATE sbtc_signer.deposit_signers + SET created_at = $1::timestamptz + WHERE txid = $2 AND output_index = $3 AND signer_pub_key = $4"#, + ) + .bind(new_time_str) // Bind as string + .bind(deposit.txid) + .bind(i32::try_from(deposit.output_index).unwrap()) + .bind(signer_pub_key) + .execute(pg_store.pool()) + .await + .unwrap(); + + new_time += time::Duration::minutes(2); + } + + let chain_tip = pg_store + .get_bitcoin_canonical_chain_tip() + .await + .unwrap() + .unwrap(); + + let deposit_decisions = pg_store + .get_deposit_signer_decisions(&chain_tip, 3, signer_pub_key) + .await + .unwrap(); + + assert_eq!(deposit_decisions.len(), 4); + // Test data contains 5 deposit requests, we should get decisions for + // the last 4. + for deposit in test_data.deposit_requests[1..].iter() { + assert!(deposit_decisions.iter().any(|decision| { + decision.txid == deposit.txid + && decision.output_index == deposit.output_index + && decision.signer_pub_key == *signer_pub_key + })); + } + + signer::testing::storage::drop_db(pg_store).await; +} + /// For this test we check that when we get the votes for a withdrawal /// request for a specific aggregate key, that we get a vote for all public /// keys for the specific aggregate key. This includes "implicit" votes @@ -1509,6 +1630,7 @@ async fn block_in_canonical_bitcoin_blockchain_in_other_block_chain() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -1582,6 +1704,7 @@ async fn we_can_fetch_bitcoin_txs_from_db() { num_deposit_requests_per_block: 2, num_withdraw_requests_per_block: 0, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -1793,6 +1916,7 @@ async fn is_known_bitcoin_block_hash_works() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -2248,6 +2372,7 @@ async fn transaction_coordinator_test_environment( num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 5, num_signers_per_request: 7, + consecutive_blocks: false, }; let context = TestContext::builder() @@ -2354,6 +2479,7 @@ async fn deposit_report_with_only_deposit_request() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -2453,6 +2579,7 @@ async fn deposit_report_with_deposit_request_reorged() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -2527,6 +2654,7 @@ async fn deposit_report_with_deposit_request_spent() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -2624,6 +2752,7 @@ async fn deposit_report_with_deposit_request_swept_but_swept_reorged() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -2754,6 +2883,7 @@ async fn deposit_report_with_deposit_request_confirmed() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: num_signers, + consecutive_blocks: false, }; let signer_set = testing::wsts::generate_signer_set_public_keys(&mut rng, num_signers); @@ -2990,6 +3120,7 @@ async fn signer_utxo_reorg_suite(desc: ReorgDescription) { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: num_signers, + consecutive_blocks: false, }; // Let's generate some dummy data and write it into the database. diff --git a/signer/tests/integration/request_decider.rs b/signer/tests/integration/request_decider.rs index 4d58af64b..79334b68e 100644 --- a/signer/tests/integration/request_decider.rs +++ b/signer/tests/integration/request_decider.rs @@ -40,6 +40,7 @@ fn test_environment( >, > { let context_window = 6; + let deposit_decisions_retry_window = 1; let test_model_parameters = testing::storage::model::Params { num_bitcoin_blocks: 20, @@ -47,6 +48,7 @@ fn test_environment( num_deposit_requests_per_block: 5, num_withdraw_requests_per_block: 5, num_signers_per_request: 0, + consecutive_blocks: false, }; let context = TestContext::builder() @@ -58,6 +60,7 @@ fn test_environment( context, num_signers, context_window, + deposit_decisions_retry_window, signing_threshold, test_model_parameters, } @@ -166,6 +169,7 @@ async fn handle_pending_deposit_request_address_script_pub_key() { network: network.connect(), context: ctx.clone(), context_window: 10000, + deposit_decisions_retry_window: 1, blocklist_checker: Some(()), signer_private_key: setup.aggregated_signer.keypair.secret_key().into(), }; @@ -250,6 +254,7 @@ async fn handle_pending_deposit_request_not_in_signing_set() { network: network.connect(), context: ctx.clone(), context_window: 10000, + deposit_decisions_retry_window: 1, blocklist_checker: Some(()), // We generate a new private key here so that we know (with very // high probability) that this signer is not in the signer set. @@ -328,6 +333,7 @@ async fn persist_received_deposit_decision_fetches_missing_deposit_requests() { network: network.spawn(), context: ctx.clone(), context_window: 10000, + deposit_decisions_retry_window: 1, blocklist_checker: Some(()), signer_private_key: PrivateKey::new(&mut rng), }; diff --git a/signer/tests/integration/rotate_keys.rs b/signer/tests/integration/rotate_keys.rs index 1c5469395..8a1856b1a 100644 --- a/signer/tests/integration/rotate_keys.rs +++ b/signer/tests/integration/rotate_keys.rs @@ -174,6 +174,7 @@ async fn rotate_key_validation_happy_path() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_model_params); test_data.write_to(&mut db).await; @@ -223,6 +224,7 @@ async fn rotate_key_validation_no_dkg() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_model_params); test_data.write_to(&mut db).await; @@ -260,6 +262,7 @@ async fn rotate_key_validation_wrong_deployer() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_model_params); test_data.write_to(&mut db).await; @@ -303,6 +306,7 @@ async fn rotate_key_validation_wrong_signing_set() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_model_params); test_data.write_to(&mut db).await; @@ -352,6 +356,7 @@ async fn rotate_key_validation_wrong_aggregate_key() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_model_params); test_data.write_to(&mut db).await; @@ -401,6 +406,7 @@ async fn rotate_key_validation_wrong_signatures_required() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_model_params); test_data.write_to(&mut db).await; @@ -455,6 +461,7 @@ async fn rotate_key_validation_replay() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_model_params); test_data.write_to(&mut db).await; @@ -493,6 +500,7 @@ async fn rotate_key_validation_replay() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_model_params); test_data.write_to(&mut db).await; diff --git a/signer/tests/integration/transaction_coordinator.rs b/signer/tests/integration/transaction_coordinator.rs index c1a2686a1..3d061bea2 100644 --- a/signer/tests/integration/transaction_coordinator.rs +++ b/signer/tests/integration/transaction_coordinator.rs @@ -818,6 +818,7 @@ async fn get_signer_public_keys_and_aggregate_key_falls_back() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_params); test_data.write_to(&db).await; @@ -926,6 +927,7 @@ async fn run_dkg_from_scratch() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_params); @@ -1143,6 +1145,7 @@ async fn run_subsequent_dkg() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_params); @@ -1588,6 +1591,7 @@ async fn sign_bitcoin_transaction() { network: network.spawn(), context: ctx.clone(), context_window: 10000, + deposit_decisions_retry_window: 1, blocklist_checker: Some(()), signer_private_key: kp.secret_key().into(), }; @@ -2028,6 +2032,7 @@ async fn sign_bitcoin_transaction_multiple_locking_keys() { network: network.spawn(), context: ctx.clone(), context_window: 10000, + deposit_decisions_retry_window: 1, blocklist_checker: Some(()), signer_private_key: kp.secret_key().into(), }; @@ -2617,6 +2622,7 @@ async fn skip_smart_contract_deployment_and_key_rotation_if_up_to_date() { network: network.spawn(), context: ctx.clone(), context_window: 10000, + deposit_decisions_retry_window: 1, blocklist_checker: Some(()), signer_private_key: kp.secret_key().into(), }; @@ -3404,6 +3410,7 @@ async fn test_conservative_initial_sbtc_limits() { context_window: 10000, blocklist_checker: Some(()), signer_private_key: kp.secret_key().into(), + deposit_decisions_retry_window: 1, }; let counter = start_count.clone(); tokio::spawn(async move { diff --git a/signer/tests/integration/transaction_signer.rs b/signer/tests/integration/transaction_signer.rs index 23029bced..f395961bd 100644 --- a/signer/tests/integration/transaction_signer.rs +++ b/signer/tests/integration/transaction_signer.rs @@ -83,6 +83,7 @@ async fn get_signer_public_keys_and_aggregate_key_falls_back() { num_deposit_requests_per_block: 0, num_withdraw_requests_per_block: 0, num_signers_per_request: 0, + consecutive_blocks: false, }; let test_data = TestData::generate(&mut rng, &[], &test_params); test_data.write_to(&db).await;