Ok the bdk looks like a far better bet!
This commit is contained in:
@@ -6,7 +6,11 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
async-trait = "0.1.52"
|
||||
bdk = "0.29.0"
|
||||
bdk_esplora = "0.15.0"
|
||||
bdk_sqlite = "0.2.0"
|
||||
bdk_wallet = { version = "1.0.0-alpha.13", features = ["all-keys"] }
|
||||
bft-json-crdt = { path = "../crates/bft-json-crdt" }
|
||||
bft-crdt-derive = { path = "../crates/bft-json-crdt/bft-crdt-derive" }
|
||||
@@ -15,15 +19,16 @@ clap = { version = "4.5.4", features = ["derive"] }
|
||||
dirs = "5.0.1"
|
||||
ezsockets = { version = "*", features = ["client"] }
|
||||
fastcrypto = "0.1.8"
|
||||
indexmap = { version = "2.2.6", features = ["serde"] }
|
||||
# serde_cbor = "0.11.2" # move to this once we need to pack things in CBOR
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.117"
|
||||
sha256 = "1.5.0"
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
toml = "0.8.14"
|
||||
tracing = "0.1.32"
|
||||
# tracing-subscriber = "0.3.9"
|
||||
toml = "0.8.14"
|
||||
indexmap = { version = "2.2.6", features = ["serde"] }
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
uuid = { version = "1.8.0", features = ["v4"] }
|
||||
|
||||
@@ -1,3 +1,114 @@
|
||||
pub fn run(name: &str) {
|
||||
println!("running btc_rpc...");
|
||||
use std::{collections::BTreeSet, io::Write, str::FromStr};
|
||||
|
||||
use bdk_esplora::{esplora_client, EsploraAsyncExt};
|
||||
use bdk_wallet::{
|
||||
bitcoin::{Address, Amount, Network, Script},
|
||||
KeychainKind, SignOptions, Wallet,
|
||||
};
|
||||
|
||||
use bdk_sqlite::{rusqlite::Connection, Store};
|
||||
|
||||
const SEND_AMOUNT: Amount = Amount::from_sat(5000);
|
||||
const STOP_GAP: usize = 50;
|
||||
const PARALLEL_REQUESTS: usize = 5;
|
||||
|
||||
pub async fn run() -> Result<(), anyhow::Error> {
|
||||
let db_path = "/tmp/bdk-esplora-async-example.sqlite";
|
||||
let conn = Connection::open(db_path)?;
|
||||
let mut db = Store::new(conn)?;
|
||||
let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
|
||||
let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
|
||||
let changeset = db.read()?;
|
||||
|
||||
let mut wallet = Wallet::new_or_load(
|
||||
external_descriptor,
|
||||
internal_descriptor,
|
||||
changeset,
|
||||
Network::Signet,
|
||||
)?;
|
||||
|
||||
let address = wallet.next_unused_address(KeychainKind::External);
|
||||
if let Some(changeset) = wallet.take_staged() {
|
||||
db.write(&changeset)?;
|
||||
}
|
||||
println!("Generated Address: {}", address);
|
||||
|
||||
let balance = wallet.balance();
|
||||
println!("Wallet balance before syncing: {} sats", balance.total());
|
||||
|
||||
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 = 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)?;
|
||||
}
|
||||
println!();
|
||||
|
||||
let balance = wallet.balance();
|
||||
println!("Wallet balance after syncing: {} sats", balance.total());
|
||||
|
||||
if balance.total() < SEND_AMOUNT {
|
||||
println!(
|
||||
"Please send at least {} sats to the receiving address",
|
||||
SEND_AMOUNT
|
||||
);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
let faucet_address = Address::from_str("mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt")?
|
||||
.require_network(Network::Signet)?;
|
||||
|
||||
let mut tx_builder = wallet.build_tx();
|
||||
tx_builder
|
||||
.add_recipient(faucet_address.script_pubkey(), SEND_AMOUNT)
|
||||
.enable_rbf();
|
||||
|
||||
let mut psbt = tx_builder.finish()?;
|
||||
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
|
||||
assert!(finalized);
|
||||
|
||||
let tx = psbt.extract_tx()?;
|
||||
client.broadcast(&tx).await?;
|
||||
println!("Tx broadcasted! Txid: {}", tx.compute_txid());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub async fn run() {
|
||||
node.start().await;
|
||||
}
|
||||
Some(Commands::Btc {}) => {
|
||||
clients::btc_rpc::run("sammy_wallet");
|
||||
let _ = clients::btc_rpc::run().await;
|
||||
}
|
||||
None => println!("No command provided. Exiting. See --help for more information."),
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use bft_json_crdt::json_crdt::SignedOp;
|
||||
use bitcoin::{absolute, key::Keypair, transaction::Version, TxIn, TxOut};
|
||||
use serde_json::{json, Value};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub(crate) const BITCOIN_KEY_FILE: &str = "bitcoin_keys.pem";
|
||||
pub(crate) const BFT_CRDT_KEY_FILE: &str = "keys.pem";
|
||||
@@ -40,29 +38,29 @@ pub fn fake_generic_transaction_json(from: String) -> Value {
|
||||
}
|
||||
|
||||
/// Generate a Bitcoin transaction from this node's bitcoin_keys
|
||||
pub fn fake_bitcoin_transaction(key_pair: Keypair) -> bitcoin::Transaction {
|
||||
let from = key_pair.public_key().to_string();
|
||||
let to = "Bob";
|
||||
let amount = 1;
|
||||
let lock_time = absolute::LockTime::from_height(0).expect("couldn't format btc lock time");
|
||||
let input = TxIn {
|
||||
previous_output: todo!(),
|
||||
script_sig: todo!(),
|
||||
sequence: todo!(),
|
||||
witness: todo!(),
|
||||
};
|
||||
let output = TxOut {
|
||||
value: todo!(),
|
||||
script_pubkey: todo!(),
|
||||
};
|
||||
let tx = bitcoin::Transaction {
|
||||
version: Version(1),
|
||||
lock_time,
|
||||
input: vec![input],
|
||||
output: vec![output],
|
||||
};
|
||||
tx
|
||||
}
|
||||
// pub fn fake_bitcoin_transaction(key_pair: Keypair) -> bitcoin::Transaction {
|
||||
// let from = key_pair.public_key().to_string();
|
||||
// let to = "Bob";
|
||||
// let amount = 1;
|
||||
// let lock_time = absolute::LockTime::from_height(0).expect("couldn't format btc lock time");
|
||||
// let input = TxIn {
|
||||
// previous_output: todo!(),
|
||||
// script_sig: todo!(),
|
||||
// sequence: todo!(),
|
||||
// witness: todo!(),
|
||||
// };
|
||||
// let output = TxOut {
|
||||
// value: todo!(),
|
||||
// script_pubkey: todo!(),
|
||||
// };
|
||||
// let tx = bitcoin::Transaction {
|
||||
// version: Version(1),
|
||||
// lock_time,
|
||||
// input: vec![input],
|
||||
// output: vec![output],
|
||||
// };
|
||||
// tx
|
||||
// }
|
||||
|
||||
pub fn shappy(op: SignedOp) -> String {
|
||||
let b = serde_json::to_string(&op).unwrap().into_bytes();
|
||||
|
||||
Reference in New Issue
Block a user