Skip to content
This repository was archived by the owner on Sep 12, 2023. It is now read-only.

feat(taker): import seed #3173

Merged
merged 2 commits into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Electron App has now a tray icon for macOS 🚀
- Split identity and wallet seed into two separate files.
- Wallet seeds created by ItchySats can now be imported and exported for the taker.

## [0.7.0] - 2022-09-30

Expand Down
17 changes: 15 additions & 2 deletions crates/bdk-ext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use bdk::bitcoin::secp256k1::SecretKey;
use bdk::bitcoin::util::bip32::ExtendedPrivKey;
use bdk::bitcoin::Amount;
use bdk::bitcoin::Network;
use bdk::database::BatchDatabase;
use bdk::BlockTime;
use rand::CryptoRng;
use rand::RngCore;
Expand All @@ -17,6 +18,20 @@ pub fn new_test_wallet(
utxo_amount: Amount,
num_utxos: u8,
) -> Result<bdk::Wallet<bdk::database::MemoryDatabase>> {
new_test_wallet_from_database(
rng,
utxo_amount,
num_utxos,
bdk::database::MemoryDatabase::new(),
)
}

pub fn new_test_wallet_from_database<DB: BatchDatabase>(
rng: &mut (impl RngCore + CryptoRng),
utxo_amount: Amount,
num_utxos: u8,
mut database: DB,
) -> Result<bdk::Wallet<DB>> {
use bdk::populate_test_db;
use bdk::testutils;

Expand All @@ -26,8 +41,6 @@ pub fn new_test_wallet(
let key = ExtendedPrivKey::new_master(Network::Regtest, &seed)?;
let descriptors = testutils!(@descriptors (&format!("wpkh({key}/*)")));

let mut database = bdk::database::MemoryDatabase::new();

for index in 0..num_utxos {
populate_test_db!(
&mut database,
Expand Down
8 changes: 8 additions & 0 deletions crates/daemon-tests/src/mocks/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use anyhow::Result;
use async_trait::async_trait;
use bdk_ext::new_test_wallet;
use daemon::bdk;
use daemon::bdk::bitcoin::util::psbt::PartiallySignedTransaction;
use daemon::bdk::bitcoin::Amount;
use daemon::bdk::bitcoin::Txid;
Expand Down Expand Up @@ -52,6 +53,9 @@ impl WalletActor {
async fn handle(&mut self, msg: wallet::Sync) {
self.mock.lock().await.sync(msg)
}
async fn handle(&mut self, msg: wallet::ImportSeed) -> Result<bdk::wallet::AddressInfo> {
self.mock.lock().await.import_seed(msg)
}
}

#[automock]
Expand All @@ -71,6 +75,10 @@ pub trait Wallet {
fn sync(&mut self, _msg: wallet::Sync) {
unreachable!("mockall will reimplement this method")
}

fn import_seed(&mut self, _msg: wallet::ImportSeed) -> Result<bdk::wallet::AddressInfo> {
unreachable!("mockall will reimplement this method")
}
}

pub fn build_party_params(msg: wallet::BuildPartyParams) -> Result<PartyParams> {
Expand Down
42 changes: 42 additions & 0 deletions crates/daemon-tests/tests/main/import_seed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use daemon::bdk::bitcoin;
use daemon::seed;
use daemon::seed::RandomSeed;
use daemon::seed::Seed;
use daemon_tests::open_cfd;
use daemon_tests::start_both;
use daemon_tests::OpenCfdArgs;
use otel_tests::otel_test;
use rand::distributions::Alphanumeric;
use rand::thread_rng;
use rand::Rng;
use std::env;
use std::path::Path;

#[otel_test]
async fn fail_to_import_seed_with_open_cfds() {
let (mut maker, mut taker) = start_both().await;

let cfd_args = OpenCfdArgs::default();
open_cfd(&mut taker, &mut maker, cfd_args.clone()).await;

let random_dir: String = thread_rng()
.sample_iter(&Alphanumeric)
.take(7)
.map(char::from)
.collect();
let data_dir = env::temp_dir().join(Path::new(&random_dir));
tokio::fs::create_dir_all(&data_dir)
.await
.expect("failed to create random temp folder");

taker
.system
.import_seed(
RandomSeed::default().seed(),
data_dir,
bitcoin::Network::Testnet,
seed::TAKER_WALLET_SEED_FILE,
)
.await
.expect_err("import seed should be rejected as open CFDs exist");
}
1 change: 1 addition & 0 deletions crates/daemon-tests/tests/main/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod collaborative_settlement;
mod connectivity;
mod import_seed;
mod liquidation;
mod non_collaborative_settlement;
mod offer;
Expand Down
40 changes: 38 additions & 2 deletions crates/daemon/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![cfg_attr(not(test), warn(clippy::unwrap_used))]

use crate::bitcoin::util::psbt::PartiallySignedTransaction;
use crate::bitcoin::Network;
use crate::bitcoin::Txid;
use crate::listen_protocols::TAKER_LISTEN_PROTOCOLS;
use anyhow::bail;
Expand Down Expand Up @@ -31,6 +32,7 @@ use ping_pong::ping;
use ping_pong::pong;
use seed::Identities;
use std::collections::HashSet;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use time::ext::NumericalDuration;
Expand Down Expand Up @@ -78,7 +80,7 @@ pub const N_PAYOUTS: usize = 200;

pub struct TakerActorSystem<O, W, P> {
pub cfd_actor: Address<taker_cfd::Actor>,
wallet_actor: Address<W>,
pub wallet_actor: Address<W>,
_oracle_actor: Address<O>,
pub auto_rollover_actor: Address<auto_rollover::Actor>,
pub price_feed_actor: Address<P>,
Expand All @@ -93,6 +95,8 @@ pub struct TakerActorSystem<O, W, P> {
pub identify_info_feed_receiver: watch::Receiver<Option<PeerInfo>>,

_tasks: Tasks,

db: sqlite_db::Connection,
}

impl<O, W, P> TakerActorSystem<O, W, P>
Expand All @@ -105,6 +109,7 @@ where
W: Handler<wallet::BuildPartyParams, Return = Result<maia_core::PartyParams>>
+ Handler<wallet::Sign, Return = Result<PartiallySignedTransaction>>
+ Handler<wallet::Withdraw, Return = Result<Txid>>
+ Handler<wallet::ImportSeed, Return = Result<bdk::wallet::AddressInfo>>
+ Handler<wallet::Sync, Return = ()>
+ Actor<Stop = ()>,
P: Handler<
Expand Down Expand Up @@ -333,7 +338,7 @@ where
let close_cfds_actor = archive_closed_cfds::Actor::new(db.clone())
.create(None)
.spawn(&mut tasks);
let archive_failed_cfds_actor = archive_failed_cfds::Actor::new(db)
let archive_failed_cfds_actor = archive_failed_cfds::Actor::new(db.clone())
.create(None)
.spawn(&mut tasks);

Expand All @@ -354,6 +359,7 @@ where
_online_status_actor: online_status_actor,
_pong_actor: pong_address,
_identify_dialer_actor: identify_dialer_actor,
db,
})
}

Expand Down Expand Up @@ -445,6 +451,36 @@ where
self.wallet_actor.send(wallet::Sync).await?;
Ok(())
}

#[instrument(skip(self, seed), err)]
pub async fn import_seed(
&self,
seed: Vec<u8>,
data_dir: PathBuf,
network: Network,
name: &str,
) -> Result<()> {
let open_cfd_ids = self.db.load_open_cfd_ids().await?;

if !open_cfd_ids.is_empty() {
use anyhow::bail;
bail!("Cannot accept imported seed since open CFDs exist");
}

// recreate the wallet within the wallet actor
self.wallet_actor
.send(wallet::ImportSeed {
seed,
path: data_dir,
network,
name: name.to_string(),
})
.await??;

self.wallet_actor.send(wallet::Sync).await?;

Ok(())
}
}

/// A struct defining our environment
Expand Down
33 changes: 28 additions & 5 deletions crates/daemon/src/seed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ use std::fmt;
use std::fmt::Debug;
use std::path::Path;

pub const TAKER_WALLET_SEED_FILE: &str = "taker_seed";
pub const TAKER_IDENTITY_SEED_FILE: &str = "taker_id_seed";

pub const MAKER_WALLET_SEED_FILE: &str = "maker_seed";
pub const MAKER_IDENTITY_SEED_FILE: &str = "maker_id_seed";

pub const RANDOM_SEED_SIZE: usize = 256;
pub const APP_SEED_SIZE: usize = 32;

/// Struct containing keys for both legacy and libp2p connections.
///
/// It is located here as all the information is derived from the seed.
Expand All @@ -33,6 +42,8 @@ impl Identities {
pub trait Seed {
fn seed(&self) -> Vec<u8>;

fn is_managed(&self) -> bool;

fn derive_extended_priv_key(&self, network: Network) -> Result<ExtendedPrivKey> {
let mut ext_priv_key_seed = [0u8; 64];

Expand Down Expand Up @@ -82,12 +93,15 @@ pub trait Seed {
}

#[derive(Copy, Clone)]
pub struct RandomSeed([u8; 256]);
pub struct RandomSeed([u8; RANDOM_SEED_SIZE]);

impl Seed for RandomSeed {
fn seed(&self) -> Vec<u8> {
self.0.to_vec()
}
fn is_managed(&self) -> bool {
true
}
}

impl Debug for RandomSeed {
Expand Down Expand Up @@ -133,26 +147,35 @@ impl RandomSeed {
}
}

impl From<[u8; RANDOM_SEED_SIZE]> for RandomSeed {
fn from(bytes: [u8; RANDOM_SEED_SIZE]) -> Self {
Self(bytes)
}
}

impl Default for RandomSeed {
fn default() -> Self {
let mut seed = [0u8; 256];
let mut seed = [0u8; RANDOM_SEED_SIZE];
rand::thread_rng().fill(&mut seed);

Self(seed)
}
}

#[derive(Copy, Clone)]
pub struct AppSeed([u8; 32]);
pub struct AppSeed([u8; APP_SEED_SIZE]);

impl Seed for AppSeed {
fn seed(&self) -> Vec<u8> {
self.0.to_vec()
}
fn is_managed(&self) -> bool {
false
}
}

impl From<[u8; 32]> for AppSeed {
fn from(bytes: [u8; 32]) -> Self {
impl From<[u8; APP_SEED_SIZE]> for AppSeed {
fn from(bytes: [u8; APP_SEED_SIZE]) -> Self {
Self(bytes)
}
}
Expand Down
Loading