2021-03-16 08:11:14 +00:00
|
|
|
use crate::bitcoin::wallet::Watchable;
|
2021-04-29 00:40:04 +00:00
|
|
|
use crate::bitcoin::{self, Address, Amount, PunishTimelock, Transaction, TxCancel, Txid};
|
2022-08-27 10:26:55 +00:00
|
|
|
use ::bitcoin::util::sighash::SighashCache;
|
2024-05-27 09:03:20 +00:00
|
|
|
use ::bitcoin::{secp256k1, EcdsaSighashType, Sighash};
|
2021-03-16 07:02:31 +00:00
|
|
|
use anyhow::{Context, Result};
|
2021-03-16 08:11:14 +00:00
|
|
|
use bdk::bitcoin::Script;
|
2022-11-22 13:39:42 +00:00
|
|
|
use bdk::miniscript::Descriptor;
|
2021-02-15 05:09:42 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
2021-03-16 08:11:14 +00:00
|
|
|
#[derive(Debug)]
|
2021-02-15 05:09:42 +00:00
|
|
|
pub struct TxPunish {
|
|
|
|
inner: Transaction,
|
2022-08-27 10:26:55 +00:00
|
|
|
digest: Sighash,
|
2021-02-25 02:52:05 +00:00
|
|
|
cancel_output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
2021-03-16 08:11:14 +00:00
|
|
|
watch_script: Script,
|
2021-02-15 05:09:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TxPunish {
|
|
|
|
pub fn new(
|
|
|
|
tx_cancel: &TxCancel,
|
|
|
|
punish_address: &Address,
|
|
|
|
punish_timelock: PunishTimelock,
|
2021-04-29 00:40:04 +00:00
|
|
|
spending_fee: Amount,
|
2021-02-15 05:09:42 +00:00
|
|
|
) -> Self {
|
2021-04-29 00:40:04 +00:00
|
|
|
let tx_punish =
|
|
|
|
tx_cancel.build_spend_transaction(punish_address, Some(punish_timelock), spending_fee);
|
2021-02-15 05:09:42 +00:00
|
|
|
|
2022-08-27 10:26:55 +00:00
|
|
|
let digest = SighashCache::new(&tx_punish)
|
|
|
|
.segwit_signature_hash(
|
|
|
|
0, // Only one input: cancel transaction
|
|
|
|
&tx_cancel
|
|
|
|
.output_descriptor
|
|
|
|
.script_code()
|
|
|
|
.expect("scriptcode"),
|
2022-11-22 13:39:42 +00:00
|
|
|
tx_cancel.amount().to_sat(),
|
2022-08-27 10:26:55 +00:00
|
|
|
EcdsaSighashType::All,
|
|
|
|
)
|
|
|
|
.expect("sighash");
|
2021-02-15 05:09:42 +00:00
|
|
|
|
|
|
|
Self {
|
|
|
|
inner: tx_punish,
|
|
|
|
digest,
|
2021-02-25 02:52:05 +00:00
|
|
|
cancel_output_descriptor: tx_cancel.output_descriptor.clone(),
|
2021-03-16 08:11:14 +00:00
|
|
|
watch_script: punish_address.script_pubkey(),
|
2021-02-15 05:09:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-27 10:26:55 +00:00
|
|
|
pub fn digest(&self) -> Sighash {
|
2021-02-15 05:09:42 +00:00
|
|
|
self.digest
|
|
|
|
}
|
|
|
|
|
2021-03-16 07:02:31 +00:00
|
|
|
pub fn complete(
|
2021-02-15 05:09:42 +00:00
|
|
|
self,
|
2021-03-16 07:02:31 +00:00
|
|
|
tx_punish_sig_bob: bitcoin::Signature,
|
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
B: bitcoin::PublicKey,
|
2021-02-15 05:09:42 +00:00
|
|
|
) -> Result<Transaction> {
|
2021-03-16 07:02:31 +00:00
|
|
|
let sig_a = a.sign(self.digest());
|
|
|
|
let sig_b = tx_punish_sig_bob;
|
|
|
|
|
2021-02-15 05:09:42 +00:00
|
|
|
let satisfier = {
|
|
|
|
let mut satisfier = HashMap::with_capacity(2);
|
|
|
|
|
2022-08-27 10:26:55 +00:00
|
|
|
let A = a.public().try_into()?;
|
|
|
|
let B = B.try_into()?;
|
2021-02-15 05:09:42 +00:00
|
|
|
|
2024-05-27 09:03:20 +00:00
|
|
|
let sig_a = secp256k1::ecdsa::Signature::from_compact(&sig_a.to_bytes())?;
|
|
|
|
let sig_b = secp256k1::ecdsa::Signature::from_compact(&sig_b.to_bytes())?;
|
2021-02-15 05:09:42 +00:00
|
|
|
// The order in which these are inserted doesn't matter
|
2023-03-15 12:12:28 +00:00
|
|
|
satisfier.insert(
|
|
|
|
A,
|
|
|
|
::bitcoin::EcdsaSig {
|
2024-05-27 09:03:20 +00:00
|
|
|
sig: sig_a,
|
2023-03-15 12:12:28 +00:00
|
|
|
hash_ty: EcdsaSighashType::All,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
satisfier.insert(
|
|
|
|
B,
|
|
|
|
::bitcoin::EcdsaSig {
|
2024-05-27 09:03:20 +00:00
|
|
|
sig: sig_b,
|
2023-03-15 12:12:28 +00:00
|
|
|
hash_ty: EcdsaSighashType::All,
|
|
|
|
},
|
|
|
|
);
|
2021-02-15 05:09:42 +00:00
|
|
|
|
|
|
|
satisfier
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut tx_punish = self.inner;
|
2021-02-25 02:52:05 +00:00
|
|
|
self.cancel_output_descriptor
|
2021-03-16 07:02:31 +00:00
|
|
|
.satisfy(&mut tx_punish.input[0], satisfier)
|
|
|
|
.context("Failed to satisfy inputs with given signatures")?;
|
2021-02-15 05:09:42 +00:00
|
|
|
|
|
|
|
Ok(tx_punish)
|
|
|
|
}
|
2021-05-03 07:35:41 +00:00
|
|
|
|
|
|
|
pub fn weight() -> usize {
|
|
|
|
548
|
|
|
|
}
|
2021-02-15 05:09:42 +00:00
|
|
|
}
|
2021-03-16 08:11:14 +00:00
|
|
|
|
|
|
|
impl Watchable for TxPunish {
|
|
|
|
fn id(&self) -> Txid {
|
|
|
|
self.inner.txid()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn script(&self) -> Script {
|
|
|
|
self.watch_script.clone()
|
|
|
|
}
|
|
|
|
}
|