Derive bitcoin private key from seed

This commit is contained in:
rishflab 2021-02-09 17:23:13 +11:00
parent a51194b9fa
commit 4768c79070
5 changed files with 64 additions and 15 deletions

View File

@ -84,8 +84,12 @@ async fn main() -> Result<()> {
let execution_params = execution_params::Testnet::get_execution_params(); let execution_params = execution_params::Testnet::get_execution_params();
let (bitcoin_wallet, monero_wallet) = let (bitcoin_wallet, monero_wallet) = init_wallets(
init_wallets(config.clone(), &wallet_data_dir).await?; config.clone(),
&wallet_data_dir,
seed.extended_private_key(BITCOIN_NETWORK)?.private_key,
)
.await?;
let (mut event_loop, _) = EventLoop::new( let (mut event_loop, _) = EventLoop::new(
config.network.listen, config.network.listen,
@ -121,12 +125,14 @@ async fn main() -> Result<()> {
async fn init_wallets( async fn init_wallets(
config: Config, config: Config,
bitcoin_wallet_data_dir: &Path, bitcoin_wallet_data_dir: &Path,
private_key: ::bitcoin::PrivateKey,
) -> Result<(bitcoin::Wallet, monero::Wallet)> { ) -> Result<(bitcoin::Wallet, monero::Wallet)> {
let bitcoin_wallet = bitcoin::Wallet::new( let bitcoin_wallet = bitcoin::Wallet::new(
config.bitcoin.electrum_rpc_url, config.bitcoin.electrum_rpc_url,
config.bitcoin.electrum_http_url, config.bitcoin.electrum_http_url,
BITCOIN_NETWORK, BITCOIN_NETWORK,
bitcoin_wallet_data_dir, bitcoin_wallet_data_dir,
private_key,
) )
.await?; .await?;
let bitcoin_balance = bitcoin_wallet.balance().await?; let bitcoin_balance = bitcoin_wallet.balance().await?;

View File

@ -90,8 +90,14 @@ async fn main() -> Result<()> {
alice_addr, alice_addr,
send_bitcoin, send_bitcoin,
} => { } => {
let (bitcoin_wallet, monero_wallet) = let (bitcoin_wallet, monero_wallet) = init_wallets(
init_wallets(config, bitcoin_network, &wallet_data_dir, monero_network).await?; config,
bitcoin_network,
&wallet_data_dir,
monero_network,
seed,
)
.await?;
let swap_id = Uuid::new_v4(); let swap_id = Uuid::new_v4();
@ -132,8 +138,14 @@ async fn main() -> Result<()> {
alice_peer_id, alice_peer_id,
alice_addr, alice_addr,
}) => { }) => {
let (bitcoin_wallet, monero_wallet) = let (bitcoin_wallet, monero_wallet) = init_wallets(
init_wallets(config, bitcoin_network, &wallet_data_dir, monero_network).await?; config,
bitcoin_network,
&wallet_data_dir,
monero_network,
seed,
)
.await?;
let bob_factory = Builder::new( let bob_factory = Builder::new(
seed, seed,
@ -157,8 +169,14 @@ async fn main() -> Result<()> {
force, force,
}) => { }) => {
// TODO: Optimization: Only init the Bitcoin wallet, Monero wallet unnecessary // TODO: Optimization: Only init the Bitcoin wallet, Monero wallet unnecessary
let (bitcoin_wallet, monero_wallet) = let (bitcoin_wallet, monero_wallet) = init_wallets(
init_wallets(config, bitcoin_network, &wallet_data_dir, monero_network).await?; config,
bitcoin_network,
&wallet_data_dir,
monero_network,
seed,
)
.await?;
let bob_factory = Builder::new( let bob_factory = Builder::new(
seed, seed,
@ -201,8 +219,14 @@ async fn main() -> Result<()> {
alice_addr, alice_addr,
force, force,
}) => { }) => {
let (bitcoin_wallet, monero_wallet) = let (bitcoin_wallet, monero_wallet) = init_wallets(
init_wallets(config, bitcoin_network, &wallet_data_dir, monero_network).await?; config,
bitcoin_network,
&wallet_data_dir,
monero_network,
seed,
)
.await?;
// TODO: Optimize to only use the Bitcoin wallet, Monero wallet is unnecessary // TODO: Optimize to only use the Bitcoin wallet, Monero wallet is unnecessary
let bob_factory = Builder::new( let bob_factory = Builder::new(
@ -238,12 +262,14 @@ async fn init_wallets(
bitcoin_network: bitcoin::Network, bitcoin_network: bitcoin::Network,
bitcoin_wallet_data_dir: &Path, bitcoin_wallet_data_dir: &Path,
monero_network: monero::Network, monero_network: monero::Network,
seed: Seed,
) -> Result<(bitcoin::Wallet, monero::Wallet)> { ) -> Result<(bitcoin::Wallet, monero::Wallet)> {
let bitcoin_wallet = bitcoin::Wallet::new( let bitcoin_wallet = bitcoin::Wallet::new(
config.bitcoin.electrum_rpc_url, config.bitcoin.electrum_rpc_url,
config.bitcoin.electrum_http_url, config.bitcoin.electrum_http_url,
bitcoin_network, bitcoin_network,
bitcoin_wallet_data_dir, bitcoin_wallet_data_dir,
seed.extended_private_key(bitcoin_network)?.private_key,
) )
.await?; .await?;

View File

@ -13,7 +13,7 @@ use backoff::{backoff::Constant as ConstantBackoff, tokio::retry};
use bdk::{ use bdk::{
blockchain::{noop_progress, Blockchain, ElectrumBlockchain}, blockchain::{noop_progress, Blockchain, ElectrumBlockchain},
electrum_client::{self, Client, ElectrumApi}, electrum_client::{self, Client, ElectrumApi},
keys::GeneratableDefaultOptions, miniscript::bitcoin::PrivateKey,
FeeRate, FeeRate,
}; };
use reqwest::{Method, Url}; use reqwest::{Method, Url};
@ -43,7 +43,8 @@ impl Wallet {
electrum_rpc_url: Url, electrum_rpc_url: Url,
electrum_http_url: Url, electrum_http_url: Url,
network: bitcoin::Network, network: bitcoin::Network,
waller_dir: &Path, wallet_dir: &Path,
private_key: PrivateKey,
) -> Result<Self> { ) -> Result<Self> {
// Workaround for https://github.com/bitcoindevkit/rust-electrum-client/issues/47. // Workaround for https://github.com/bitcoindevkit/rust-electrum-client/issues/47.
let config = electrum_client::ConfigBuilder::default().retry(2).build(); let config = electrum_client::ConfigBuilder::default().retry(2).build();
@ -51,11 +52,10 @@ impl Wallet {
let client = Client::from_config(electrum_rpc_url.as_str(), config) let client = Client::from_config(electrum_rpc_url.as_str(), config)
.map_err(|e| anyhow!("Failed to init electrum rpc client: {:?}", e))?; .map_err(|e| anyhow!("Failed to init electrum rpc client: {:?}", e))?;
let db = bdk::sled::open(waller_dir)?.open_tree(SLED_TREE_NAME)?; let db = bdk::sled::open(wallet_dir)?.open_tree(SLED_TREE_NAME)?;
let p_key = ::bitcoin::PrivateKey::generate_default()?;
let bdk_wallet = bdk::Wallet::new( let bdk_wallet = bdk::Wallet::new(
bdk::template::P2WPKH(p_key), bdk::template::P2WPKH(private_key),
None, None,
network, network,
db, db,

View File

@ -1,5 +1,7 @@
use crate::fs::ensure_directory_exists; use crate::fs::ensure_directory_exists;
use ::bitcoin::secp256k1::{self, constants::SECRET_KEY_SIZE, SecretKey}; use ::bitcoin::secp256k1::{self, constants::SECRET_KEY_SIZE, SecretKey};
use anyhow::Result;
use bdk::bitcoin::util::bip32::ExtendedPrivKey;
use pem::{encode, Pem}; use pem::{encode, Pem};
use rand::prelude::*; use rand::prelude::*;
use std::{ use std::{
@ -26,6 +28,11 @@ impl Seed {
Ok(Seed(bytes)) Ok(Seed(bytes))
} }
pub fn extended_private_key(&self, network: bitcoin::Network) -> Result<ExtendedPrivKey> {
let private_key = ExtendedPrivKey::new_master(network, &self.bytes())?;
Ok(private_key)
}
pub fn bytes(&self) -> [u8; SEED_LENGTH] { pub fn bytes(&self) -> [u8; SEED_LENGTH] {
self.0 self.0
} }

View File

@ -346,6 +346,9 @@ where
.get_host_port(testutils::electrs::HTTP_PORT) .get_host_port(testutils::electrs::HTTP_PORT)
.expect("Could not map electrs http port"); .expect("Could not map electrs http port");
let alice_seed = Seed::random().unwrap();
let bob_seed = Seed::random().unwrap();
let (alice_bitcoin_wallet, alice_monero_wallet) = init_test_wallets( let (alice_bitcoin_wallet, alice_monero_wallet) = init_test_wallets(
"alice", "alice",
containers.bitcoind_url.clone(), containers.bitcoind_url.clone(),
@ -354,6 +357,7 @@ where
tempdir().unwrap().path(), tempdir().unwrap().path(),
electrs_rpc_port, electrs_rpc_port,
electrs_http_port, electrs_http_port,
alice_seed,
) )
.await; .await;
@ -375,6 +379,7 @@ where
tempdir().unwrap().path(), tempdir().unwrap().path(),
electrs_rpc_port, electrs_rpc_port,
electrs_http_port, electrs_http_port,
bob_seed,
) )
.await; .await;
@ -570,6 +575,7 @@ async fn init_monero_container(
(monero, monerods) (monero, monerods)
} }
#[allow(clippy::too_many_arguments)]
async fn init_test_wallets( async fn init_test_wallets(
name: &str, name: &str,
bitcoind_url: Url, bitcoind_url: Url,
@ -578,6 +584,7 @@ async fn init_test_wallets(
datadir: &Path, datadir: &Path,
electrum_rpc_port: u16, electrum_rpc_port: u16,
electrum_http_port: u16, electrum_http_port: u16,
seed: Seed,
) -> (Arc<bitcoin::Wallet>, Arc<monero::Wallet>) { ) -> (Arc<bitcoin::Wallet>, Arc<monero::Wallet>) {
monero monero
.init(vec![(name, starting_balances.xmr.as_piconero())]) .init(vec![(name, starting_balances.xmr.as_piconero())])
@ -603,6 +610,9 @@ async fn init_test_wallets(
electrum_http_url, electrum_http_url,
bitcoin::Network::Regtest, bitcoin::Network::Regtest,
datadir, datadir,
seed.extended_private_key(bitcoin::Network::Regtest)
.expect("Could not create extended private key from seed")
.private_key,
) )
.await .await
.expect("could not init btc wallet"); .expect("could not init btc wallet");