WIP
This commit is contained in:
@@ -1,38 +1,76 @@
|
||||
use bdk::{
|
||||
bitcoin::Network,
|
||||
database::MemoryDatabase,
|
||||
keys::{
|
||||
bip39::{Language, Mnemonic, WordCount},
|
||||
DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey,
|
||||
},
|
||||
miniscript,
|
||||
template::Bip84,
|
||||
KeychainKind, Wallet,
|
||||
};
|
||||
use std::io::Write;
|
||||
|
||||
use bdk::{bitcoin::Script, KeychainKind};
|
||||
use bdk_esplora::esplora_client;
|
||||
|
||||
use crate::{keys, utils};
|
||||
|
||||
pub async fn run() -> Result<(), anyhow::Error> {
|
||||
// Generate a new mnemonic
|
||||
let mnemonic: GeneratedKey<_, miniscript::Segwitv0> =
|
||||
Mnemonic::generate((WordCount::Words12, Language::English)).unwrap();
|
||||
let mnemonic_words = mnemonic.to_string();
|
||||
let mnemonic = Mnemonic::parse(&mnemonic_words).unwrap();
|
||||
let dave = utils::home(&"dave".to_string());
|
||||
let sammy = utils::home(&"sammy".to_string());
|
||||
|
||||
// Generate the extended key
|
||||
let xkey: ExtendedKey = mnemonic.into_extended_key()?;
|
||||
// Load mnemonics from disk
|
||||
let dave_wallet = keys::bitcoin::load_from_file(&dave).unwrap();
|
||||
let sammy_wallet = keys::bitcoin::load_from_file(&sammy).unwrap();
|
||||
|
||||
// Get private key from the extended key
|
||||
let xprv = xkey.into_xprv(Network::Signet).unwrap();
|
||||
let dave_address = dave_wallet.get_address(bdk::wallet::AddressIndex::New)?;
|
||||
println!("Dave address: {:?}", dave_address);
|
||||
|
||||
// Create a BDK wallet using BIP 84 descriptor ("m/84h/1h/0h/0" and "m/84h/1h/0h/1")
|
||||
let wallet = Wallet::new(
|
||||
Bip84(xprv, KeychainKind::External),
|
||||
Some(Bip84(xprv, KeychainKind::Internal)),
|
||||
Network::Signet,
|
||||
MemoryDatabase::default(),
|
||||
)?;
|
||||
let sammy_address = sammy_wallet.get_address(bdk::wallet::AddressIndex::New)?;
|
||||
println!("Sammy address: {:?}", sammy_address);
|
||||
|
||||
let address = wallet.get_address(bdk::wallet::AddressIndex::New)?;
|
||||
println!("Generated Address: {:?}", address);
|
||||
print!("Syncing...");
|
||||
let client = esplora_client::Builder::new("http://signet.bitcoindevkit.net").build_async()?;
|
||||
|
||||
fn generate_inspect(kind: KeychainKind) -> impl FnMut(u32, &Script) + Send + Sync + 'static {
|
||||
let mut once = Some(());
|
||||
let mut stdout = std::io::stdout();
|
||||
move |spk_i, _| {
|
||||
match once.take() {
|
||||
Some(_) => print!("\nScanning keychain [{:?}]", kind),
|
||||
None => print!(" {:<3}", spk_i),
|
||||
};
|
||||
stdout.flush().expect("must flush");
|
||||
}
|
||||
}
|
||||
|
||||
// let request = dave_wallet
|
||||
// .start_full_scan()
|
||||
// .inspect_spks_for_all_keychains({
|
||||
// let mut once = BTreeSet::<KeychainKind>::new();
|
||||
// move |keychain, spk_i, _| {
|
||||
// match once.insert(keychain) {
|
||||
// true => print!("\nScanning keychain [{:?}]", keychain),
|
||||
// false => print!(" {:<3}", spk_i),
|
||||
// }
|
||||
// std::io::stdout().flush().expect("must flush")
|
||||
// }
|
||||
// })
|
||||
// .inspect_spks_for_keychain(
|
||||
// KeychainKind::External,
|
||||
// generate_inspect(KeychainKind::External),
|
||||
// )
|
||||
// .inspect_spks_for_keychain(
|
||||
// KeychainKind::Internal,
|
||||
// generate_inspect(KeychainKind::Internal),
|
||||
// );
|
||||
|
||||
// let mut update = client
|
||||
// .full_scan(request, STOP_GAP, PARALLEL_REQUESTS)
|
||||
// .await?;
|
||||
// let now = std::time::UNIX_EPOCH.elapsed().unwrap().as_secs();
|
||||
// let _ = update.graph_update.update_last_seen_unconfirmed(now);
|
||||
|
||||
// wallet.apply_update(update)?;
|
||||
// if let Some(changeset) = wallet.take_staged() {
|
||||
// db.write(&changeset)?;
|
||||
// }
|
||||
|
||||
let dave_balance = dave_wallet.get_balance()?;
|
||||
println!("Wallet balance before syncing: {} sats", dave_balance);
|
||||
|
||||
let sammy_balance = sammy_wallet.get_balance()?;
|
||||
println!("Wallet balance before syncing: {} sats", sammy_balance);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,40 +1,59 @@
|
||||
use bitcoin::secp256k1::{rand, Keypair, Secp256k1, SecretKey};
|
||||
use bdk::{
|
||||
bitcoin::Network,
|
||||
database::MemoryDatabase,
|
||||
keys::{
|
||||
bip39::{Language, Mnemonic, WordCount},
|
||||
DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey,
|
||||
},
|
||||
miniscript,
|
||||
template::Bip84,
|
||||
KeychainKind, Wallet,
|
||||
};
|
||||
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
pub fn make_keypair() -> bitcoin::secp256k1::Keypair {
|
||||
let secp = Secp256k1::new();
|
||||
let (secret_key, _) = secp.generate_keypair(&mut rand::thread_rng());
|
||||
Keypair::from_secret_key(&secp, &secret_key)
|
||||
pub fn make_mnemonic() -> String {
|
||||
let mnemonic: GeneratedKey<_, miniscript::Segwitv0> =
|
||||
Mnemonic::generate((WordCount::Words12, Language::English)).unwrap();
|
||||
mnemonic.to_string()
|
||||
}
|
||||
|
||||
pub(crate) fn write(key_path: &PathBuf) -> Result<(), std::io::Error> {
|
||||
let key_pair = make_keypair();
|
||||
let mut file = File::create(key_path)?;
|
||||
|
||||
let pub_str = key_pair.public_key().to_string();
|
||||
let priv_str = key_pair.display_secret().to_string();
|
||||
println!("private key: {priv_str}");
|
||||
let out = format!("{pub_str}/{priv_str}");
|
||||
println!("out: {out}");
|
||||
file.write(out.as_bytes())?;
|
||||
pub(crate) fn write(mnemonic_path: &PathBuf) -> Result<(), std::io::Error> {
|
||||
let mnemonic = make_mnemonic();
|
||||
let mut file = File::create(mnemonic_path)?;
|
||||
println!("mnemonic: {mnemonic}");
|
||||
file.write(mnemonic.as_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn load_from_file(side_dir: &PathBuf) -> bitcoin::secp256k1::Keypair {
|
||||
let bitcoin_key_path = crate::utils::side_paths(side_dir.clone()).1; // TODO: this tuple stinks
|
||||
pub fn create_wallet(mnemonic_words: String) -> anyhow::Result<Wallet<MemoryDatabase>> {
|
||||
let mnemonic = Mnemonic::parse(mnemonic_words).unwrap();
|
||||
|
||||
let data = fs::read_to_string(bitcoin_key_path).expect("couldn't read bitcoin key file");
|
||||
println!("bitcoin keys: {:?}", data);
|
||||
// Generate the extended key
|
||||
let xkey: ExtendedKey = mnemonic.into_extended_key()?;
|
||||
|
||||
let secret_key_data = data.split("/").collect::<Vec<&str>>()[1];
|
||||
let secp = Secp256k1::new();
|
||||
let secret_key =
|
||||
SecretKey::from_str(secret_key_data).expect("couldn't load secret key from file");
|
||||
Keypair::from_secret_key(&secp, &secret_key)
|
||||
// Get private key from the extended key
|
||||
let xprv = xkey.into_xprv(Network::Signet).unwrap();
|
||||
|
||||
// Create a BDK wallet using BIP 84 descriptor ("m/84h/1h/0h/0" and "m/84h/1h/0h/1")
|
||||
let wallet = Wallet::new(
|
||||
Bip84(xprv, KeychainKind::External),
|
||||
Some(Bip84(xprv, KeychainKind::Internal)),
|
||||
Network::Signet,
|
||||
MemoryDatabase::default(),
|
||||
)?;
|
||||
|
||||
Ok(wallet)
|
||||
}
|
||||
|
||||
pub(crate) fn load_from_file(side_dir: &PathBuf) -> anyhow::Result<Wallet<MemoryDatabase>> {
|
||||
let mnemonic_path = crate::utils::side_paths(side_dir.clone()).1; // TODO: this tuple stinks
|
||||
let mnemonic_words = fs::read_to_string(mnemonic_path).expect("couldn't read bitcoin key file");
|
||||
println!("Creating wallet from mnemonic: {mnemonic_words}");
|
||||
create_wallet(mnemonic_words)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ async fn setup(name: &String) -> SideNode {
|
||||
// First, load up the keys and create a bft-crdt
|
||||
let side_dir = utils::home(name);
|
||||
let bft_crdt_keys = keys::bft_crdt::load_from_file(&side_dir);
|
||||
let bitcoin_keys = keys::bitcoin::load_from_file(&side_dir);
|
||||
let bitcoin_wallet = keys::bitcoin::load_from_file(&side_dir).unwrap();
|
||||
let crdt = BaseCrdt::<TransactionList>::new(&bft_crdt_keys);
|
||||
|
||||
// Channels for internal communication, and a tokio task for stdin input
|
||||
@@ -57,7 +57,7 @@ async fn setup(name: &String) -> SideNode {
|
||||
let node = SideNode::new(
|
||||
crdt,
|
||||
bft_crdt_keys,
|
||||
bitcoin_keys,
|
||||
bitcoin_wallet,
|
||||
incoming_receiver,
|
||||
stdin_receiver,
|
||||
handle,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use bdk::database::MemoryDatabase;
|
||||
use bft_json_crdt::json_crdt::{BaseCrdt, SignedOp};
|
||||
use fastcrypto::ed25519::Ed25519KeyPair;
|
||||
use tokio::sync::mpsc;
|
||||
@@ -7,7 +8,7 @@ use crate::{clients::websocket::Client, crdt::TransactionList, utils};
|
||||
pub struct SideNode {
|
||||
crdt: BaseCrdt<TransactionList>,
|
||||
bft_crdt_keys: fastcrypto::ed25519::Ed25519KeyPair,
|
||||
bitcoin_keys: bitcoin::secp256k1::Keypair,
|
||||
bitcoin_wallet: bdk::Wallet<MemoryDatabase>,
|
||||
incoming_receiver: mpsc::Receiver<SignedOp>,
|
||||
stdin_receiver: std::sync::mpsc::Receiver<String>,
|
||||
handle: ezsockets::Client<Client>,
|
||||
@@ -17,7 +18,7 @@ impl SideNode {
|
||||
pub fn new(
|
||||
crdt: BaseCrdt<TransactionList>,
|
||||
bft_crdt_keys: Ed25519KeyPair,
|
||||
bitcoin_keys: bitcoin::secp256k1::Keypair,
|
||||
bitcoin_wallet: bdk::Wallet<MemoryDatabase>,
|
||||
incoming_receiver: mpsc::Receiver<SignedOp>,
|
||||
stdin_receiver: std::sync::mpsc::Receiver<String>,
|
||||
handle: ezsockets::Client<Client>,
|
||||
@@ -25,7 +26,7 @@ impl SideNode {
|
||||
let node = Self {
|
||||
crdt,
|
||||
bft_crdt_keys,
|
||||
bitcoin_keys,
|
||||
bitcoin_wallet,
|
||||
incoming_receiver,
|
||||
stdin_receiver,
|
||||
handle,
|
||||
|
||||
@@ -35,7 +35,8 @@ async fn test_distribute_via_websockets() {
|
||||
async fn setup(_: &str) -> SideNode {
|
||||
// First, load up the keys and create a bft-crdt
|
||||
let bft_crdt_keys = make_keypair();
|
||||
let bitcoin_keys = keys::bitcoin::make_keypair();
|
||||
let mnemonic_words = keys::bitcoin::make_mnemonic();
|
||||
let bitcoin_wallet = keys::bitcoin::create_wallet(mnemonic_words).unwrap();
|
||||
let crdt = BaseCrdt::<TransactionList>::new(&bft_crdt_keys);
|
||||
|
||||
// Channels for internal communication, and a tokio task for stdin input
|
||||
@@ -47,7 +48,7 @@ async fn setup(_: &str) -> SideNode {
|
||||
let node = SideNode::new(
|
||||
crdt,
|
||||
bft_crdt_keys,
|
||||
bitcoin_keys,
|
||||
bitcoin_wallet,
|
||||
incoming_receiver,
|
||||
stdin_receiver,
|
||||
handle,
|
||||
|
||||
Reference in New Issue
Block a user