diff --git a/doc/API.md b/doc/API.md index b0fb5042..00a6be8a 100644 --- a/doc/API.md +++ b/doc/API.md @@ -62,7 +62,7 @@ Display general information about the current daemon state. | `vaults` | integer | Current number of vaults (unconfirmed are included) | | `managers_threshold` | integer | Number of managers needed for spending the `unvault_tx` | | `descriptors` | object | Three `string` entries: `deposit`, `unvault` and `cpfp` for the three Miniscript descriptors | - +| `participant_type` | string | Answer can be `stakeholder`, `manager`, `stakeholdermanager` | ### `getdepositaddress` diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 5807a6f3..31d9cd8c 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -8,7 +8,7 @@ mod utils; pub use crate::{ bitcoind::{interface::WalletTransaction, BitcoindError}, communication::ServerStatus, - revaultd::{BlockchainTip, VaultStatus}, + revaultd::{BlockchainTip, UserRole, VaultStatus}, }; use crate::{ communication::{ @@ -268,6 +268,15 @@ impl DaemonControl { }) .count(); + assert!(revaultd.is_stakeholder() || revaultd.is_manager()); + let participant_type = if revaultd.is_manager() && revaultd.is_stakeholder() { + UserRole::StakeholderManager + } else if revaultd.is_manager() { + UserRole::Manager + } else { + UserRole::Stakeholder + }; + GetInfoResult { version: VERSION.to_string(), network: revaultd.bitcoind_config.network, @@ -280,6 +289,7 @@ impl DaemonControl { unvault: revaultd.unvault_descriptor.clone(), cpfp: revaultd.cpfp_descriptor.clone(), }, + participant_type, } } @@ -1430,6 +1440,8 @@ pub struct GetInfoResult { pub vaults: usize, pub managers_threshold: usize, pub descriptors: GetInfoDescriptors, + #[serde(serialize_with = "ser_to_string", deserialize_with = "deser_from_str")] + pub participant_type: UserRole, } /// Information about a vault. diff --git a/src/revaultd.rs b/src/revaultd.rs index 8d746101..c389a9ef 100644 --- a/src/revaultd.rs +++ b/src/revaultd.rs @@ -283,6 +283,33 @@ pub enum UserRole { StakeholderManager, } +impl FromStr for UserRole { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "stakeholder" => Ok(Self::Stakeholder), + "stakeholdermanager" => Ok(Self::StakeholderManager), + "manager" => Ok(Self::Manager), + _ => Err(format!("Unknown role: {}", s)), + } + } +} + +impl fmt::Display for UserRole { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match *self { + Self::Stakeholder => "stakeholder", + Self::Manager => "manager", + Self::StakeholderManager => "stakeholdermanager", + } + ) + } +} + /// Our global state pub struct RevaultD { // Bitcoind stuff diff --git a/tests/test_rpc.py b/tests/test_rpc.py index 95dd5b3e..70bc954f 100644 --- a/tests/test_rpc.py +++ b/tests/test_rpc.py @@ -27,6 +27,7 @@ def test_getinfo(revaultd_manager, bitcoind): assert res["vaults"] == 0 # revaultd_manager always deploys with N = 2, M = 3, threshold = M assert res["managers_threshold"] == 3 + assert res["participant_type"] == "manager" # test descriptors: RPC call & which Revaultd's were configured assert res["descriptors"]["cpfp"] == revaultd_manager.cpfp_desc assert res["descriptors"]["deposit"] == revaultd_manager.deposit_desc