[wallet] Add explicit ordering for the signers

This commit is contained in:
Alekos Filini 2020-08-17 12:10:51 +02:00
parent f54243fd18
commit 991db28170
No known key found for this signature in database
GPG Key ID: 5E8AFC3034FDFA4F
2 changed files with 89 additions and 16 deletions

View File

@ -24,7 +24,7 @@ pub mod tx_builder;
pub mod utils; pub mod utils;
use address_validator::AddressValidator; use address_validator::AddressValidator;
use signer::{Signer, SignerId, SignersContainer}; use signer::{Signer, SignerId, SignerOrdering, SignersContainer};
use tx_builder::TxBuilder; use tx_builder::TxBuilder;
use utils::{After, FeeRate, IsDust, Older}; use utils::{After, FeeRate, IsDust, Older};
@ -142,6 +142,7 @@ where
&mut self, &mut self,
script_type: ScriptType, script_type: ScriptType,
id: SignerId<DescriptorPublicKey>, id: SignerId<DescriptorPublicKey>,
ordering: SignerOrdering,
signer: Arc<Box<dyn Signer>>, signer: Arc<Box<dyn Signer>>,
) { ) {
let signers = match script_type { let signers = match script_type {
@ -149,7 +150,7 @@ where
ScriptType::Internal => Arc::make_mut(&mut self.change_signers), ScriptType::Internal => Arc::make_mut(&mut self.change_signers),
}; };
signers.add_external(id, signer); signers.add_external(id, ordering, signer);
} }
pub fn add_address_validator(&mut self, validator: Arc<Box<dyn AddressValidator>>) { pub fn add_address_validator(&mut self, validator: Arc<Box<dyn AddressValidator>>) {
@ -575,15 +576,18 @@ where
Ok((psbt, details)) Ok((psbt, details))
} }
// TODO: define an enum for signing errors
pub fn sign(&self, mut psbt: PSBT, assume_height: Option<u32>) -> Result<(PSBT, bool), Error> { pub fn sign(&self, mut psbt: PSBT, assume_height: Option<u32>) -> Result<(PSBT, bool), Error> {
// this helps us doing our job later // this helps us doing our job later
self.add_input_hd_keypaths(&mut psbt)?; self.add_input_hd_keypaths(&mut psbt)?;
for index in 0..psbt.inputs.len() { for signer in self
self.signers.sign(&mut psbt, index)?; .signers
if self.change_descriptor.is_some() { .signers()
self.change_signers.sign(&mut psbt, index)?; .iter()
.chain(self.change_signers.signers().iter())
{
for index in 0..psbt.inputs.len() {
signer.sign(&mut psbt, index)?;
} }
} }

View File

@ -1,6 +1,8 @@
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::ops::Bound::Included;
use std::sync::Arc; use std::sync::Arc;
use bitcoin::blockdata::opcodes; use bitcoin::blockdata::opcodes;
@ -150,9 +152,35 @@ impl Signer for PrivateKey {
} }
} }
#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq)]
pub struct SignerOrdering(pub usize);
impl std::default::Default for SignerOrdering {
fn default() -> Self {
SignerOrdering(100)
}
}
#[derive(Debug, Clone)]
struct SignersContainerKey<Pk: MiniscriptKey> {
id: SignerId<Pk>,
ordering: SignerOrdering,
}
impl<Pk: MiniscriptKey> From<(SignerId<Pk>, SignerOrdering)> for SignersContainerKey<Pk> {
fn from(tuple: (SignerId<Pk>, SignerOrdering)) -> Self {
SignersContainerKey {
id: tuple.0,
ordering: tuple.1,
}
}
}
/// Container for multiple signers /// Container for multiple signers
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct SignersContainer<Pk: MiniscriptKey>(HashMap<SignerId<Pk>, Arc<Box<dyn Signer>>>); pub struct SignersContainer<Pk: MiniscriptKey>(
BTreeMap<SignersContainerKey<Pk>, Arc<Box<dyn Signer>>>,
);
impl SignersContainer<DescriptorPublicKey> { impl SignersContainer<DescriptorPublicKey> {
pub fn as_key_map(&self) -> KeyMap { pub fn as_key_map(&self) -> KeyMap {
@ -190,10 +218,12 @@ impl From<KeyMap> for SignersContainer<DescriptorPublicKey> {
.public_key(&Secp256k1::signing_only()) .public_key(&Secp256k1::signing_only())
.to_pubkeyhash(), .to_pubkeyhash(),
), ),
SignerOrdering::default(),
Arc::new(Box::new(private_key)), Arc::new(Box::new(private_key)),
), ),
DescriptorSecretKey::XPrv(xprv) => container.add_external( DescriptorSecretKey::XPrv(xprv) => container.add_external(
SignerId::from(xprv.root_fingerprint()), SignerId::from(xprv.root_fingerprint()),
SignerOrdering::default(),
Arc::new(Box::new(xprv)), Arc::new(Box::new(xprv)),
), ),
}; };
@ -206,7 +236,7 @@ impl From<KeyMap> for SignersContainer<DescriptorPublicKey> {
impl<Pk: MiniscriptKey> SignersContainer<Pk> { impl<Pk: MiniscriptKey> SignersContainer<Pk> {
/// Default constructor /// Default constructor
pub fn new() -> Self { pub fn new() -> Self {
SignersContainer(HashMap::new()) SignersContainer(Default::default())
} }
/// Adds an external signer to the container for the specified id. Optionally returns the /// Adds an external signer to the container for the specified id. Optionally returns the
@ -214,24 +244,43 @@ impl<Pk: MiniscriptKey> SignersContainer<Pk> {
pub fn add_external( pub fn add_external(
&mut self, &mut self,
id: SignerId<Pk>, id: SignerId<Pk>,
ordering: SignerOrdering,
signer: Arc<Box<dyn Signer>>, signer: Arc<Box<dyn Signer>>,
) -> Option<Arc<Box<dyn Signer>>> { ) -> Option<Arc<Box<dyn Signer>>> {
self.0.insert(id, signer) self.0.insert((id, ordering).into(), signer)
} }
/// Removes a signer from the container and returns it /// Removes a signer from the container and returns it
pub fn remove(&mut self, id: SignerId<Pk>) -> Option<Arc<Box<dyn Signer>>> { pub fn remove(
self.0.remove(&id) &mut self,
id: SignerId<Pk>,
ordering: SignerOrdering,
) -> Option<Arc<Box<dyn Signer>>> {
self.0.remove(&(id, ordering).into())
} }
/// Returns the list of identifiers of all the signers in the container /// Returns the list of identifiers of all the signers in the container
pub fn ids(&self) -> Vec<&SignerId<Pk>> { pub fn ids(&self) -> Vec<&SignerId<Pk>> {
self.0.keys().collect() self.0
.keys()
.map(|SignersContainerKey { id, .. }| id)
.collect()
} }
/// Finds the signer with a given id in the container /// Returns the list of signers in the container, sorted by lowest to highest `ordering`
pub fn signers(&self) -> Vec<&Arc<Box<dyn Signer>>> {
self.0.values().collect()
}
/// Finds the signer with lowest ordering for a given id in the container.
pub fn find(&self, id: SignerId<Pk>) -> Option<&Arc<Box<dyn Signer>>> { pub fn find(&self, id: SignerId<Pk>) -> Option<&Arc<Box<dyn Signer>>> {
self.0.get(&id) self.0
.range((
Included(&(id.clone(), SignerOrdering(0)).into()),
Included(&(id, SignerOrdering(usize::MAX)).into()),
))
.map(|(_, v)| v)
.nth(0)
} }
} }
@ -327,3 +376,23 @@ impl ComputeSighash for Segwitv0 {
)) ))
} }
} }
impl<Pk: MiniscriptKey> PartialOrd for SignersContainerKey<Pk> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<Pk: MiniscriptKey> Ord for SignersContainerKey<Pk> {
fn cmp(&self, other: &Self) -> Ordering {
self.ordering.cmp(&other.ordering)
}
}
impl<Pk: MiniscriptKey> PartialEq for SignersContainerKey<Pk> {
fn eq(&self, other: &Self) -> bool {
self.ordering == other.ordering
}
}
impl<Pk: MiniscriptKey> Eq for SignersContainerKey<Pk> {}