Skip to content

Commit

Permalink
Batch sign messages (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabiazcona authored Mar 25, 2022
1 parent df0aff4 commit 1a0a5a5
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 5 deletions.
38 changes: 37 additions & 1 deletion src/account.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{CryptoType, Network, Pair};
use core::mem;

const ROOT_ACCOUNT: &str = "ROOT";

Expand All @@ -10,11 +11,13 @@ pub enum Account<'a, P> {
Root {
pair: P,
network: Network,
pending_sign: Vec<Vec<u8>>,
},
Sub {
path: &'a str,
name: &'a str,
network: Network,
pending_sign: Vec<Vec<u8>>,
},
}

Expand All @@ -26,6 +29,7 @@ where
Account::Root {
pair,
network: Network::default(),
pending_sign: Vec::new(),
}
}

Expand Down Expand Up @@ -67,9 +71,41 @@ where
Self::Sub { .. } => todo!(),
}
}

/// Save data to be signed later
pub fn add_to_pending(&mut self, message: &[u8]) {
self.pending_sign_mut().push(message.into());
}

/// Sign messages from the queue returning them and their signatures
pub fn sign_pending(&mut self) -> Vec<(Vec<u8>, P::Signature)> {
let v = mem::take(self.pending_sign_mut());
v.into_iter()
.map(|msg| {
let s = self.sign(&msg);
(msg, s)
})
.collect()
}

// Return an iterator over the messages pending for signature in this account
pub fn get_pending(&self) -> impl Iterator<Item = &[u8]> {
self.pending_sign().iter().map(|i| i.as_ref())
}

fn pending_sign_mut(&mut self) -> &mut Vec<Vec<u8>> {
match self {
Self::Root { pending_sign, .. } | Self::Sub { pending_sign, .. } => pending_sign,
}
}

fn pending_sign(&self) -> &Vec<Vec<u8>> {
match self {
Self::Root { pending_sign, .. } | Self::Sub { pending_sign, .. } => pending_sign,
}
}
}

impl<P: Pair> CryptoType for Account<'_, P> {
type Pair = P;
}

69 changes: 66 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ where
/// let vault: SimpleVault<sr25519::Pair> = "//Alice".into();
/// let mut wallet = Wallet::from(vault);
/// if wallet.is_locked() {
/// wallet = wallet.unlock("").await?;
/// wallet = wallet.unlock(()).await?;
/// }
/// # assert_eq!(wallet.is_locked(), false);
/// # Ok(())
Expand All @@ -98,15 +98,78 @@ where
/// # use libwallet::{Wallet, SimpleVault, sr25519, Result};
/// # #[async_std::main] async fn main() -> Result<()> {
///
/// let wallet = Wallet::new(SimpleVault::<sr25519::Pair>::new()).unlock("").await?;
/// let wallet = Wallet::new(SimpleVault::<sr25519::Pair>::new()).unlock(()).await?;
/// let signature = wallet.sign(&[0x01, 0x02, 0x03]);
/// assert!(signature.is_ok());
/// # assert!(signature.is_ok());
/// # Ok(()) }
/// ```
pub fn sign(&self, message: &[u8]) -> Result<SignatureOf<V, C>> {
Ok(self.root_account()?.sign(message))
}

/// Save data to be signed later by root account
/// ```
/// # use libwallet::{Wallet, SimpleVault, sr25519, Result};
/// # #[async_std::main] async fn main() -> Result<()> {
///
/// let mut wallet = Wallet::new(SimpleVault::<sr25519::Pair>::new()).unlock(()).await?;
/// let res = wallet.sign_later(&[0x01, 0x02, 0x03]);
/// assert!(res.is_ok());
/// # Ok(()) }
/// ```
pub fn sign_later(&mut self, message: &[u8]) -> Result<()> {
self.root
.as_mut()
.map(|a| a.add_to_pending(message))
.ok_or(Error::Locked)
}

/// Try to sign all messages in the queue of an account
/// Returns signed transactions
/// ```
/// # use libwallet::{Wallet, SimpleVault, sr25519, Result};
/// # #[async_std::main] async fn main() -> Result<()> {
///
/// let mut wallet = Wallet::new(SimpleVault::<sr25519::Pair>::new()).unlock(()).await?;
/// wallet.sign_later(&[0x01, 0x02, 0x03]);
/// wallet.sign_later(&[0x01, 0x02]);
/// wallet.sign_pending("ROOT");
/// let res = wallet.get_pending("ROOT").collect::<Vec<_>>();
/// assert!(res.is_empty());
/// # Ok(()) }
/// ```
pub fn sign_pending(&mut self, name: &str) -> Vec<(Vec<u8>, SignatureOf<V, C>)> {
match name {
"ROOT" => self
.root
.as_mut()
.map(|a| a.sign_pending())
.unwrap_or_default(),
_ => todo!(), //search sub-accounts
}
}

/// Iteratate over the messages with pending signature of the named account.
/// It panics if the wallet is locked.
///
/// ```
/// # use libwallet::{Wallet, SimpleVault, sr25519, Result};
/// # #[async_std::main] async fn main() -> Result<()> {
///
/// let mut wallet = Wallet::new(SimpleVault::<sr25519::Pair>::new()).unlock(()).await?;
/// wallet.sign_later(&[0x01, 0x02, 0x03]);
/// wallet.sign_later(&[0x01, 0x02]);
/// let res = wallet.get_pending("ROOT").collect::<Vec<_>>();
/// assert_eq!(vec![vec![0x01, 0x02, 0x03], vec![0x01, 0x02]], res);
/// # Ok(()) }
/// ```
pub fn get_pending(&self, name: &str) -> impl Iterator<Item = &[u8]> {
match name {
"ROOT" => self.root_account().unwrap().get_pending(),
_ => todo!(), //get sub-accounts
}
}

/// Switch the network used by the root account which is used by
/// default when deriving new sub-accounts
pub fn switch_default_network(&mut self, net: &str) -> Result<&Account<V::Pair>> {
Expand Down
2 changes: 1 addition & 1 deletion src/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl<P: Pair> SimpleVault<P> {
/// # use libwallet::{SimpleVault, Vault, Result, sr25519};
/// # #[async_std::main] async fn main() -> Result<()> {
/// let vault = SimpleVault::<sr25519::Pair>::new();
/// assert!(vault.unlock("").await.is_ok());
/// assert!(vault.unlock(()).await.is_ok());
/// # Ok(()) }
/// ```
#[cfg(feature = "std")]
Expand Down

0 comments on commit 1a0a5a5

Please sign in to comment.