Refactoring
This commit is contained in:
parent
6db81ee769
commit
306949e9f0
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1197,7 +1197,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "sp_backend"
|
name = "sp_backend"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/Sosthene00/sp-backend?branch=sp_client#0213188a95921081f5c74e5099ac46e6737a07d0"
|
source = "git+https://github.com/Sosthene00/sp-backend?branch=sp_client#32967c214df9a25daef551a372b89c400f2369f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitcoin 0.31.1",
|
"bitcoin 0.31.1",
|
||||||
|
179
src/main.rs
179
src/main.rs
@ -1,11 +1,12 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
env,
|
env,
|
||||||
|
fmt::Debug,
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex, MutexGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use bitcoincore_rpc::json::{self as bitcoin_json};
|
use bitcoincore_rpc::json::{self as bitcoin_json};
|
||||||
@ -56,6 +57,8 @@ type Tx = UnboundedSender<Message>;
|
|||||||
|
|
||||||
type PeerMap = Arc<Mutex<HashMap<SocketAddr, Tx>>>;
|
type PeerMap = Arc<Mutex<HashMap<SocketAddr, Tx>>>;
|
||||||
|
|
||||||
|
type SharedDaemon = Arc<Mutex<Daemon>>;
|
||||||
|
|
||||||
const FAUCET_AMT: Amount = Amount::from_sat(1000);
|
const FAUCET_AMT: Amount = Amount::from_sat(1000);
|
||||||
|
|
||||||
pub(crate) trait MutexExt<T> {
|
pub(crate) trait MutexExt<T> {
|
||||||
@ -216,19 +219,15 @@ fn find_owned_outputs(
|
|||||||
|
|
||||||
fn faucet_send(
|
fn faucet_send(
|
||||||
sp_address: SilentPaymentAddress,
|
sp_address: SilentPaymentAddress,
|
||||||
sp_client: Arc<Mutex<SpClient>>,
|
sp_wallet: Arc<SilentPaymentWallet>,
|
||||||
sp_outputs: Arc<Mutex<OutputList>>,
|
shared_daemon: SharedDaemon,
|
||||||
daemon: Arc<Mutex<Daemon>>,
|
|
||||||
) -> Result<Txid> {
|
) -> Result<Txid> {
|
||||||
let mut first_tx: Option<Transaction> = None;
|
let mut first_tx: Option<Transaction> = None;
|
||||||
let final_tx: Transaction;
|
let final_tx: Transaction;
|
||||||
let mut new_outpoints: HashMap<OutPoint, OwnedOutput>;
|
let mut new_outpoints: HashMap<OutPoint, OwnedOutput>;
|
||||||
|
|
||||||
// do we have a sp output available ?
|
// do we have a sp output available ?
|
||||||
let available_outpoints = sp_outputs
|
let available_outpoints = sp_wallet.get_outputs()?.to_spendable_list();
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(e.to_string()))?
|
|
||||||
.to_spendable_list();
|
|
||||||
|
|
||||||
let available_amt = available_outpoints
|
let available_amt = available_outpoints
|
||||||
.iter()
|
.iter()
|
||||||
@ -252,9 +251,8 @@ fn faucet_send(
|
|||||||
nb_outputs: 1,
|
nb_outputs: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
let fee_estimate = daemon
|
let fee_estimate = shared_daemon
|
||||||
.lock()
|
.lock_anyhow()?
|
||||||
.map_err(|e| Error::msg(format!("{}", e.to_string())))?
|
|
||||||
.estimate_fee(6)?
|
.estimate_fee(6)?
|
||||||
.unwrap_or(Amount::from_sat(1000))
|
.unwrap_or(Amount::from_sat(1000))
|
||||||
.checked_div(1000)
|
.checked_div(1000)
|
||||||
@ -262,7 +260,7 @@ fn faucet_send(
|
|||||||
|
|
||||||
log::debug!("fee estimate for 6 blocks: {}", fee_estimate);
|
log::debug!("fee estimate for 6 blocks: {}", fee_estimate);
|
||||||
|
|
||||||
let wallet = sp_client.lock().map_err(|e| Error::msg(e.to_string()))?;
|
let wallet = sp_wallet.get_client()?;
|
||||||
|
|
||||||
let mut new_psbt = wallet.create_new_psbt(inputs.clone(), vec![recipient], None)?;
|
let mut new_psbt = wallet.create_new_psbt(inputs.clone(), vec![recipient], None)?;
|
||||||
log::debug!("Created psbt: {}", new_psbt);
|
log::debug!("Created psbt: {}", new_psbt);
|
||||||
@ -317,7 +315,8 @@ fn faucet_send(
|
|||||||
let keypair = Keypair::new(&secp, &mut thread_rng());
|
let keypair = Keypair::new(&secp, &mut thread_rng());
|
||||||
|
|
||||||
// we first spend from core to the pubkey we just created
|
// we first spend from core to the pubkey we just created
|
||||||
let (core_tx, fee_rate) = spend_from_core(keypair.x_only_public_key().0, daemon.clone())?;
|
let (core_tx, fee_rate) =
|
||||||
|
spend_from_core(keypair.x_only_public_key().0, shared_daemon.clone())?;
|
||||||
|
|
||||||
// check that the first output of the transaction pays to the key we just created
|
// check that the first output of the transaction pays to the key we just created
|
||||||
assert!(
|
assert!(
|
||||||
@ -352,10 +351,7 @@ fn faucet_send(
|
|||||||
.get(0)
|
.get(0)
|
||||||
.expect("Failed to generate keys")
|
.expect("Failed to generate keys")
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let change_sp_address = sp_client
|
let change_sp_address = sp_wallet.get_client()?.get_receiving_address();
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock sp_client: {}", e.to_string())))?
|
|
||||||
.get_receiving_address();
|
|
||||||
let change_output_key: XOnlyPublicKey =
|
let change_output_key: XOnlyPublicKey =
|
||||||
generate_recipient_pubkeys(vec![change_sp_address], partial_secret)?
|
generate_recipient_pubkeys(vec![change_sp_address], partial_secret)?
|
||||||
.into_values()
|
.into_values()
|
||||||
@ -410,9 +406,7 @@ fn faucet_send(
|
|||||||
|
|
||||||
first_tx = Some(core_tx);
|
first_tx = Some(core_tx);
|
||||||
|
|
||||||
let client = sp_client
|
let client = sp_wallet.get_client()?;
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("{}", e.to_string())))?;
|
|
||||||
|
|
||||||
let input_pubkey = &keypair.public_key();
|
let input_pubkey = &keypair.public_key();
|
||||||
|
|
||||||
@ -431,9 +425,9 @@ fn faucet_send(
|
|||||||
new_outpoints = find_owned_outputs(&final_tx, ours)?;
|
new_outpoints = find_owned_outputs(&final_tx, ours)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(core) = daemon.lock() {
|
if let Ok(daemon) = shared_daemon.lock() {
|
||||||
// get current blockheight
|
// get current blockheight
|
||||||
let blkheight: u32 = core.get_current_height()?.try_into()?;
|
let blkheight: u32 = daemon.get_current_height()?.try_into()?;
|
||||||
// update the new outpoints
|
// update the new outpoints
|
||||||
for o in new_outpoints.iter_mut() {
|
for o in new_outpoints.iter_mut() {
|
||||||
o.1.blockheight = blkheight;
|
o.1.blockheight = blkheight;
|
||||||
@ -441,34 +435,32 @@ fn faucet_send(
|
|||||||
|
|
||||||
// broadcast one or two transactions
|
// broadcast one or two transactions
|
||||||
if first_tx.is_some() {
|
if first_tx.is_some() {
|
||||||
core.broadcast(&first_tx.unwrap())?;
|
daemon.broadcast(&first_tx.unwrap())?;
|
||||||
}
|
}
|
||||||
core.broadcast(&final_tx)?;
|
daemon.broadcast(&final_tx)?;
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::msg("Failed to lock daemon"));
|
return Err(Error::msg("Failed to lock daemon"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// update our sp_client with the change output(s)
|
// update our sp_client with the change output(s)
|
||||||
let mut outputs = sp_outputs
|
let mut outputs = sp_wallet.get_outputs()?;
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("{}", e.to_string())))?;
|
|
||||||
|
|
||||||
outputs.extend_from(new_outpoints);
|
outputs.extend_from(new_outpoints);
|
||||||
|
|
||||||
log::debug!("{:?}", outputs.to_outpoints_list());
|
// save to disk
|
||||||
|
sp_wallet.get_storage()?.save(outputs.deref())?;
|
||||||
|
|
||||||
Ok(final_tx.txid())
|
Ok(final_tx.txid())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_faucet_request(
|
fn handle_faucet_request(
|
||||||
msg: &str,
|
msg: &str,
|
||||||
sp_client: Arc<Mutex<SpClient>>,
|
sp_wallet: Arc<SilentPaymentWallet>,
|
||||||
sp_outputs: Arc<Mutex<OutputList>>,
|
shared_daemon: SharedDaemon,
|
||||||
daemon: Arc<Mutex<Daemon>>,
|
|
||||||
) -> Result<Txid> {
|
) -> Result<Txid> {
|
||||||
if let Ok(sp_address) = SilentPaymentAddress::try_from(&msg["faucet".len()..]) {
|
if let Ok(sp_address) = SilentPaymentAddress::try_from(&msg["faucet".len()..]) {
|
||||||
// send bootstrap coins to this sp_address
|
// send bootstrap coins to this sp_address
|
||||||
faucet_send(sp_address, sp_client, sp_outputs, daemon)
|
faucet_send(sp_address, sp_wallet, shared_daemon)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::msg(format!(
|
Err(Error::msg(format!(
|
||||||
"faucet message with unparsable sp_address"
|
"faucet message with unparsable sp_address"
|
||||||
@ -477,12 +469,11 @@ fn handle_faucet_request(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connection(
|
async fn handle_connection(
|
||||||
peer_map: PeerMap,
|
peers: PeerMap,
|
||||||
|
shared_daemon: SharedDaemon,
|
||||||
|
sp_wallet: Arc<SilentPaymentWallet>,
|
||||||
raw_stream: TcpStream,
|
raw_stream: TcpStream,
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
sp_client: Arc<Mutex<SpClient>>,
|
|
||||||
sp_outputs: Arc<Mutex<OutputList>>,
|
|
||||||
daemon: Arc<Mutex<Daemon>>,
|
|
||||||
) {
|
) {
|
||||||
debug!("Incoming TCP connection from: {}", addr);
|
debug!("Incoming TCP connection from: {}", addr);
|
||||||
|
|
||||||
@ -493,24 +484,29 @@ async fn handle_connection(
|
|||||||
|
|
||||||
// Insert the write part of this peer to the peer map.
|
// Insert the write part of this peer to the peer map.
|
||||||
let (tx, rx) = unbounded_channel();
|
let (tx, rx) = unbounded_channel();
|
||||||
peer_map.lock().unwrap().insert(addr, tx);
|
match peers.lock_anyhow() {
|
||||||
|
Ok(mut peer_map) => peer_map.insert(addr, tx),
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{}", e);
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (outgoing, incoming) = ws_stream.split();
|
let (outgoing, incoming) = ws_stream.split();
|
||||||
|
|
||||||
let broadcast_incoming = incoming.try_for_each({
|
let broadcast_incoming = incoming.try_for_each({
|
||||||
let peer_map = peer_map.clone();
|
let peers = peers.clone();
|
||||||
move |msg| {
|
move |msg| {
|
||||||
if msg.is_text() {
|
if msg.is_text() {
|
||||||
if msg.to_string().starts_with("faucet") {
|
if msg.to_string().starts_with("faucet") {
|
||||||
match handle_faucet_request(
|
match handle_faucet_request(
|
||||||
&msg.to_string(),
|
&msg.to_string(),
|
||||||
sp_client.clone(),
|
sp_wallet.clone(),
|
||||||
sp_outputs.clone(),
|
shared_daemon.clone(),
|
||||||
daemon.clone(),
|
|
||||||
) {
|
) {
|
||||||
Ok(txid) => {
|
Ok(txid) => {
|
||||||
if let Err(e) = broadcast_message(
|
if let Err(e) = broadcast_message(
|
||||||
peer_map.clone(),
|
peers.clone(),
|
||||||
Message::Text(format!("faucet{}", txid.to_string())),
|
Message::Text(format!("faucet{}", txid.to_string())),
|
||||||
BroadcastType::Sender(addr),
|
BroadcastType::Sender(addr),
|
||||||
) {
|
) {
|
||||||
@ -521,7 +517,7 @@ async fn handle_connection(
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if let Err(e) = broadcast_message(
|
if let Err(e) = broadcast_message(
|
||||||
peer_map.clone(),
|
peers.clone(),
|
||||||
Message::Text(e.to_string()),
|
Message::Text(e.to_string()),
|
||||||
BroadcastType::Sender(addr),
|
BroadcastType::Sender(addr),
|
||||||
) {
|
) {
|
||||||
@ -532,7 +528,7 @@ async fn handle_connection(
|
|||||||
} else {
|
} else {
|
||||||
// we just send it `as is` to everyone except sender
|
// we just send it `as is` to everyone except sender
|
||||||
if let Err(e) =
|
if let Err(e) =
|
||||||
broadcast_message(peer_map.clone(), msg, BroadcastType::ExcludeSender(addr))
|
broadcast_message(peers.clone(), msg, BroadcastType::ExcludeSender(addr))
|
||||||
{
|
{
|
||||||
log::error!("Failed to broadcast message: {}", e);
|
log::error!("Failed to broadcast message: {}", e);
|
||||||
}
|
}
|
||||||
@ -558,7 +554,7 @@ async fn handle_connection(
|
|||||||
future::select(broadcast_incoming, receive_from_others).await;
|
future::select(broadcast_incoming, receive_from_others).await;
|
||||||
|
|
||||||
debug!("{} disconnected", &addr);
|
debug!("{} disconnected", &addr);
|
||||||
peer_map.lock().unwrap().remove(&addr);
|
peers.lock().unwrap().remove(&addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flatten_msg(parts: &[Vec<u8>]) -> Vec<u8> {
|
fn flatten_msg(parts: &[Vec<u8>]) -> Vec<u8> {
|
||||||
@ -628,7 +624,11 @@ fn process_raw_tx_message(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_zmq(peer_map: PeerMap, daemon: Arc<Mutex<Daemon>>) {
|
async fn handle_zmq(
|
||||||
|
peers: PeerMap,
|
||||||
|
shared_daemon: SharedDaemon,
|
||||||
|
sp_wallet: Arc<SilentPaymentWallet>,
|
||||||
|
) {
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
debug!("Starting listening on Core");
|
debug!("Starting listening on Core");
|
||||||
for msg in bitcoincore_zmq::subscribe_receiver(&["tcp://127.0.0.1:29000"]).unwrap() {
|
for msg in bitcoincore_zmq::subscribe_receiver(&["tcp://127.0.0.1:29000"]).unwrap() {
|
||||||
@ -643,22 +643,50 @@ async fn handle_zmq(peer_map: PeerMap, daemon: Arc<Mutex<Daemon>>) {
|
|||||||
|
|
||||||
let payload: Vec<u8> = match core_msg.topic_str() {
|
let payload: Vec<u8> = match core_msg.topic_str() {
|
||||||
"rawtx" => {
|
"rawtx" => {
|
||||||
let processed = process_raw_tx_message(&core_msg, daemon.clone());
|
let processed = process_raw_tx_message(&core_msg, shared_daemon.clone());
|
||||||
match processed {
|
match processed {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"rawblock" => {
|
||||||
|
// scan the block for our outputs
|
||||||
|
match scan_blocks(shared_daemon.clone(), sp_wallet.clone(), 1) {
|
||||||
|
Ok(()) => {
|
||||||
|
let updated = match sp_wallet.get_outputs() {
|
||||||
|
Ok(sp_outputs) => sp_outputs,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{}", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match sp_wallet.get_storage() {
|
||||||
|
Ok(storage) => {
|
||||||
|
if let Err(e) = storage.save(updated.deref()) {
|
||||||
|
log::error!("{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => log::error!("{}", e),
|
||||||
|
};
|
||||||
|
|
||||||
|
flatten_msg(&core_msg.serialize_to_vecs())
|
||||||
|
},
|
||||||
_ => flatten_msg(&core_msg.serialize_to_vecs()),
|
_ => flatten_msg(&core_msg.serialize_to_vecs()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = broadcast_message(
|
if let Err(e) = broadcast_message(
|
||||||
peer_map.clone(),
|
peers.clone(),
|
||||||
Message::Binary(payload),
|
Message::Binary(payload),
|
||||||
BroadcastType::ToAll,
|
BroadcastType::ToAll,
|
||||||
) {
|
) {
|
||||||
log::error!("{}", e.to_string());
|
log::error!("{}", e.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -678,16 +706,15 @@ async fn main() -> Result<()> {
|
|||||||
.expect("Please provide either \"true\" or \"false\"");
|
.expect("Please provide either \"true\" or \"false\"");
|
||||||
let core_wallet: Option<String> = env::args().nth(4);
|
let core_wallet: Option<String> = env::args().nth(4);
|
||||||
|
|
||||||
let state = PeerMap::new(Mutex::new(HashMap::new()));
|
let peers = PeerMap::new(Mutex::new(HashMap::new()));
|
||||||
|
|
||||||
// Connect the rpc daemon
|
// Connect the rpc daemon
|
||||||
let daemon = Daemon::connect(core_wallet).unwrap();
|
let shared_daemon = Arc::new(Mutex::new(Daemon::connect(core_wallet)?));
|
||||||
|
|
||||||
let current_tip: u32 = daemon
|
let current_tip: u32 = shared_daemon
|
||||||
.get_current_height()
|
.lock_anyhow()?
|
||||||
.expect("Failed to make rpc call")
|
.get_current_height()?
|
||||||
.try_into()
|
.try_into()?;
|
||||||
.expect("block count is higher than u32::MAX");
|
|
||||||
|
|
||||||
let mut config_dir = PathBuf::from_str(&env::var("HOME")?)?;
|
let mut config_dir = PathBuf::from_str(&env::var("HOME")?)?;
|
||||||
config_dir.push(".4nk");
|
config_dir.push(".4nk");
|
||||||
@ -753,30 +780,31 @@ async fn main() -> Result<()> {
|
|||||||
|
|
||||||
let last_scan = sp_outputs.get_last_scan();
|
let last_scan = sp_outputs.get_last_scan();
|
||||||
|
|
||||||
let shared_daemon = Arc::new(Mutex::new(daemon));
|
let shared_sp_client = Mutex::new(sp_client);
|
||||||
let shared_sp_client = Arc::new(Mutex::new(sp_client));
|
let shared_sp_outputs = Mutex::new(sp_outputs);
|
||||||
let shared_sp_outputs = Arc::new(Mutex::new(sp_outputs));
|
let shared_outputs_storage = Mutex::new(sp_outputs_file);
|
||||||
|
|
||||||
|
let sp_wallet = Arc::new(SilentPaymentWallet {
|
||||||
|
sp_client: shared_sp_client,
|
||||||
|
sp_outputs: shared_sp_outputs,
|
||||||
|
storage: shared_outputs_storage,
|
||||||
|
});
|
||||||
|
|
||||||
if last_scan < current_tip {
|
if last_scan < current_tip {
|
||||||
log::info!("Scanning for our outputs");
|
log::info!("Scanning for our outputs");
|
||||||
match scan_blocks(
|
scan_blocks(
|
||||||
shared_sp_client.clone(),
|
|
||||||
shared_daemon.clone(),
|
shared_daemon.clone(),
|
||||||
shared_sp_outputs.clone(),
|
sp_wallet.clone(),
|
||||||
current_tip - last_scan,
|
current_tip - last_scan,
|
||||||
) {
|
)?;
|
||||||
Ok(()) => {
|
|
||||||
let updated = shared_sp_outputs
|
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e)))?;
|
|
||||||
sp_outputs_file.save(updated.deref())?;
|
|
||||||
}
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to Bitcoin Core
|
// Subscribe to Bitcoin Core
|
||||||
tokio::spawn(handle_zmq(state.clone(), shared_daemon.clone()));
|
tokio::spawn(handle_zmq(
|
||||||
|
peers.clone(),
|
||||||
|
shared_daemon.clone(),
|
||||||
|
sp_wallet.clone(),
|
||||||
|
));
|
||||||
|
|
||||||
// Create the event loop and TCP listener we'll accept connections on.
|
// Create the event loop and TCP listener we'll accept connections on.
|
||||||
let try_socket = TcpListener::bind(&addr).await;
|
let try_socket = TcpListener::bind(&addr).await;
|
||||||
@ -786,12 +814,11 @@ async fn main() -> Result<()> {
|
|||||||
// Let's spawn the handling of each connection in a separate task.
|
// Let's spawn the handling of each connection in a separate task.
|
||||||
while let Ok((stream, addr)) = listener.accept().await {
|
while let Ok((stream, addr)) = listener.accept().await {
|
||||||
tokio::spawn(handle_connection(
|
tokio::spawn(handle_connection(
|
||||||
state.clone(),
|
peers.clone(),
|
||||||
|
shared_daemon.clone(),
|
||||||
|
sp_wallet.clone(),
|
||||||
stream,
|
stream,
|
||||||
addr,
|
addr,
|
||||||
shared_sp_client.clone(),
|
|
||||||
shared_sp_outputs.clone(),
|
|
||||||
shared_daemon.clone(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
64
src/scan.rs
64
src/scan.rs
@ -1,6 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use electrum_client::ElectrumApi;
|
use electrum_client::ElectrumApi;
|
||||||
@ -9,11 +10,12 @@ use sp_backend::bitcoin::bip158::BlockFilter;
|
|||||||
use sp_backend::bitcoin::hex::DisplayHex;
|
use sp_backend::bitcoin::hex::DisplayHex;
|
||||||
use sp_backend::bitcoin::secp256k1::{All, PublicKey, Scalar, Secp256k1, SecretKey};
|
use sp_backend::bitcoin::secp256k1::{All, PublicKey, Scalar, Secp256k1, SecretKey};
|
||||||
use sp_backend::bitcoin::{BlockHash, OutPoint, Transaction, TxOut, XOnlyPublicKey};
|
use sp_backend::bitcoin::{BlockHash, OutPoint, Transaction, TxOut, XOnlyPublicKey};
|
||||||
|
use sp_backend::db::Storage;
|
||||||
use sp_backend::silentpayments::receiving::Receiver;
|
use sp_backend::silentpayments::receiving::Receiver;
|
||||||
use sp_backend::spclient::{OutputList, OutputSpendStatus, OwnedOutput, SpClient};
|
use sp_backend::spclient::{OutputSpendStatus, OwnedOutput};
|
||||||
use tokio::time::Instant;
|
use tokio::time::Instant;
|
||||||
|
|
||||||
use crate::{electrumclient, Daemon};
|
use crate::{electrumclient, MutexExt, SharedDaemon, SilentPaymentWallet};
|
||||||
|
|
||||||
fn get_script_to_secret_map(
|
fn get_script_to_secret_map(
|
||||||
sp_receiver: &Receiver,
|
sp_receiver: &Receiver,
|
||||||
@ -172,23 +174,17 @@ fn scan_block_inputs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn scan_blocks(
|
pub fn scan_blocks(
|
||||||
sp_client: Arc<Mutex<SpClient>>,
|
shared_daemon: SharedDaemon,
|
||||||
daemon: Arc<Mutex<Daemon>>,
|
sp_wallet: Arc<SilentPaymentWallet>,
|
||||||
sp_outputs: Arc<Mutex<OutputList>>,
|
|
||||||
mut n_blocks_to_scan: u32,
|
mut n_blocks_to_scan: u32,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
log::info!("Starting a rescan");
|
log::info!("Starting a rescan");
|
||||||
let electrum_client = electrumclient::create_electrum_client()?;
|
let electrum_client = electrumclient::create_electrum_client()?;
|
||||||
|
|
||||||
let core = daemon
|
let core = shared_daemon.lock_anyhow()?;
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e.to_string())))?;
|
|
||||||
|
|
||||||
let secp = Secp256k1::new();
|
let secp = Secp256k1::new();
|
||||||
let scan_height = sp_outputs
|
let scan_height = sp_wallet.get_outputs()?.get_last_scan();
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e.to_string())))?
|
|
||||||
.get_last_scan();
|
|
||||||
let tip_height: u32 = core.get_current_height()?.try_into()?;
|
let tip_height: u32 = core.get_current_height()?.try_into()?;
|
||||||
|
|
||||||
// 0 means scan to tip
|
// 0 means scan to tip
|
||||||
@ -215,16 +211,9 @@ pub fn scan_blocks(
|
|||||||
|
|
||||||
let mut tweak_data_map = electrum_client.sp_tweaks(start as usize)?;
|
let mut tweak_data_map = electrum_client.sp_tweaks(start as usize)?;
|
||||||
|
|
||||||
let scan_sk = sp_client
|
let scan_sk = sp_wallet.get_client()?.get_scan_key();
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e.to_string())))?
|
|
||||||
.get_scan_key();
|
|
||||||
|
|
||||||
let sp_receiver = sp_client
|
let sp_receiver = sp_wallet.get_client()?.sp_receiver.clone();
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e.to_string())))?
|
|
||||||
.sp_receiver
|
|
||||||
.clone();
|
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
|
|
||||||
for (blkheight, blkhash, blkfilter) in filters {
|
for (blkheight, blkhash, blkfilter) in filters {
|
||||||
@ -239,10 +228,8 @@ pub fn scan_blocks(
|
|||||||
let candidate_spks: Vec<&[u8; 34]> = spk2secret.keys().collect();
|
let candidate_spks: Vec<&[u8; 34]> = spk2secret.keys().collect();
|
||||||
|
|
||||||
// check if owned inputs are spent
|
// check if owned inputs are spent
|
||||||
let our_outputs: HashMap<OutPoint, OwnedOutput> = sp_outputs
|
let our_outputs: HashMap<OutPoint, OwnedOutput> =
|
||||||
.lock()
|
sp_wallet.get_outputs()?.to_outpoints_list();
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e.to_string())))?
|
|
||||||
.to_outpoints_list();
|
|
||||||
|
|
||||||
let owned_spks: Result<Vec<Vec<u8>>> = our_outputs
|
let owned_spks: Result<Vec<Vec<u8>>> = our_outputs
|
||||||
.iter()
|
.iter()
|
||||||
@ -261,25 +248,18 @@ pub fn scan_blocks(
|
|||||||
let utxo_created_in_block =
|
let utxo_created_in_block =
|
||||||
scan_block_outputs(&sp_receiver, &blk.txdata, blkheight.into(), spk2secret)?;
|
scan_block_outputs(&sp_receiver, &blk.txdata, blkheight.into(), spk2secret)?;
|
||||||
if !utxo_created_in_block.is_empty() {
|
if !utxo_created_in_block.is_empty() {
|
||||||
sp_outputs
|
sp_wallet.get_outputs()?.extend_from(utxo_created_in_block);
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e)))?
|
|
||||||
.extend_from(utxo_created_in_block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the list of outputs just in case
|
// update the list of outputs just in case
|
||||||
// utxos may be created and destroyed in the same block
|
// utxos may be created and destroyed in the same block
|
||||||
let updated_outputs: HashMap<OutPoint, OwnedOutput> = sp_outputs
|
let updated_outputs: HashMap<OutPoint, OwnedOutput> =
|
||||||
.lock()
|
sp_wallet.get_outputs()?.to_outpoints_list();
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e.to_string())))?
|
|
||||||
.to_outpoints_list();
|
|
||||||
|
|
||||||
// search inputs and mark as mined
|
// search inputs and mark as mined
|
||||||
let utxo_destroyed_in_block = scan_block_inputs(updated_outputs, blk.txdata)?;
|
let utxo_destroyed_in_block = scan_block_inputs(updated_outputs, blk.txdata)?;
|
||||||
if !utxo_destroyed_in_block.is_empty() {
|
if !utxo_destroyed_in_block.is_empty() {
|
||||||
let mut outputs = sp_outputs
|
let mut outputs = sp_wallet.get_outputs()?;
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e)))?;
|
|
||||||
for outpoint in utxo_destroyed_in_block {
|
for outpoint in utxo_destroyed_in_block {
|
||||||
outputs.mark_mined(outpoint, blkhash)?;
|
outputs.mark_mined(outpoint, blkhash)?;
|
||||||
}
|
}
|
||||||
@ -294,9 +274,11 @@ pub fn scan_blocks(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// update last_scan height
|
// update last_scan height
|
||||||
sp_outputs
|
let mut updated = sp_wallet.get_outputs()?;
|
||||||
.lock()
|
|
||||||
.map_err(|e| Error::msg(format!("Failed to lock daemon: {}", e)))?
|
updated.update_last_scan(end);
|
||||||
.update_last_scan(end);
|
|
||||||
|
sp_wallet.get_storage()?.save(updated.deref())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user