Faucet refactoring

This commit is contained in:
Sosthene 2024-05-22 10:18:02 +02:00
parent 083843a94a
commit de84c8a1bf

View File

@ -1,5 +1,4 @@
use std::{ use std::{
any::Any,
collections::HashMap, collections::HashMap,
env, env,
fmt::Debug, fmt::Debug,
@ -11,17 +10,12 @@ use std::{
use bitcoincore_rpc::json::{self as bitcoin_json}; use bitcoincore_rpc::json::{self as bitcoin_json};
use futures_util::{future, pin_mut, stream::TryStreamExt, FutureExt, StreamExt}; use futures_util::{future, pin_mut, stream::TryStreamExt, FutureExt, StreamExt};
use log::{debug, error}; use log::{debug, error};
use sdk_common::network::{AnkFlag, AnkNetworkMsg, FaucetMessage, NewTxMessage}; use sdk_common::{
network::{AnkFlag, AnkNetworkMsg, FaucetMessage, NewTxMessage},
silentpayments::create_transaction_for_address_with_shared_secret,
};
use sp_client::bitcoin::{ use sp_client::bitcoin::{
absolute::LockTime, absolute::LockTime, consensus::{deserialize, serialize}, hex::{DisplayHex, FromHex}, key::TapTweak, script::PushBytesBuf, sighash::{Prevouts, SighashCache}, taproot::Signature, transaction::Version, Amount, OutPoint, Psbt, ScriptBuf, TapSighashType, Transaction, TxIn, TxOut, Witness, XOnlyPublicKey
consensus::{deserialize, serialize},
hex::{DisplayHex, FromHex},
key::TapTweak,
sighash::{Prevouts, SighashCache},
taproot::Signature,
transaction::Version,
Amount, OutPoint, Psbt, ScriptBuf, TapSighashType, Transaction, TxIn, TxOut, Witness,
XOnlyPublicKey,
}; };
use sp_client::{ use sp_client::{
bitcoin::secp256k1::{ bitcoin::secp256k1::{
@ -99,12 +93,12 @@ fn broadcast_message(
payload: String, payload: String,
broadcast: BroadcastType, broadcast: BroadcastType,
) -> Result<()> { ) -> Result<()> {
// log::debug!("Broadcasting message: {}", msg);
let ank_msg = AnkNetworkMsg { let ank_msg = AnkNetworkMsg {
flag, flag,
content: payload, content: payload,
}; };
let msg = Message::Text(serde_json::to_string(&ank_msg)?); let msg = Message::Text(serde_json::to_string(&ank_msg)?);
log::debug!("Broadcasting message: {}", msg);
match broadcast { match broadcast {
BroadcastType::Sender(addr) => { BroadcastType::Sender(addr) => {
peers peers
@ -114,7 +108,7 @@ fn broadcast_message(
.find(|(peer_addr, _)| peer_addr == &&addr) .find(|(peer_addr, _)| peer_addr == &&addr)
.ok_or(Error::msg("Failed to find the sender in the peer_map"))? .ok_or(Error::msg("Failed to find the sender in the peer_map"))?
.1 .1
.send(msg.clone())?; .send(msg)?;
} }
BroadcastType::ExcludeSender(addr) => { BroadcastType::ExcludeSender(addr) => {
peers peers
@ -173,6 +167,7 @@ fn spend_from_core(
fn faucet_send( fn faucet_send(
sp_address: SilentPaymentAddress, sp_address: SilentPaymentAddress,
commitment: &str,
sp_wallet: Arc<SilentPaymentWallet>, sp_wallet: Arc<SilentPaymentWallet>,
shared_daemon: SharedDaemon, shared_daemon: SharedDaemon,
) -> Result<Transaction> { ) -> Result<Transaction> {
@ -215,26 +210,13 @@ fn faucet_send(
let wallet = sp_wallet.get_wallet()?; let wallet = sp_wallet.get_wallet()?;
let mut new_psbt = let signed_psbt = create_transaction_for_address_with_shared_secret(
wallet recipient, &wallet, Some(commitment), fee_estimate,
.get_client() )?;
.create_new_psbt(inputs.clone(), vec![recipient], None)?;
log::debug!("Created psbt: {}", new_psbt);
SpClient::set_fees(&mut new_psbt, fee_estimate, sp_address.into())?;
let partial_secret = wallet
.get_client()
.get_partial_secret_from_psbt(&new_psbt)?;
wallet
.get_client()
.fill_sp_outputs(&mut new_psbt, partial_secret)?;
log::debug!("Definitive psbt: {}", new_psbt);
let mut aux_rand = [0u8; 32];
thread_rng().fill(&mut aux_rand);
let mut signed = wallet.get_client().sign_psbt(new_psbt, &aux_rand)?;
log::debug!("signed psbt: {}", signed);
SpClient::finalize_psbt(&mut signed)?;
final_tx = signed.extract_tx()?; let psbt = Psbt::from_str(&signed_psbt)?;
final_tx = psbt.extract_tx()?;
} else { } else {
// let's try to spend directly from the mining address // let's try to spend directly from the mining address
let secp = Secp256k1::signing_only(); let secp = Secp256k1::signing_only();
@ -252,6 +234,7 @@ fn faucet_send(
) )
); );
// This is ugly and can be streamlined
// create a new transaction that spends the newly created UTXO to the sp_address // create a new transaction that spends the newly created UTXO to the sp_address
let mut faucet_tx = Transaction { let mut faucet_tx = Transaction {
input: vec![TxIn { input: vec![TxIn {
@ -290,6 +273,10 @@ fn faucet_send(
let ext_spk = ScriptBuf::new_p2tr_tweaked(ext_output_key.dangerous_assume_tweaked()); let ext_spk = ScriptBuf::new_p2tr_tweaked(ext_output_key.dangerous_assume_tweaked());
let change_spk = ScriptBuf::new_p2tr_tweaked(change_output_key.dangerous_assume_tweaked()); let change_spk = ScriptBuf::new_p2tr_tweaked(change_output_key.dangerous_assume_tweaked());
let mut op_return = PushBytesBuf::new();
op_return.extend_from_slice(&Vec::from_hex(commitment)?)?;
let data_spk = ScriptBuf::new_op_return(op_return);
// Take some margin to pay for the fees // Take some margin to pay for the fees
if core_tx.output[0].value < FAUCET_AMT * 4 { if core_tx.output[0].value < FAUCET_AMT * 4 {
return Err(Error::msg("Not enough funds")); return Err(Error::msg("Not enough funds"));
@ -305,6 +292,10 @@ fn faucet_send(
value: change_amt, value: change_amt,
script_pubkey: change_spk, script_pubkey: change_spk,
}); });
faucet_tx.output.push(TxOut {
value: Amount::from_sat(0),
script_pubkey: data_spk,
});
// dummy signature only used for fee estimation // dummy signature only used for fee estimation
faucet_tx.input[0].witness.push([1; 64].to_vec()); faucet_tx.input[0].witness.push([1; 64].to_vec());
@ -344,7 +335,8 @@ fn faucet_send(
if first_tx.is_some() { if first_tx.is_some() {
daemon.broadcast(&first_tx.unwrap())?; daemon.broadcast(&first_tx.unwrap())?;
} }
daemon.broadcast(&final_tx)?; let txid = daemon.broadcast(&final_tx)?;
debug!("Sent tx {}", txid);
} else { } else {
return Err(Error::msg("Failed to lock daemon")); return Err(Error::msg("Failed to lock daemon"));
} }
@ -353,14 +345,19 @@ fn faucet_send(
} }
fn handle_faucet_request( fn handle_faucet_request(
msg: &str, msg: &FaucetMessage,
sp_wallet: Arc<SilentPaymentWallet>, sp_wallet: Arc<SilentPaymentWallet>,
shared_daemon: SharedDaemon, shared_daemon: SharedDaemon,
) -> Result<NewTxMessage> { ) -> Result<NewTxMessage> {
let sp_address = SilentPaymentAddress::try_from(msg)?; let sp_address = SilentPaymentAddress::try_from(msg.sp_address.as_str())?;
debug!("Sending bootstrap coins to {}", sp_address); debug!("Sending bootstrap coins to {}", sp_address);
// send bootstrap coins to this sp_address // send bootstrap coins to this sp_address
let tx = faucet_send(sp_address, sp_wallet.clone(), shared_daemon.clone())?; let tx = faucet_send(
sp_address,
&msg.commitment,
sp_wallet.clone(),
shared_daemon.clone(),
)?;
// get the tweak // get the tweak
let partial_tweak = compute_partial_tweak_to_transaction(&tx, shared_daemon.clone())?; let partial_tweak = compute_partial_tweak_to_transaction(&tx, shared_daemon.clone())?;
@ -442,24 +439,16 @@ async fn handle_connection(
if let Ok(content) = serde_json::from_str::<FaucetMessage>(&ank_msg.content) if let Ok(content) = serde_json::from_str::<FaucetMessage>(&ank_msg.content)
{ {
match handle_faucet_request( match handle_faucet_request(
&content.sp_address, &content,
sp_wallet.clone(), sp_wallet.clone(),
shared_daemon.clone(), shared_daemon.clone(),
) { ) {
Ok(new_tx_msg) => { Ok(new_tx_msg) => {
if let Err(e) = broadcast_message( debug!(
peers.clone(), "Obtained new_tx_msg: {}",
AnkFlag::NewTx, serde_json::to_string(&new_tx_msg).unwrap()
serde_json::to_string(&new_tx_msg)
.expect("This should not fail"),
BroadcastType::Sender(addr),
) {
log::error!(
"Failed to broadcast message: {}",
e.to_string()
); );
} }
}
Err(e) => { Err(e) => {
log::error!("Failed to send faucet tx: {}", e); log::error!("Failed to send faucet tx: {}", e);
if let Err(e) = broadcast_message( if let Err(e) = broadcast_message(
@ -502,13 +491,12 @@ async fn handle_connection(
if let Err(e) = broadcast_message( if let Err(e) = broadcast_message(
peers.clone(), peers.clone(),
AnkFlag::Unknown, AnkFlag::Unknown,
serde_json::to_string(&ank_msg.content) serde_json::to_string(&ank_msg.content).expect("This should not fail"),
.expect("This should not fail"),
BroadcastType::ExcludeSender(addr), BroadcastType::ExcludeSender(addr),
) { ) {
log::error!("Failed to send message with error: {}", e); log::error!("Failed to send message with error: {}", e);
} }
}, }
AnkFlag::Prd => unimplemented!(), AnkFlag::Prd => unimplemented!(),
}, },
Err(_) => log::error!("Failed to parse network message"), Err(_) => log::error!("Failed to parse network message"),
@ -578,6 +566,7 @@ fn compute_partial_tweak_to_transaction(
} }
fn create_new_tx_message(transaction: Vec<u8>, daemon: Arc<Mutex<Daemon>>) -> Result<NewTxMessage> { fn create_new_tx_message(transaction: Vec<u8>, daemon: Arc<Mutex<Daemon>>) -> Result<NewTxMessage> {
// debug!("Creating tx message");
let tx: Transaction = deserialize(&transaction)?; let tx: Transaction = deserialize(&transaction)?;
if tx.is_coinbase() { if tx.is_coinbase() {
@ -609,9 +598,13 @@ async fn handle_zmq(peers: PeerMap, shared_daemon: SharedDaemon) {
let payload: String = if let (Some(topic), Some(data)) = (core_msg.get(0), core_msg.get(1)) let payload: String = if let (Some(topic), Some(data)) = (core_msg.get(0), core_msg.get(1))
{ {
// debug!("topic: {}", std::str::from_utf8(&topic).unwrap());
match std::str::from_utf8(&topic) { match std::str::from_utf8(&topic) {
Ok("rawtx") => match create_new_tx_message(data.to_vec(), shared_daemon.clone()) { Ok("rawtx") => match create_new_tx_message(data.to_vec(), shared_daemon.clone()) {
Ok(m) => serde_json::to_string(&m).expect("This shouldn't fail"), Ok(m) => {
debug!("Created message");
serde_json::to_string(&m).expect("This shouldn't fail")
}
Err(e) => { Err(e) => {
error!("{}", e); error!("{}", e);
continue; continue;
@ -628,6 +621,7 @@ async fn handle_zmq(peers: PeerMap, shared_daemon: SharedDaemon) {
continue; continue;
}; };
debug!("Broadcasting message {}", payload);
if let Err(e) = if let Err(e) =
broadcast_message(peers.clone(), AnkFlag::NewTx, payload, BroadcastType::ToAll) broadcast_message(peers.clone(), AnkFlag::NewTx, payload, BroadcastType::ToAll)
{ {