Compare commits
1 Commits
frost
...
multiparty
Author | SHA1 | Date | |
---|---|---|---|
|
9c4e5b4d25 |
@ -28,6 +28,7 @@ electrum = ["electrum-client"]
|
||||
esplora = ["reqwest", "futures"]
|
||||
key-value-db = ["sled"]
|
||||
cli-utils = ["clap"]
|
||||
multiparty = []
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "0.2", features = ["macros"] }
|
||||
@ -50,6 +51,10 @@ name = "miniscriptc"
|
||||
path = "examples/compiler.rs"
|
||||
required-features = ["compiler"]
|
||||
|
||||
[[example]]
|
||||
name = "multiparty"
|
||||
required-features = ["multiparty","compiler"]
|
||||
|
||||
# Provide a more user-friendly alias for the REPL
|
||||
[[example]]
|
||||
name = "magic"
|
||||
|
96
examples/multiparty.rs
Normal file
96
examples/multiparty.rs
Normal file
@ -0,0 +1,96 @@
|
||||
extern crate bitcoin;
|
||||
extern crate clap;
|
||||
extern crate log;
|
||||
extern crate magical_bitcoin_wallet;
|
||||
extern crate miniscript;
|
||||
extern crate rand;
|
||||
extern crate serde_json;
|
||||
extern crate sled;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use log::info;
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
use bitcoin::PublicKey;
|
||||
|
||||
use miniscript::policy::Concrete;
|
||||
use miniscript::Descriptor;
|
||||
|
||||
use magical_bitcoin_wallet::multiparty::{Coordinator, Participant, Peer};
|
||||
|
||||
fn main() {
|
||||
env_logger::init_from_env(
|
||||
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
|
||||
);
|
||||
|
||||
let matches = App::new("Multiparty Tools")
|
||||
.arg(
|
||||
Arg::with_name("POLICY")
|
||||
.help("Sets the spending policy to compile")
|
||||
.required(true)
|
||||
.index(1),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("TYPE")
|
||||
.help("Sets the script type used to embed the compiled policy")
|
||||
.required(true)
|
||||
.index(2)
|
||||
.possible_values(&["sh", "wsh", "sh-wsh"]),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let policy_str = matches.value_of("POLICY").unwrap();
|
||||
info!("Compiling policy: {}", policy_str);
|
||||
|
||||
let policy = Concrete::<String>::from_str(&policy_str).unwrap();
|
||||
let compiled = policy.compile().unwrap();
|
||||
|
||||
let descriptor = match matches.value_of("TYPE").unwrap() {
|
||||
"sh" => Descriptor::Sh(compiled),
|
||||
"wsh" => Descriptor::Wsh(compiled),
|
||||
"sh-wsh" => Descriptor::ShWsh(compiled),
|
||||
_ => panic!("Invalid type"),
|
||||
};
|
||||
|
||||
info!("Descriptor: {}", descriptor);
|
||||
|
||||
let mut coordinator: Participant<Coordinator> = Participant::new(descriptor).unwrap();
|
||||
/*let policy = coordinator.policy_for(vec![]).unwrap();
|
||||
info!(
|
||||
"Policy:\n{}",
|
||||
serde_json::to_string_pretty(&policy).unwrap()
|
||||
);*/
|
||||
|
||||
let missing_keys = coordinator.missing_keys();
|
||||
info!("Missing keys: {:?}", missing_keys);
|
||||
|
||||
let pk =
|
||||
PublicKey::from_str("02c65413e56b343a0a31c18d506f1502a17fc64dfbcef6bfb00d1c0d6229bb6f61")
|
||||
.unwrap();
|
||||
coordinator.add_key("Alice", pk.into()).unwrap();
|
||||
coordinator.add_key("Carol", pk.into()).unwrap();
|
||||
|
||||
let for_bob = coordinator.descriptor_for("Bob").unwrap();
|
||||
info!("Descriptor for Bob: {}", for_bob);
|
||||
|
||||
let mut bob_peer: Participant<Peer> = Participant::new(for_bob).unwrap();
|
||||
info!(
|
||||
"Bob's policy: {}",
|
||||
serde_json::to_string(&bob_peer.policy().unwrap().unwrap()).unwrap()
|
||||
);
|
||||
bob_peer.use_key(pk.into()).unwrap();
|
||||
info!("Bob's my_key: {}", bob_peer.my_key().unwrap());
|
||||
|
||||
coordinator.add_key("Bob", pk.into()).unwrap();
|
||||
info!("Coordinator completed: {}", coordinator.completed());
|
||||
|
||||
let coord_map = coordinator.get_map().unwrap();
|
||||
|
||||
let finalized = coordinator.finalize().unwrap();
|
||||
info!("Coordinator final: {}", finalized);
|
||||
|
||||
let bob_finalized = bob_peer.apply_map(coord_map).unwrap();
|
||||
info!("Bob final: {}", bob_finalized);
|
||||
}
|
@ -6,6 +6,12 @@ pub enum Error {
|
||||
MalformedInput,
|
||||
KeyParsingError(String),
|
||||
|
||||
AliasAsPublicKey,
|
||||
KeyHasSecret,
|
||||
Incomplete,
|
||||
MissingAlias(String),
|
||||
InvalidAlias(String),
|
||||
|
||||
Policy(crate::descriptor::policy::PolicyError),
|
||||
|
||||
InputIndexDoesntExist,
|
||||
|
@ -1,3 +1,6 @@
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use bitcoin::secp256k1::{All, Secp256k1};
|
||||
use bitcoin::{PrivateKey, PublicKey};
|
||||
|
||||
@ -9,34 +12,39 @@ use super::error::Error;
|
||||
use super::extended_key::DerivationIndex;
|
||||
use super::DescriptorExtendedKey;
|
||||
|
||||
pub(super) trait Key: std::fmt::Debug + std::fmt::Display {
|
||||
fn fingerprint(&self, secp: &Secp256k1<All>) -> Option<Fingerprint>;
|
||||
fn as_public_key(&self, secp: &Secp256k1<All>, index: Option<u32>) -> Result<PublicKey, Error>;
|
||||
fn as_secret_key(&self) -> Option<PrivateKey>;
|
||||
fn xprv(&self) -> Option<ExtendedPrivKey>;
|
||||
fn full_path(&self, index: u32) -> Option<DerivationPath>;
|
||||
fn is_fixed(&self) -> bool;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KeyAlias {
|
||||
alias: String,
|
||||
has_secret: bool,
|
||||
}
|
||||
|
||||
fn has_secret(&self) -> bool {
|
||||
self.xprv().is_some() || self.as_secret_key().is_some()
|
||||
}
|
||||
|
||||
fn public(&self, secp: &Secp256k1<All>) -> Result<Box<dyn Key>, Error> {
|
||||
Ok(Box::new(self.as_public_key(secp, None)?))
|
||||
impl KeyAlias {
|
||||
pub(crate) fn new_boxed(alias: &str, has_secret: bool) -> Box<dyn Key> {
|
||||
Box::new(KeyAlias {
|
||||
alias: alias.into(),
|
||||
has_secret,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for PublicKey {
|
||||
fn fingerprint(&self, _secp: &Secp256k1<All>) -> Option<Fingerprint> {
|
||||
None
|
||||
pub(crate) fn parse_key(string: &str) -> Result<(String, Box<dyn RealKey>), Error> {
|
||||
if let Ok(pk) = PublicKey::from_str(string) {
|
||||
return Ok((string.to_string(), Box::new(pk)));
|
||||
} else if let Ok(sk) = PrivateKey::from_wif(string) {
|
||||
return Ok((string.to_string(), Box::new(sk)));
|
||||
} else if let Ok(ext_key) = DescriptorExtendedKey::from_str(string) {
|
||||
return Ok((string.to_string(), Box::new(ext_key)));
|
||||
}
|
||||
|
||||
fn as_public_key(
|
||||
&self,
|
||||
_secp: &Secp256k1<All>,
|
||||
_index: Option<u32>,
|
||||
) -> Result<PublicKey, Error> {
|
||||
Ok(PublicKey::clone(self))
|
||||
return Err(Error::KeyParsingError(string.to_string()));
|
||||
}
|
||||
|
||||
pub trait Key: std::fmt::Debug + std::fmt::Display {
|
||||
fn as_public_key(&self, secp: &Secp256k1<All>, index: Option<u32>) -> Result<PublicKey, Error>;
|
||||
fn is_fixed(&self) -> bool;
|
||||
|
||||
fn alias(&self) -> Option<&str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_secret_key(&self) -> Option<PrivateKey> {
|
||||
@ -51,16 +59,50 @@ impl Key for PublicKey {
|
||||
None
|
||||
}
|
||||
|
||||
fn fingerprint(&self, _secp: &Secp256k1<All>) -> Option<Fingerprint> {
|
||||
None
|
||||
}
|
||||
|
||||
fn has_secret(&self) -> bool {
|
||||
self.xprv().is_some() || self.as_secret_key().is_some()
|
||||
}
|
||||
|
||||
fn public(&self, secp: &Secp256k1<All>) -> Result<Box<dyn RealKey>, Error> {
|
||||
Ok(Box::new(self.as_public_key(secp, None)?))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RealKey: Key {
|
||||
fn into_key(&self) -> Box<dyn Key>;
|
||||
}
|
||||
|
||||
impl<T: RealKey + 'static> From<T> for Box<dyn RealKey> {
|
||||
fn from(key: T) -> Self {
|
||||
Box::new(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for PublicKey {
|
||||
fn as_public_key(
|
||||
&self,
|
||||
_secp: &Secp256k1<All>,
|
||||
_index: Option<u32>,
|
||||
) -> Result<PublicKey, Error> {
|
||||
Ok(PublicKey::clone(self))
|
||||
}
|
||||
|
||||
fn is_fixed(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for PrivateKey {
|
||||
fn fingerprint(&self, _secp: &Secp256k1<All>) -> Option<Fingerprint> {
|
||||
None
|
||||
impl RealKey for PublicKey {
|
||||
fn into_key(&self) -> Box<dyn Key> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for PrivateKey {
|
||||
fn as_public_key(
|
||||
&self,
|
||||
secp: &Secp256k1<All>,
|
||||
@ -73,18 +115,15 @@ impl Key for PrivateKey {
|
||||
Some(PrivateKey::clone(self))
|
||||
}
|
||||
|
||||
fn xprv(&self) -> Option<ExtendedPrivKey> {
|
||||
None
|
||||
}
|
||||
|
||||
fn full_path(&self, _index: u32) -> Option<DerivationPath> {
|
||||
None
|
||||
}
|
||||
|
||||
fn is_fixed(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
impl RealKey for PrivateKey {
|
||||
fn into_key(&self) -> Box<dyn Key> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for DescriptorExtendedKey {
|
||||
fn fingerprint(&self, secp: &Secp256k1<All>) -> Option<Fingerprint> {
|
||||
@ -99,7 +138,7 @@ impl Key for DescriptorExtendedKey {
|
||||
Ok(self.derive_xpub(secp, index.unwrap_or(0))?.public_key)
|
||||
}
|
||||
|
||||
fn public(&self, secp: &Secp256k1<All>) -> Result<Box<dyn Key>, Error> {
|
||||
fn public(&self, secp: &Secp256k1<All>) -> Result<Box<dyn RealKey>, Error> {
|
||||
if self.final_index == DerivationIndex::Hardened {
|
||||
return Err(Error::HardenedDerivationOnXpub);
|
||||
}
|
||||
@ -163,10 +202,6 @@ impl Key for DescriptorExtendedKey {
|
||||
}))
|
||||
}
|
||||
|
||||
fn as_secret_key(&self) -> Option<PrivateKey> {
|
||||
None
|
||||
}
|
||||
|
||||
fn xprv(&self) -> Option<ExtendedPrivKey> {
|
||||
self.secret
|
||||
}
|
||||
@ -179,3 +214,67 @@ impl Key for DescriptorExtendedKey {
|
||||
self.final_index == DerivationIndex::Fixed
|
||||
}
|
||||
}
|
||||
impl RealKey for DescriptorExtendedKey {
|
||||
fn into_key(&self) -> Box<dyn Key> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for KeyAlias {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let flag = if self.has_secret { "#" } else { "" };
|
||||
|
||||
write!(f, "{}{}", flag, self.alias)
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for KeyAlias {
|
||||
fn as_public_key(
|
||||
&self,
|
||||
_secp: &Secp256k1<All>,
|
||||
_index: Option<u32>,
|
||||
) -> Result<PublicKey, Error> {
|
||||
Err(Error::AliasAsPublicKey)
|
||||
}
|
||||
|
||||
fn is_fixed(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn alias(&self) -> Option<&str> {
|
||||
Some(self.alias.as_str())
|
||||
}
|
||||
|
||||
fn has_secret(&self) -> bool {
|
||||
self.has_secret
|
||||
}
|
||||
|
||||
fn public(&self, _secp: &Secp256k1<All>) -> Result<Box<dyn RealKey>, Error> {
|
||||
Err(Error::AliasAsPublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, PartialOrd, Eq, Ord, Default)]
|
||||
pub(crate) struct DummyKey();
|
||||
|
||||
impl fmt::Display for DummyKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "DummyKey")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for DummyKey {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(_: &str) -> Result<Self, Self::Err> {
|
||||
Ok(DummyKey::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl miniscript::MiniscriptKey for DummyKey {
|
||||
type Hash = DummyKey;
|
||||
|
||||
fn to_pubkeyhash(&self) -> DummyKey {
|
||||
DummyKey::default()
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use crate::psbt::utils::PSBTUtils;
|
||||
pub mod checksum;
|
||||
pub mod error;
|
||||
pub mod extended_key;
|
||||
mod keys;
|
||||
pub mod keys;
|
||||
pub mod policy;
|
||||
|
||||
pub use self::checksum::get_checksum;
|
||||
@ -27,9 +27,9 @@ use self::error::Error;
|
||||
pub use self::extended_key::{DerivationIndex, DescriptorExtendedKey};
|
||||
pub use self::policy::Policy;
|
||||
|
||||
use self::keys::Key;
|
||||
use self::keys::{parse_key, DummyKey, Key, RealKey};
|
||||
|
||||
trait MiniscriptExtractPolicy {
|
||||
pub(crate) trait MiniscriptExtractPolicy {
|
||||
fn extract_policy(
|
||||
&self,
|
||||
lookup_map: &BTreeMap<String, Box<dyn Key>>,
|
||||
@ -40,31 +40,6 @@ pub trait ExtractPolicy {
|
||||
fn extract_policy(&self) -> Result<Option<Policy>, Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, PartialOrd, Eq, Ord, Default)]
|
||||
struct DummyKey();
|
||||
|
||||
impl fmt::Display for DummyKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "DummyKey")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for DummyKey {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(_: &str) -> Result<Self, Self::Err> {
|
||||
Ok(DummyKey::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl miniscript::MiniscriptKey for DummyKey {
|
||||
type Hash = DummyKey;
|
||||
|
||||
fn to_pubkeyhash(&self) -> DummyKey {
|
||||
DummyKey::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub type DerivedDescriptor = Descriptor<PublicKey>;
|
||||
pub type StringDescriptor = Descriptor<String>;
|
||||
|
||||
@ -112,13 +87,13 @@ where
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ExtendedDescriptor {
|
||||
#[serde(flatten)]
|
||||
internal: StringDescriptor,
|
||||
pub(crate) internal: StringDescriptor,
|
||||
|
||||
#[serde(skip)]
|
||||
keys: BTreeMap<String, Box<dyn Key>>,
|
||||
pub(crate) keys: BTreeMap<String, Box<dyn RealKey>>,
|
||||
|
||||
#[serde(skip)]
|
||||
ctx: Secp256k1<All>,
|
||||
pub(crate) ctx: Secp256k1<All>,
|
||||
}
|
||||
|
||||
impl fmt::Display for ExtendedDescriptor {
|
||||
@ -144,30 +119,18 @@ impl std::convert::AsRef<StringDescriptor> for ExtendedDescriptor {
|
||||
}
|
||||
|
||||
impl ExtendedDescriptor {
|
||||
fn parse_string(string: &str) -> Result<(String, Box<dyn Key>), Error> {
|
||||
if let Ok(pk) = PublicKey::from_str(string) {
|
||||
return Ok((string.to_string(), Box::new(pk)));
|
||||
} else if let Ok(sk) = PrivateKey::from_wif(string) {
|
||||
return Ok((string.to_string(), Box::new(sk)));
|
||||
} else if let Ok(ext_key) = DescriptorExtendedKey::from_str(string) {
|
||||
return Ok((string.to_string(), Box::new(ext_key)));
|
||||
}
|
||||
|
||||
return Err(Error::KeyParsingError(string.to_string()));
|
||||
}
|
||||
|
||||
fn new(sd: StringDescriptor) -> Result<Self, Error> {
|
||||
let ctx = Secp256k1::gen_new();
|
||||
let keys: RefCell<BTreeMap<String, Box<dyn Key>>> = RefCell::new(BTreeMap::new());
|
||||
let keys: RefCell<BTreeMap<String, Box<dyn RealKey>>> = RefCell::new(BTreeMap::new());
|
||||
|
||||
let translatefpk = |string: &String| -> Result<_, Error> {
|
||||
let (key, parsed) = Self::parse_string(string)?;
|
||||
let (key, parsed) = parse_key(string)?;
|
||||
keys.borrow_mut().insert(key, parsed);
|
||||
|
||||
Ok(DummyKey::default())
|
||||
};
|
||||
let translatefpkh = |string: &String| -> Result<_, Error> {
|
||||
let (key, parsed) = Self::parse_string(string)?;
|
||||
let (key, parsed) = parse_key(string)?;
|
||||
keys.borrow_mut().insert(key, parsed);
|
||||
|
||||
Ok(DummyKey::default())
|
||||
@ -329,7 +292,7 @@ impl ExtendedDescriptor {
|
||||
}
|
||||
|
||||
pub fn as_public_version(&self) -> Result<ExtendedDescriptor, Error> {
|
||||
let keys: RefCell<BTreeMap<String, Box<dyn Key>>> = RefCell::new(BTreeMap::new());
|
||||
let keys: RefCell<BTreeMap<String, Box<dyn RealKey>>> = RefCell::new(BTreeMap::new());
|
||||
|
||||
let translatefpk = |string: &String| -> Result<_, Error> {
|
||||
let public = self.keys.get(string).unwrap().public(&self.ctx)?;
|
||||
@ -360,7 +323,13 @@ impl ExtendedDescriptor {
|
||||
|
||||
impl ExtractPolicy for ExtendedDescriptor {
|
||||
fn extract_policy(&self) -> Result<Option<Policy>, Error> {
|
||||
self.internal.extract_policy(&self.keys)
|
||||
self.internal.extract_policy(
|
||||
&self
|
||||
.keys
|
||||
.iter()
|
||||
.map(|(k, v)| (k.into(), v.into_key()))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,19 +27,27 @@ pub struct PKOrF {
|
||||
pubkey_hash: Option<hash160::Hash>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
fingerprint: Option<Fingerprint>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
alias: Option<String>,
|
||||
}
|
||||
|
||||
impl PKOrF {
|
||||
fn from_key(k: &Box<dyn Key>) -> Self {
|
||||
let secp = Secp256k1::gen_new();
|
||||
|
||||
let pubkey = k.as_public_key(&secp, None).unwrap();
|
||||
if let Some(fing) = k.fingerprint(&secp) {
|
||||
if let Some(alias) = k.alias() {
|
||||
PKOrF {
|
||||
alias: Some(alias.into()),
|
||||
..Default::default()
|
||||
}
|
||||
} else if let Some(fing) = k.fingerprint(&secp) {
|
||||
PKOrF {
|
||||
fingerprint: Some(fing),
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
let pubkey = k.as_public_key(&secp, None).unwrap();
|
||||
PKOrF {
|
||||
pubkey: Some(pubkey),
|
||||
..Default::default()
|
||||
|
@ -33,6 +33,8 @@ pub mod error;
|
||||
pub mod blockchain;
|
||||
pub mod database;
|
||||
pub mod descriptor;
|
||||
#[cfg(feature = "multiparty")]
|
||||
pub mod multiparty;
|
||||
pub mod psbt;
|
||||
pub mod signer;
|
||||
pub mod types;
|
||||
|
231
src/multiparty/mod.rs
Normal file
231
src/multiparty/mod.rs
Normal file
@ -0,0 +1,231 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
|
||||
use crate::descriptor::error::Error;
|
||||
use crate::descriptor::keys::{parse_key, DummyKey, Key, KeyAlias, RealKey};
|
||||
use crate::descriptor::{ExtendedDescriptor, MiniscriptExtractPolicy, Policy, StringDescriptor};
|
||||
|
||||
pub trait ParticipantType: Default {
|
||||
fn validate_aliases(aliases: Vec<&String>) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Coordinator {}
|
||||
impl ParticipantType for Coordinator {
|
||||
fn validate_aliases(aliases: Vec<&String>) -> Result<(), Error> {
|
||||
if aliases.into_iter().any(|a| a == "[PEER]") {
|
||||
Err(Error::InvalidAlias("[PEER]".into()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Peer;
|
||||
impl ParticipantType for Peer {
|
||||
fn validate_aliases(aliases: Vec<&String>) -> Result<(), Error> {
|
||||
if !aliases.into_iter().any(|a| a == "[PEER]") {
|
||||
Err(Error::MissingAlias("[PEER]".into()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Participant<T: ParticipantType> {
|
||||
descriptor: StringDescriptor,
|
||||
parsed_keys: BTreeMap<String, Box<dyn Key>>,
|
||||
received_keys: BTreeMap<String, Box<dyn RealKey>>,
|
||||
|
||||
_data: T,
|
||||
}
|
||||
|
||||
impl<T: ParticipantType> Participant<T> {
|
||||
pub fn new(sd: StringDescriptor) -> Result<Self, Error> {
|
||||
let parsed_keys = Self::parse_keys(&sd, vec![]);
|
||||
|
||||
T::validate_aliases(parsed_keys.keys().collect())?;
|
||||
|
||||
Ok(Participant {
|
||||
descriptor: sd,
|
||||
parsed_keys,
|
||||
received_keys: Default::default(),
|
||||
_data: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_keys(
|
||||
sd: &StringDescriptor,
|
||||
with_secrets: Vec<&str>,
|
||||
) -> BTreeMap<String, Box<dyn Key>> {
|
||||
let keys: RefCell<BTreeMap<String, Box<dyn Key>>> = RefCell::new(BTreeMap::new());
|
||||
|
||||
let translatefpk = |string: &String| -> Result<_, Error> {
|
||||
let (key, parsed) = match parse_key(string) {
|
||||
Ok((key, parsed)) => (key, parsed.into_key()),
|
||||
Err(_) => (
|
||||
string.clone(),
|
||||
KeyAlias::new_boxed(string.as_str(), with_secrets.contains(&string.as_str())),
|
||||
),
|
||||
};
|
||||
keys.borrow_mut().insert(key, parsed);
|
||||
|
||||
Ok(DummyKey::default())
|
||||
};
|
||||
let translatefpkh = |string: &String| -> Result<_, Error> {
|
||||
let (key, parsed) = match parse_key(string) {
|
||||
Ok((key, parsed)) => (key, parsed.into_key()),
|
||||
Err(_) => (
|
||||
string.clone(),
|
||||
KeyAlias::new_boxed(string.as_str(), with_secrets.contains(&string.as_str())),
|
||||
),
|
||||
};
|
||||
keys.borrow_mut().insert(key, parsed);
|
||||
|
||||
Ok(DummyKey::default())
|
||||
};
|
||||
|
||||
sd.translate_pk(translatefpk, translatefpkh).unwrap();
|
||||
|
||||
keys.into_inner()
|
||||
}
|
||||
|
||||
pub fn policy_for(&self, with_secrets: Vec<&str>) -> Result<Option<Policy>, Error> {
|
||||
let keys = Self::parse_keys(&self.descriptor, with_secrets);
|
||||
self.descriptor.extract_policy(&keys)
|
||||
}
|
||||
|
||||
fn _missing_keys(&self) -> Vec<&String> {
|
||||
self.parsed_keys
|
||||
.keys()
|
||||
.filter(|k| !self.received_keys.contains_key(*k))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn completed(&self) -> bool {
|
||||
self._missing_keys().is_empty()
|
||||
}
|
||||
|
||||
pub fn finalize(self) -> Result<ExtendedDescriptor, Error> {
|
||||
if !self.completed() {
|
||||
return Err(Error::Incomplete);
|
||||
}
|
||||
|
||||
let translatefpk = |string: &String| -> Result<_, Error> {
|
||||
Ok(format!(
|
||||
"{}",
|
||||
self.received_keys
|
||||
.get(string)
|
||||
.expect(&format!("Missing key: `{}`", string))
|
||||
))
|
||||
};
|
||||
let translatefpkh = |string: &String| -> Result<_, Error> {
|
||||
Ok(format!(
|
||||
"{}",
|
||||
self.received_keys
|
||||
.get(string)
|
||||
.expect(&format!("Missing key: `{}`", string))
|
||||
))
|
||||
};
|
||||
|
||||
let internal = self.descriptor.translate_pk(translatefpk, translatefpkh)?;
|
||||
|
||||
Ok(ExtendedDescriptor {
|
||||
internal,
|
||||
keys: self.received_keys,
|
||||
ctx: Secp256k1::gen_new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Participant<Coordinator> {
|
||||
pub fn descriptor(&self) -> &StringDescriptor {
|
||||
&self.descriptor
|
||||
}
|
||||
|
||||
pub fn add_key(&mut self, alias: &str, key: Box<dyn RealKey>) -> Result<(), Error> {
|
||||
// TODO: check network
|
||||
|
||||
if key.has_secret() {
|
||||
return Err(Error::KeyHasSecret);
|
||||
}
|
||||
|
||||
self.received_keys.insert(alias.into(), key);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn received_keys(&self) -> Vec<&String> {
|
||||
self.received_keys.keys().collect()
|
||||
}
|
||||
|
||||
pub fn missing_keys(&self) -> Vec<&String> {
|
||||
self._missing_keys()
|
||||
}
|
||||
|
||||
pub fn descriptor_for(&self, alias: &str) -> Result<StringDescriptor, Error> {
|
||||
if !self.parsed_keys.contains_key(alias) {
|
||||
return Err(Error::MissingAlias(alias.into()));
|
||||
}
|
||||
|
||||
let map_name = |s: &String| {
|
||||
if s == alias {
|
||||
"[PEER]".into()
|
||||
} else {
|
||||
s.into()
|
||||
}
|
||||
};
|
||||
|
||||
let translatefpk = |string: &String| -> Result<_, Error> { Ok(map_name(string)) };
|
||||
let translatefpkh = |string: &String| -> Result<_, Error> { Ok(map_name(string)) };
|
||||
|
||||
Ok(self.descriptor.translate_pk(translatefpk, translatefpkh)?)
|
||||
}
|
||||
|
||||
pub fn get_map(&self) -> Result<BTreeMap<String, String>, Error> {
|
||||
if !self.completed() {
|
||||
return Err(Error::Incomplete);
|
||||
}
|
||||
|
||||
Ok(self
|
||||
.received_keys
|
||||
.iter()
|
||||
.map(|(k, v)| (k.into(), format!("{}", v)))
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl Participant<Peer> {
|
||||
pub fn policy(&self) -> Result<Option<Policy>, Error> {
|
||||
self.policy_for(vec!["[PEER]"])
|
||||
}
|
||||
|
||||
pub fn use_key(&mut self, key: Box<dyn RealKey>) -> Result<(), Error> {
|
||||
let secp = Secp256k1::gen_new();
|
||||
self.received_keys
|
||||
.insert("[PEER]".into(), key.public(&secp)?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn my_key(&mut self) -> Option<&Box<dyn RealKey>> {
|
||||
self.received_keys.get("[PEER]".into())
|
||||
}
|
||||
|
||||
pub fn apply_map(mut self, map: BTreeMap<String, String>) -> Result<ExtendedDescriptor, Error> {
|
||||
let mut parsed_map: BTreeMap<_, _> = map
|
||||
.into_iter()
|
||||
.map(|(k, v)| -> Result<_, Error> {
|
||||
let (_, parsed) = parse_key(&v)?;
|
||||
Ok((k, parsed))
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
self.received_keys.append(&mut parsed_map);
|
||||
|
||||
self.finalize()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user