-
Notifications
You must be signed in to change notification settings - Fork 11
feat: devnet support for dash-spv
#784
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
Changes from all commits
38d2656
4cf58b7
4c2dbc9
a8a537e
f59de5f
4d5e0f6
e3c8002
a5b5204
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ pub mod rotation; | |
|
|
||
| use std::fmt::{Display, Formatter}; | ||
| use std::io; | ||
| use std::sync::OnceLock; | ||
|
|
||
| #[cfg(feature = "bincode")] | ||
| use bincode::{Decode, Encode}; | ||
|
|
@@ -207,6 +208,49 @@ pub const LLMQ_DEVNET: LLMQParams = LLMQParams { | |
| recovery_members: 6, | ||
| }; | ||
|
|
||
| /// Runtime override values for `LLMQ_DEVNET`, matching Dash Core's | ||
| /// `-llmqdevnetparams=<size>:<threshold>`. | ||
| #[repr(C)] | ||
| #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] | ||
| pub struct LlmqDevnetParams { | ||
| /// Quorum size (total members). | ||
| pub size: u32, | ||
| /// Signing threshold (also used as min_size and bad_votes_threshold). | ||
| pub threshold: u32, | ||
| } | ||
|
|
||
| /// Runtime override for `LLMQ_DEVNET` params, matching Dash Core's `-llmqdevnetparams`. | ||
| static LLMQ_DEVNET_OVERRIDE: OnceLock<LlmqDevnetParams> = OnceLock::new(); | ||
|
|
||
| /// Override the `LLMQ_DEVNET` quorum size and threshold (matches Dash Core's | ||
| /// `-llmqdevnetparams=<size>:<threshold>`). Idempotent for identical values, | ||
| /// returns an error if a conflicting override was already set. | ||
| pub fn set_llmq_devnet_params(params: LlmqDevnetParams) -> Result<(), &'static str> { | ||
| match LLMQ_DEVNET_OVERRIDE.get() { | ||
| Some(&existing) if existing == params => Ok(()), | ||
| Some(_) => Err("LLMQ_DEVNET params already set to a different value"), | ||
| None => LLMQ_DEVNET_OVERRIDE | ||
| .set(params) | ||
| .map_err(|_| "LLMQ_DEVNET params already set to a different value"), | ||
|
xdustinface marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
| /// Get the effective `LLMQ_DEVNET` params, applying any runtime override. | ||
| pub fn llmq_devnet_params() -> LLMQParams { | ||
| let mut params = LLMQ_DEVNET; | ||
| if let Some(&LlmqDevnetParams { | ||
| size, | ||
| threshold, | ||
| }) = LLMQ_DEVNET_OVERRIDE.get() | ||
| { | ||
| params.size = size; | ||
| params.min_size = threshold; | ||
| params.threshold = threshold; | ||
| params.dkg_params.bad_votes_threshold = threshold; | ||
| } | ||
| params | ||
| } | ||
|
Comment on lines
+222
to
+252
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win Add focused tests for the new process-wide devnet override path. Please add unit tests for: valid override application, invalid value rejection, and second-set behavior. As per coding guidelines, "Write unit tests for new functionality". 🤖 Prompt for AI Agents |
||
|
|
||
| pub const LLMQ_50_60: LLMQParams = LLMQParams { | ||
| quorum_type: LLMQType::Llmqtype50_60, | ||
| name: "llmq_50_60", | ||
|
|
@@ -358,14 +402,14 @@ impl LLMQType { | |
| LLMQType::Llmqtype60_75 => LLMQ_60_75, | ||
| LLMQType::Llmqtype25_67 => LLMQ_25_67, | ||
| LLMQType::LlmqtypeTest => LLMQ_TEST, | ||
| LLMQType::LlmqtypeDevnet => LLMQ_DEVNET, | ||
| LLMQType::LlmqtypeDevnet => llmq_devnet_params(), | ||
| LLMQType::LlmqtypeTestV17 => LLMQ_V017, | ||
| LLMQType::LlmqtypeTestDIP0024 => LLMQ_TEST_DIP00024, | ||
| LLMQType::LlmqtypeTestInstantSend => LLMQ_TEST_INSTANT_SEND, | ||
| LLMQType::LlmqtypeDevnetDIP0024 => LLMQ_0024, | ||
| LLMQType::LlmqtypeTestnetPlatform => LLMQ_TEST_PLATFORM, | ||
| LLMQType::LlmqtypeDevnetPlatform => LLMQ_DEV_PLATFORM, | ||
| LLMQType::LlmqtypeUnknown => LLMQ_DEVNET, | ||
| LLMQType::LlmqtypeUnknown => llmq_devnet_params(), | ||
| } | ||
| } | ||
| pub fn size(&self) -> u32 { | ||
|
|
@@ -661,4 +705,40 @@ mod tests { | |
| assert_eq!(params.threshold, 67); | ||
| assert_eq!(params.signing_active_quorum_count, 24); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_llmq_devnet_override_lifecycle() { | ||
| // LLMQ_DEVNET_OVERRIDE is a process-global OnceLock, so the three contract | ||
| // checks (initial set, idempotent re-set, conflicting re-set) all run in | ||
| // this single test to avoid races between tests sharing the same lock. | ||
| set_llmq_devnet_params(LlmqDevnetParams { | ||
| size: 8, | ||
| threshold: 5, | ||
| }) | ||
| .expect("initial override should succeed"); | ||
|
|
||
| let params = llmq_devnet_params(); | ||
| assert_eq!(params.size, 8); | ||
| assert_eq!(params.min_size, 5); | ||
| assert_eq!(params.threshold, 5); | ||
| assert_eq!(params.dkg_params.bad_votes_threshold, 5); | ||
|
|
||
| set_llmq_devnet_params(LlmqDevnetParams { | ||
| size: 8, | ||
| threshold: 5, | ||
| }) | ||
| .expect("re-setting identical values should be idempotent"); | ||
| assert!( | ||
| set_llmq_devnet_params(LlmqDevnetParams { | ||
| size: 12, | ||
| threshold: 6, | ||
| }) | ||
| .is_err(), | ||
| "conflicting override must error" | ||
| ); | ||
|
|
||
| let params_after = llmq_devnet_params(); | ||
| assert_eq!(params_after.size, 8); | ||
| assert_eq!(params_after.threshold, 5); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apply_global_overridesidempotency contract doesn’t match implementation.The method comment says same-value calls are idempotent, but
OnceLock::setfails on every second call regardless of value. This can break creating multiple clients in one process.🤖 Prompt for AI Agents