1use std::collections::hash_map::Entry;
2use std::collections::HashMap;
3
4use crate::bitvm_client::{self, ClementineBitVMPublicKeys, SECP};
5use crate::builder::script::SpendPath;
6#[cfg(test)]
7use crate::builder::transaction::deposit_signature_owner::DepositSigKeyOwner;
8use crate::builder::transaction::input::SpentTxIn;
9use crate::builder::transaction::{SighashCalculator, TxHandler};
10use crate::config::protocol::ProtocolParamset;
11use crate::rpc::clementine::tagged_signature::SignatureId;
12use crate::rpc::clementine::TaggedSignature;
13use alloy::signers::k256;
14use alloy::signers::local::PrivateKeySigner;
15use bitcoin::hashes::hash160;
16use bitcoin::secp256k1::PublicKey;
17use bitcoin::taproot::{self, LeafVersion, TaprootSpendInfo};
18use bitcoin::{
19 hashes::Hash,
20 secp256k1::{schnorr, Keypair, Message, SecretKey, XOnlyPublicKey},
21 Address, ScriptBuf, TapSighash, TapTweakHash,
22};
23use bitcoin::{Network, OutPoint, TapNodeHash, TapSighashType, Witness};
24use bitvm::signatures::winternitz;
25#[cfg(test)]
26use bitvm::signatures::winternitz::{BinarysearchVerifier, ToBytesConverter, Winternitz};
27use clementine_errors::BridgeError;
28use clementine_errors::TxError;
29use clementine_primitives::EVMAddress;
30use clementine_primitives::{PublicHash, RoundIndex};
31use clementine_utils::sign::TapTweakData;
32use eyre::{Context, OptionExt};
33use hkdf::Hkdf;
34use sha2::Sha256;
35
36pub use clementine_errors::VerificationError;
37
38#[derive(Debug, Clone)]
39pub enum WinternitzDerivationPath {
40 Kickoff(RoundIndex, u32, &'static ProtocolParamset),
43 BitvmAssert(u32, u32, u32, OutPoint, &'static ProtocolParamset),
45 ChallengeAckHash(u32, OutPoint, &'static ProtocolParamset),
48}
49
50impl WinternitzDerivationPath {
51 fn get_type_id(&self) -> u8 {
52 match self {
53 WinternitzDerivationPath::Kickoff(..) => 0u8,
54 WinternitzDerivationPath::BitvmAssert(..) => 1u8,
55 WinternitzDerivationPath::ChallengeAckHash(..) => 2u8,
56 }
57 }
58
59 fn get_network_prefix(&self) -> u8 {
60 let paramset = match self {
61 WinternitzDerivationPath::Kickoff(.., paramset) => paramset,
62 WinternitzDerivationPath::BitvmAssert(.., paramset) => paramset,
63 WinternitzDerivationPath::ChallengeAckHash(.., paramset) => paramset,
64 };
65 match paramset.network {
66 Network::Regtest => 0u8,
67 Network::Testnet4 => 1u8,
68 Network::Signet => 2u8,
69 Network::Bitcoin => 3u8,
70 _ => panic!("Unsupported network {:?}", paramset.network),
72 }
73 }
74
75 fn to_bytes(&self) -> Vec<u8> {
76 let type_id = self.get_type_id();
77 let mut bytes = vec![type_id, self.get_network_prefix()];
78
79 match self {
80 WinternitzDerivationPath::Kickoff(round_idx, kickoff_idx, _) => {
81 bytes.extend_from_slice(&round_idx.to_index().to_be_bytes());
82 bytes.extend_from_slice(&kickoff_idx.to_be_bytes());
83 }
84 WinternitzDerivationPath::BitvmAssert(
85 message_length,
86 pk_type_idx,
87 pk_idx,
88 deposit_outpoint,
89 _,
90 ) => {
91 bytes.extend_from_slice(&message_length.to_be_bytes());
92 bytes.extend_from_slice(&pk_type_idx.to_be_bytes());
93 bytes.extend_from_slice(&pk_idx.to_be_bytes());
94 bytes.extend_from_slice(&deposit_outpoint.txid.to_byte_array());
95 bytes.extend_from_slice(&deposit_outpoint.vout.to_be_bytes());
96 }
97 WinternitzDerivationPath::ChallengeAckHash(watchtower_idx, deposit_outpoint, _) => {
98 bytes.extend_from_slice(&watchtower_idx.to_be_bytes());
99 bytes.extend_from_slice(&deposit_outpoint.txid.to_byte_array());
100 bytes.extend_from_slice(&deposit_outpoint.vout.to_be_bytes());
101 }
102 }
103
104 bytes
105 }
106
107 pub fn get_params(&self) -> winternitz::Parameters {
109 match self {
110 WinternitzDerivationPath::Kickoff(_, _, paramset) => winternitz::Parameters::new(
111 paramset.kickoff_blockhash_commit_length,
112 paramset.winternitz_log_d,
113 ),
114 WinternitzDerivationPath::BitvmAssert(message_length, _, _, _, paramset) => {
115 winternitz::Parameters::new(*message_length, paramset.winternitz_log_d)
116 }
117 WinternitzDerivationPath::ChallengeAckHash(_, _, paramset) => {
118 winternitz::Parameters::new(1, paramset.winternitz_log_d)
119 }
120 }
121 }
122}
123
124fn calc_tweaked_keypair(
125 keypair: &Keypair,
126 merkle_root: Option<TapNodeHash>,
127) -> Result<Keypair, BridgeError> {
128 Ok(keypair
129 .add_xonly_tweak(
130 &SECP,
131 &TapTweakHash::from_key_and_tweak(keypair.x_only_public_key().0, merkle_root)
132 .to_scalar(),
133 )
134 .wrap_err("Failed to add tweak to keypair")?)
135}
136
137fn calc_tweaked_xonly_pk(
138 pubkey: XOnlyPublicKey,
139 merkle_root: Option<TapNodeHash>,
140) -> Result<XOnlyPublicKey, BridgeError> {
141 Ok(pubkey
142 .add_tweak(
143 &SECP,
144 &TapTweakHash::from_key_and_tweak(pubkey, merkle_root).to_scalar(),
145 )
146 .wrap_err("Failed to add tweak to xonly_pk")?
147 .0)
148}
149
150#[derive(Debug, Clone, Default)]
151pub struct TweakCache {
157 tweaked_key_cache: HashMap<(XOnlyPublicKey, Option<TapNodeHash>), XOnlyPublicKey>,
158 tweaked_keypair_cache: HashMap<(XOnlyPublicKey, Option<TapNodeHash>), Keypair>,
160}
161
162impl TweakCache {
163 fn get_tweaked_keypair(
164 &mut self,
165 keypair: &Keypair,
166 merkle_root: Option<TapNodeHash>,
167 ) -> Result<&Keypair, BridgeError> {
168 match self
169 .tweaked_keypair_cache
170 .entry((keypair.x_only_public_key().0, merkle_root))
171 {
172 Entry::Occupied(entry) => Ok(entry.into_mut()),
173 Entry::Vacant(entry) => Ok(entry.insert(calc_tweaked_keypair(keypair, merkle_root)?)),
174 }
175 }
176
177 fn get_tweaked_xonly_key(
178 &mut self,
179 pubkey: XOnlyPublicKey,
180 merkle_root: Option<TapNodeHash>,
181 ) -> Result<XOnlyPublicKey, BridgeError> {
182 match self.tweaked_key_cache.entry((pubkey, merkle_root)) {
183 Entry::Occupied(entry) => Ok(*entry.get()),
184 Entry::Vacant(entry) => Ok(*entry.insert(calc_tweaked_xonly_pk(pubkey, merkle_root)?)),
185 }
186 }
187}
188
189pub fn verify_schnorr(
190 signature: &schnorr::Signature,
191 sighash: &Message,
192 pubkey: XOnlyPublicKey,
193 tweak_data: TapTweakData,
194 tweak_cache: Option<&mut TweakCache>,
195) -> Result<(), BridgeError> {
196 let pubkey = match tweak_data {
197 TapTweakData::KeyPath(merkle_root) => match tweak_cache {
198 Some(cache) => cache.get_tweaked_xonly_key(pubkey, merkle_root)?,
199 None => calc_tweaked_xonly_pk(pubkey, merkle_root)?,
200 },
201 TapTweakData::ScriptPath => pubkey,
202 TapTweakData::Unknown => return Err(eyre::eyre!("Spend Path Unknown").into()),
203 };
204 SECP.verify_schnorr(signature, sighash, &pubkey)
205 .map_err(|_| eyre::eyre!("Failed to verify Schnorr signature").into())
206}
207
208#[derive(Debug, Clone)]
209pub struct Actor {
210 pub keypair: Keypair,
211 pub xonly_public_key: XOnlyPublicKey,
212 pub public_key: PublicKey,
213 pub address: Address,
214 #[cfg(test)]
215 pub annex: Option<Vec<u8>>,
216}
217
218impl clementine_tx_sender::TxSenderSigner for Actor {
219 fn address(&self) -> &Address {
220 &self.address
221 }
222
223 fn xonly_public_key(&self) -> XOnlyPublicKey {
224 self.xonly_public_key
225 }
226
227 fn sign_with_tweak_data(
228 &self,
229 sighash: bitcoin::TapSighash,
230 tweak_data: TapTweakData,
231 ) -> Result<schnorr::Signature, clementine_errors::BridgeError> {
232 self.sign_with_tweak_data(sighash, tweak_data, None)
233 }
234}
235
236impl Actor {
237 #[tracing::instrument(ret(level = tracing::Level::TRACE))]
238 pub fn new(sk: SecretKey, network: bitcoin::Network) -> Self {
239 let keypair = Keypair::from_secret_key(&SECP, &sk);
240 let (xonly, _parity) = XOnlyPublicKey::from_keypair(&keypair);
241 let address = Address::p2tr(&SECP, xonly, None, network);
242
243 Actor {
244 keypair,
245 xonly_public_key: xonly,
246 public_key: keypair.public_key(),
247 address,
248 #[cfg(test)]
249 annex: None,
250 }
251 }
252
253 #[tracing::instrument(skip(self), err(level = tracing::Level::ERROR), ret(level = tracing::Level::TRACE))]
254 fn sign_with_tweak(
255 &self,
256 sighash: TapSighash,
257 merkle_root: Option<TapNodeHash>,
258 tweak_cache: Option<&mut TweakCache>,
259 ) -> Result<schnorr::Signature, BridgeError> {
260 let keypair;
261 let keypair_ref = match tweak_cache {
262 Some(cache) => cache.get_tweaked_keypair(&self.keypair, merkle_root)?,
263 None => {
264 keypair = calc_tweaked_keypair(&self.keypair, merkle_root)?;
265 &keypair
266 }
267 };
268
269 Ok(bitvm_client::SECP
270 .sign_schnorr(&Message::from_digest(*sighash.as_byte_array()), keypair_ref))
271 }
272
273 #[tracing::instrument(skip(self), ret(level = tracing::Level::TRACE))]
274 fn sign(&self, sighash: TapSighash) -> schnorr::Signature {
275 bitvm_client::SECP.sign_schnorr(
276 &Message::from_digest(*sighash.as_byte_array()),
277 &self.keypair,
278 )
279 }
280
281 pub fn sign_with_tweak_data(
282 &self,
283 sighash: TapSighash,
284 tweak_data: TapTweakData,
285 tweak_cache: Option<&mut TweakCache>,
286 ) -> Result<schnorr::Signature, BridgeError> {
287 match tweak_data {
288 TapTweakData::KeyPath(merkle_root) => {
289 self.sign_with_tweak(sighash, merkle_root, tweak_cache)
290 }
291 TapTweakData::ScriptPath => Ok(self.sign(sighash)),
292 TapTweakData::Unknown => Err(eyre::eyre!("Spend Data Unknown").into()),
293 }
294 }
295
296 pub fn get_evm_address(&self) -> Result<EVMAddress, BridgeError> {
297 let x =
298 k256::ecdsa::SigningKey::from_bytes(&self.keypair.secret_key().secret_bytes().into())
299 .wrap_err("Failed to convert secret key to signing key")?;
300 let key: PrivateKeySigner = x.into();
301 let wallet_address = key.address();
302
303 Ok(EVMAddress(wallet_address.into_array()))
304 }
305
306 pub fn get_derived_winternitz_sk(
308 &self,
309 path: WinternitzDerivationPath,
310 ) -> Result<winternitz::SecretKey, BridgeError> {
311 let hk = Hkdf::<Sha256>::new(None, self.keypair.secret_key().as_ref());
312 let path_bytes = path.to_bytes();
313 let mut derived_key = vec![0u8; 32];
314 hk.expand(&path_bytes, &mut derived_key)
315 .map_err(|e| eyre::eyre!("Key derivation failed: {:?}", e))?;
316
317 Ok(derived_key)
318 }
319
320 pub fn derive_winternitz_pk(
322 &self,
323 path: WinternitzDerivationPath,
324 ) -> Result<winternitz::PublicKey, BridgeError> {
325 let winternitz_params = path.get_params();
326
327 let altered_secret_key = self.get_derived_winternitz_sk(path)?;
328 let public_key = winternitz::generate_public_key(&winternitz_params, &altered_secret_key);
329
330 Ok(public_key)
331 }
332
333 #[cfg(test)]
335 pub fn sign_winternitz_signature(
336 &self,
337 path: WinternitzDerivationPath,
338 data: Vec<u8>,
339 ) -> Result<Witness, BridgeError> {
340 let winternitz = Winternitz::<BinarysearchVerifier, ToBytesConverter>::new();
341
342 let winternitz_params = path.get_params();
343
344 let altered_secret_key = self.get_derived_winternitz_sk(path)?;
345
346 let witness = winternitz.sign(&winternitz_params, &altered_secret_key, &data);
347
348 Ok(witness)
349 }
350
351 pub fn generate_preimage_from_path(
352 &self,
353 path: WinternitzDerivationPath,
354 ) -> Result<PublicHash, BridgeError> {
355 let first_preimage = self.get_derived_winternitz_sk(path)?;
356 let second_preimage = hash160::Hash::hash(&first_preimage);
357 Ok(second_preimage.to_byte_array())
358 }
359
360 pub fn generate_public_hash_from_path(
363 &self,
364 path: WinternitzDerivationPath,
365 ) -> Result<PublicHash, BridgeError> {
366 let preimage = self.generate_preimage_from_path(path)?;
367 let hash = hash160::Hash::hash(&preimage);
368 Ok(hash.to_byte_array())
369 }
370
371 pub fn generate_bitvm_pks_for_deposit(
372 &self,
373 deposit_outpoint: OutPoint,
374 paramset: &'static ProtocolParamset,
375 ) -> Result<ClementineBitVMPublicKeys, BridgeError> {
376 let mut pks = ClementineBitVMPublicKeys::create_replacable();
377 let pk_vec = self.derive_winternitz_pk(
378 ClementineBitVMPublicKeys::get_latest_blockhash_derivation(deposit_outpoint, paramset),
379 )?;
380 pks.latest_blockhash_pk = ClementineBitVMPublicKeys::vec_to_array::<43>(&pk_vec);
381 let pk_vec = self.derive_winternitz_pk(
382 ClementineBitVMPublicKeys::get_challenge_sending_watchtowers_derivation(
383 deposit_outpoint,
384 paramset,
385 ),
386 )?;
387 pks.challenge_sending_watchtowers_pk =
388 ClementineBitVMPublicKeys::vec_to_array::<43>(&pk_vec);
389 for i in 0..pks.bitvm_pks.0.len() {
390 let pk_vec = self.derive_winternitz_pk(WinternitzDerivationPath::BitvmAssert(
391 64,
392 3,
393 i as u32,
394 deposit_outpoint,
395 paramset,
396 ))?;
397 pks.bitvm_pks.0[i] = ClementineBitVMPublicKeys::vec_to_array::<67>(&pk_vec);
398 }
399 for i in 0..pks.bitvm_pks.1.len() {
400 let pk_vec = self.derive_winternitz_pk(WinternitzDerivationPath::BitvmAssert(
401 64,
402 4,
403 i as u32,
404 deposit_outpoint,
405 paramset,
406 ))?;
407 pks.bitvm_pks.1[i] = ClementineBitVMPublicKeys::vec_to_array::<67>(&pk_vec);
408 }
409 for i in 0..pks.bitvm_pks.2.len() {
410 let pk_vec = self.derive_winternitz_pk(WinternitzDerivationPath::BitvmAssert(
411 32,
412 5,
413 i as u32,
414 deposit_outpoint,
415 paramset,
416 ))?;
417 pks.bitvm_pks.2[i] = ClementineBitVMPublicKeys::vec_to_array::<35>(&pk_vec);
418 }
419
420 Ok(pks)
421 }
422
423 fn get_saved_signature(
424 signature_id: SignatureId,
425 signatures: &[TaggedSignature],
426 ) -> Option<schnorr::Signature> {
427 signatures
428 .iter()
429 .find(|sig| {
430 sig.signature_id
431 .map(|id| id == signature_id)
432 .unwrap_or(false)
433 })
434 .and_then(|sig| schnorr::Signature::from_slice(sig.signature.as_ref()).ok())
435 }
436
437 pub fn add_script_path_to_witness(
438 witness: &mut Witness,
439 script: &ScriptBuf,
440 spend_info: &TaprootSpendInfo,
441 ) -> Result<(), BridgeError> {
442 let spend_control_block = spend_info
443 .control_block(&(script.clone(), LeafVersion::TapScript))
444 .ok_or_eyre("Failed to find control block for script")?;
445 witness.push(script.clone());
446 witness.push(spend_control_block.serialize());
447 Ok(())
448 }
449
450 pub fn tx_sign_preimage(
451 &self,
452 txhandler: &mut TxHandler,
453 data: impl AsRef<[u8]>,
454 ) -> Result<(), BridgeError> {
455 #[cfg(test)]
456 {
457 txhandler.set_test_annex(self.annex.clone());
458 }
459
460 let mut signed_preimage = false;
461
462 let data = data.as_ref();
463 let signer = move |_: usize,
464 spt: &SpentTxIn,
465 calc_sighash: SighashCalculator<'_>|
466 -> Result<Option<Witness>, BridgeError> {
467 let spendinfo = spt
468 .get_spendable()
469 .get_spend_info()
470 .as_ref()
471 .ok_or(TxError::MissingSpendInfo)?;
472 let signature_id = spt.get_signature_id();
473 match spt.get_spend_path() {
474 SpendPath::ScriptSpend(script_idx) => {
475 let script = spt
476 .get_spendable()
477 .get_scripts()
478 .get(script_idx)
479 .ok_or(TxError::NoScriptAtIndex(script_idx))?;
480 let sighash_type = signature_id
481 .get_deposit_sig_owner()
482 .map(|s| s.sighash_type())?
483 .unwrap_or(TapSighashType::Default);
484
485 use crate::builder::script::ScriptKind as Kind;
486
487 let mut witness = match script.kind() {
488 Kind::PreimageRevealScript(script) => {
489 if script.0 != self.xonly_public_key {
490 return Err(TxError::NotOwnedScriptPath.into());
491 }
492 let signature = self.sign(calc_sighash(sighash_type)?);
493 script.generate_script_inputs(
494 data,
495 &taproot::Signature {
496 signature,
497 sighash_type,
498 },
499 )
500 }
501 Kind::WinternitzCommit(_)
502 | Kind::CheckSig(_)
503 | Kind::Other(_)
504 | Kind::BaseDepositScript(_)
505 | Kind::ReplacementDepositScript(_)
506 | Kind::TimelockScript(_)
507 | Kind::ManualSpend(_) => return Ok(None),
508 };
509
510 if signed_preimage {
511 return Err(eyre::eyre!("Encountered multiple preimage reveal scripts when attempting to commit to only one.").into());
512 }
513
514 signed_preimage = true;
515
516 Self::add_script_path_to_witness(
517 &mut witness,
518 &script.to_script_buf(),
519 spendinfo,
520 )?;
521
522 #[cfg(test)]
524 {
525 if let Some(ref annex) = self.annex {
526 if matches!(
527 signature_id.get_deposit_sig_owner()?,
528 DepositSigKeyOwner::Own(_)
529 ) {
530 witness.push(annex);
531 }
532 }
533 }
534
535 Ok(Some(witness))
536 }
537 SpendPath::KeySpend => Ok(None),
538 SpendPath::Unknown => Err(TxError::SpendPathNotSpecified.into()),
539 }
540 };
541
542 txhandler.sign_txins(signer)?;
543 Ok(())
544 }
545 pub fn tx_sign_winternitz(
546 &self,
547 txhandler: &mut TxHandler,
548 data: &[(Vec<u8>, WinternitzDerivationPath)],
549 ) -> Result<(), BridgeError> {
550 #[cfg(test)]
551 {
552 txhandler.set_test_annex(self.annex.clone());
553 }
554
555 let mut signed_winternitz = false;
556
557 let signer = move |_: usize,
558 spt: &SpentTxIn,
559 calc_sighash: SighashCalculator<'_>|
560 -> Result<Option<Witness>, BridgeError> {
561 let spendinfo = spt
562 .get_spendable()
563 .get_spend_info()
564 .as_ref()
565 .ok_or(TxError::MissingSpendInfo)?;
566 let signature_id = spt.get_signature_id();
567 match spt.get_spend_path() {
568 SpendPath::ScriptSpend(script_idx) => {
569 let script = spt
570 .get_spendable()
571 .get_scripts()
572 .get(script_idx)
573 .ok_or(TxError::NoScriptAtIndex(script_idx))?;
574 let sighash_type = signature_id
575 .get_deposit_sig_owner()
576 .map(|s| s.sighash_type())?
577 .unwrap_or(TapSighashType::Default);
578
579 use crate::builder::script::ScriptKind as Kind;
580
581 let mut witness = match script.kind() {
582 Kind::WinternitzCommit(script) => {
583 if script.checksig_pubkey != self.xonly_public_key {
584 return Err(TxError::NotOwnedScriptPath.into());
585 }
586
587 let mut script_data = Vec::with_capacity(data.len());
588 for (data, path) in data {
589 let secret_key = self.get_derived_winternitz_sk(path.clone())?;
590 script_data.push((data.clone(), secret_key));
591 }
592 script.generate_script_inputs(
593 &script_data,
594 &taproot::Signature {
595 signature: self.sign(calc_sighash(sighash_type)?),
596 sighash_type,
597 },
598 )
599 }
600 Kind::PreimageRevealScript(_)
601 | Kind::CheckSig(_)
602 | Kind::Other(_)
603 | Kind::BaseDepositScript(_)
604 | Kind::ReplacementDepositScript(_)
605 | Kind::TimelockScript(_)
606 | Kind::ManualSpend(_) => return Ok(None),
607 };
608
609 if signed_winternitz {
610 return Err(eyre::eyre!("Encountered multiple winternitz scripts when attempting to commit to only one.").into());
611 }
612
613 signed_winternitz = true;
614
615 Self::add_script_path_to_witness(
616 &mut witness,
617 &script.to_script_buf(),
618 spendinfo,
619 )?;
620
621 #[cfg(test)]
623 {
624 if let Some(ref annex) = self.annex {
625 if matches!(
626 signature_id.get_deposit_sig_owner()?,
627 DepositSigKeyOwner::Own(_)
628 ) {
629 witness.push(annex);
630 }
631 }
632 }
633
634 Ok(Some(witness))
635 }
636 SpendPath::KeySpend => Ok(None),
637 SpendPath::Unknown => Err(TxError::SpendPathNotSpecified.into()),
638 }
639 };
640
641 txhandler.sign_txins(signer)?;
642 Ok(())
643 }
644
645 pub fn tx_sign_and_fill_sigs(
646 &self,
647 txhandler: &mut TxHandler,
648 signatures: &[TaggedSignature],
649 mut tweak_cache: Option<&mut TweakCache>,
650 ) -> Result<(), BridgeError> {
651 #[cfg(test)]
652 {
653 txhandler.set_test_annex(self.annex.clone());
654 }
655
656 let tx_type = txhandler.get_transaction_type();
657 let signer = move |_,
658 spt: &SpentTxIn,
659 calc_sighash: SighashCalculator<'_>|
660 -> Result<Option<Witness>, BridgeError> {
661 let spendinfo = spt
662 .get_spendable()
663 .get_spend_info()
664 .as_ref()
665 .ok_or(TxError::MissingSpendInfo)?;
666 let sighash_type = spt
667 .get_signature_id()
668 .get_deposit_sig_owner()
669 .map(|s| s.sighash_type())?
670 .unwrap_or(TapSighashType::Default);
671
672 let signature_id = spt.get_signature_id();
674 let sig = Self::get_saved_signature(signature_id, signatures);
675 let sighash = calc_sighash(sighash_type)?;
676
677 match spt.get_spend_path() {
678 SpendPath::ScriptSpend(script_idx) => {
679 let script = spt
680 .get_spendable()
681 .get_scripts()
682 .get(script_idx)
683 .ok_or(TxError::NoScriptAtIndex(script_idx))?;
684
685 let sig = sig.map(|sig| taproot::Signature {
686 signature: sig,
687 sighash_type,
688 });
689
690 use crate::builder::script::ScriptKind as Kind;
691
692 let mut witness: Witness = match script.kind() {
694 Kind::BaseDepositScript(script) => {
695 match (sig, script.0 == self.xonly_public_key) {
696 (Some(sig), _) => {
697 Self::verify_signature(
698 &sig.signature,
699 sighash,
700 script.0,
701 TapTweakData::ScriptPath,
702 &signature_id,
703 )?;
704 script.generate_script_inputs(&sig)
705 }
706 (None, true) => {
707 script.generate_script_inputs(&taproot::Signature {
708 signature: self.sign(sighash),
709 sighash_type,
710 })
711 }
712 (None, false) => {
713 return Err(TxError::SignatureNotFound(tx_type).into())
714 }
715 }
716 }
717 Kind::ReplacementDepositScript(script) => {
718 match (sig, script.0 == self.xonly_public_key) {
719 (Some(sig), _) => {
720 Self::verify_signature(
721 &sig.signature,
722 sighash,
723 script.0,
724 TapTweakData::ScriptPath,
725 &signature_id,
726 )?;
727 script.generate_script_inputs(&sig)
728 }
729 (None, true) => {
730 script.generate_script_inputs(&taproot::Signature {
731 signature: self.sign(sighash),
732 sighash_type,
733 })
734 }
735 (None, false) => {
736 return Err(TxError::SignatureNotFound(tx_type).into());
737 }
738 }
739 }
740 Kind::TimelockScript(script) => match (sig, script.0) {
741 (Some(sig), Some(xonly_pk)) => {
742 Self::verify_signature(
743 &sig.signature,
744 sighash,
745 xonly_pk,
746 TapTweakData::ScriptPath,
747 &signature_id,
748 )?;
749 script.generate_script_inputs(Some(&sig))
750 }
751 (None, Some(xonly_key)) if xonly_key == self.xonly_public_key => script
752 .generate_script_inputs(Some(&taproot::Signature {
753 signature: self.sign(sighash),
754 sighash_type,
755 })),
756 (None, Some(_)) => {
757 return Err(TxError::SignatureNotFound(tx_type).into())
758 }
759 (_, None) => Witness::new(),
760 },
761 Kind::CheckSig(script) => match (sig, script.0 == self.xonly_public_key) {
762 (Some(sig), _) => {
763 Self::verify_signature(
764 &sig.signature,
765 sighash,
766 script.0,
767 TapTweakData::ScriptPath,
768 &signature_id,
769 )?;
770 script.generate_script_inputs(&sig)
771 }
772
773 (None, true) => script.generate_script_inputs(&taproot::Signature {
774 signature: self.sign(sighash),
775 sighash_type,
776 }),
777 (None, false) => return Err(TxError::SignatureNotFound(tx_type).into()),
778 },
779 Kind::WinternitzCommit(_)
780 | Kind::PreimageRevealScript(_)
781 | Kind::Other(_)
782 | Kind::ManualSpend(_) => return Ok(None),
783 };
784
785 Self::add_script_path_to_witness(
787 &mut witness,
788 &script.to_script_buf(),
789 spendinfo,
790 )?;
791
792 #[cfg(test)]
794 {
795 if let Some(ref annex) = self.annex {
796 if matches!(
797 signature_id.get_deposit_sig_owner()?,
798 DepositSigKeyOwner::Own(_)
799 ) {
800 witness.push(annex);
801 }
802 }
803 }
804
805 Ok(Some(witness))
806 }
807 SpendPath::KeySpend => {
808 let xonly_public_key = spendinfo.internal_key();
809 let sig = match sig {
810 Some(sig) => {
811 Self::verify_signature(
812 &sig,
813 sighash,
814 xonly_public_key,
815 TapTweakData::KeyPath(spendinfo.merkle_root()),
816 &signature_id,
817 )?;
818 taproot::Signature {
819 signature: sig,
820 sighash_type,
821 }
822 }
823 None => {
824 if xonly_public_key == self.xonly_public_key {
825 taproot::Signature {
826 signature: self.sign_with_tweak(
827 sighash,
828 spendinfo.merkle_root(),
829 tweak_cache.as_deref_mut(),
830 )?,
831 sighash_type,
832 }
833 } else {
834 return Err(TxError::NotOwnKeyPath.into());
835 }
836 }
837 };
838 #[cfg(test)]
839 {
840 let mut witness = Witness::from_slice(&[&sig.serialize()]);
841 if let Some(ref annex) = self.annex {
842 if matches!(
843 signature_id.get_deposit_sig_owner()?,
844 DepositSigKeyOwner::Own(_)
845 ) {
846 witness.push(annex);
847 }
848 }
849 Ok(Some(witness))
850 }
851
852 #[cfg(not(test))]
853 {
854 Ok(Some(Witness::from_slice(&[&sig.serialize()])))
855 }
856 }
857 SpendPath::Unknown => Err(TxError::SpendPathNotSpecified.into()),
858 }
859 };
860
861 txhandler.sign_txins(signer)?;
862 Ok(())
863 }
864
865 fn verify_signature(
867 sig: &schnorr::Signature,
868 sighash: TapSighash,
869 xonly_public_key: XOnlyPublicKey,
870 tweak_data: TapTweakData,
871 signature_id: &SignatureId,
872 ) -> Result<(), BridgeError> {
873 verify_schnorr(
874 sig,
875 &Message::from(sighash),
876 xonly_public_key,
877 tweak_data,
878 None,
879 )
880 .wrap_err(format!(
881 "Failed to verify signature from DB for signature {signature_id:?} for signer xonly pk {xonly_public_key}"
882 ))
883 .map_err(Into::into)
884 }
885}
886
887#[cfg(test)]
888mod tests {
889 use super::Actor;
890 use crate::builder::address::create_taproot_address;
891 use crate::config::protocol::ProtocolParamsetName;
892
893 use super::*;
894 use crate::builder::script::{CheckSig, SpendPath, SpendableScript};
895 use crate::builder::transaction::input::SpendableTxIn;
896 use crate::builder::transaction::output::UnspentTxOut;
897 use crate::builder::transaction::{TxHandler, TxHandlerBuilder};
898 use clementine_errors::TransactionType;
899
900 use crate::bitvm_client::SECP;
901 use crate::rpc::clementine::NormalSignatureKind;
902 use crate::{actor::WinternitzDerivationPath, test::common::*};
903 use bitcoin::secp256k1::{schnorr, Message, SecretKey};
904
905 use bitcoin::sighash::TapSighashType;
906 use bitcoin::transaction::Transaction;
907
908 use bitcoin::secp256k1::rand;
909 use bitcoin::{Amount, Network, OutPoint, Txid};
910 use bitcoincore_rpc::RpcApi;
911 use bitvm::{
912 execute_script,
913 signatures::winternitz::{self, BinarysearchVerifier, ToBytesConverter, Winternitz},
914 treepp::script,
915 };
916 use rand::thread_rng;
917 use std::str::FromStr;
918 use std::sync::Arc;
919
920 fn create_key_spend_tx_handler(actor: &Actor) -> (bitcoin::TxOut, TxHandler) {
922 let (tap_addr, spend_info) =
923 create_taproot_address(&[], Some(actor.xonly_public_key), Network::Regtest);
924 let prevtxo = bitcoin::TxOut {
926 value: Amount::from_sat(1000),
927 script_pubkey: tap_addr.script_pubkey(),
928 };
929 let builder = TxHandlerBuilder::new(TransactionType::Dummy).add_input(
930 NormalSignatureKind::Reimburse2,
931 SpendableTxIn::new(
932 OutPoint::default(),
933 prevtxo.clone(),
934 vec![],
935 Some(spend_info),
936 ),
937 SpendPath::KeySpend,
938 bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
939 );
940
941 (
942 prevtxo,
943 builder
944 .add_output(UnspentTxOut::new(
945 bitcoin::TxOut {
946 value: Amount::from_sat(999),
947 script_pubkey: actor.address.script_pubkey(),
948 },
949 vec![],
950 None,
951 ))
952 .finalize(),
953 )
954 }
955
956 fn create_dummy_checksig_script(actor: &Actor) -> CheckSig {
958 CheckSig(actor.xonly_public_key)
961 }
962
963 fn create_script_spend_tx_handler(actor: &Actor) -> (bitcoin::TxOut, TxHandler) {
965 let script = create_dummy_checksig_script(actor);
968
969 let (tap_addr, spend_info) = create_taproot_address(
970 &[script.to_script_buf()],
971 Some(actor.xonly_public_key),
972 Network::Regtest,
973 );
974
975 let prevutxo = bitcoin::TxOut {
976 value: Amount::from_sat(1000),
977 script_pubkey: tap_addr.script_pubkey(),
978 };
979 let spendable_input = SpendableTxIn::new(
980 OutPoint::default(),
981 prevutxo.clone(),
982 vec![Arc::new(script)],
983 Some(spend_info),
984 );
985
986 let builder = TxHandlerBuilder::new(TransactionType::Dummy).add_input(
987 NormalSignatureKind::KickoffNotFinalized1,
988 spendable_input,
989 SpendPath::ScriptSpend(0),
990 bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
991 );
992
993 (
994 prevutxo,
995 builder
996 .add_output(UnspentTxOut::new(
997 bitcoin::TxOut {
998 value: Amount::from_sat(999),
999 script_pubkey: actor.address.script_pubkey(),
1000 },
1001 vec![],
1002 None,
1003 ))
1004 .finalize(),
1005 )
1006 }
1007
1008 #[test]
1009 fn test_actor_key_spend_verification() {
1010 let sk = SecretKey::new(&mut thread_rng());
1011 let actor = Actor::new(sk, Network::Regtest);
1012 let (utxo, mut txhandler) = create_key_spend_tx_handler(&actor);
1013
1014 actor
1016 .tx_sign_and_fill_sigs(&mut txhandler, &[], None)
1017 .expect("Key spend signature should succeed");
1018
1019 let tx: &Transaction = txhandler.get_cached_tx();
1021
1022 tx.verify(|_| Some(utxo.clone()))
1023 .expect("Expected valid signature for key spend");
1024 }
1025
1026 #[test]
1027 fn test_actor_script_spend_tx_valid() {
1028 let sk = SecretKey::new(&mut thread_rng());
1029 let actor = Actor::new(sk, Network::Regtest);
1030 let (prevutxo, mut txhandler) = create_script_spend_tx_handler(&actor);
1031
1032 let signatures: Vec<_> = vec![];
1035 actor
1036 .tx_sign_and_fill_sigs(&mut txhandler, &signatures, None)
1037 .expect("Script spend partial sign should succeed");
1038
1039 let tx: &Transaction = txhandler.get_cached_tx();
1041
1042 tx.verify(|_| Some(prevutxo.clone()))
1043 .expect("Invalid transaction");
1044 }
1045
1046 #[test]
1047 fn test_actor_script_spend_sig_valid() {
1048 let sk = SecretKey::new(&mut thread_rng());
1049 let actor = Actor::new(sk, Network::Regtest);
1050 let (_, mut txhandler) = create_script_spend_tx_handler(&actor);
1051
1052 let signatures: Vec<_> = vec![];
1055 actor
1056 .tx_sign_and_fill_sigs(&mut txhandler, &signatures, None)
1057 .expect("Script spend partial sign should succeed");
1058
1059 let tx: &Transaction = txhandler.get_cached_tx();
1061
1062 let witness = &tx.input[0].witness;
1065 assert!(!witness.is_empty(), "Witness should not be empty");
1066 let sig = schnorr::Signature::from_slice(&witness[0])
1067 .expect("Failed to parse Schnorr signature from witness");
1068
1069 let sighash = txhandler
1071 .calculate_script_spend_sighash_indexed(0, 0, TapSighashType::Default)
1072 .expect("Sighash computed");
1073
1074 let message = Message::from_digest(*sighash.as_byte_array());
1075 SECP.verify_schnorr(&sig, &message, &actor.xonly_public_key)
1076 .expect("Script spend signature verification failed");
1077 }
1078
1079 #[test]
1080 fn actor_new() {
1081 let sk = SecretKey::new(&mut rand::thread_rng());
1082 let network = Network::Regtest;
1083
1084 let actor = Actor::new(sk, network);
1085
1086 assert_eq!(sk.public_key(&SECP), actor.public_key);
1087 assert_eq!(sk.x_only_public_key(&SECP).0, actor.xonly_public_key);
1088 }
1089
1090 #[test]
1091 fn sign_taproot_pubkey_spend() {
1092 let sk = SecretKey::new(&mut rand::thread_rng());
1093 let network = Network::Regtest;
1094 let actor = Actor::new(sk, network);
1095
1096 let tx_handler = create_key_spend_tx_handler(&actor).1;
1099 let sighash = tx_handler
1100 .calculate_pubkey_spend_sighash(0, bitcoin::TapSighashType::Default)
1101 .expect("calculating pubkey spend sighash");
1102
1103 let signature = actor.sign(sighash);
1104
1105 let message = Message::from_digest(*sighash.as_byte_array());
1106 SECP.verify_schnorr(&signature, &message, &actor.xonly_public_key)
1107 .expect("invalid signature");
1108 }
1109
1110 #[test]
1111 fn sign_taproot_pubkey_spend_tx_with_sighash() {
1112 let sk = SecretKey::new(&mut rand::thread_rng());
1113 let network = Network::Regtest;
1114 let actor = Actor::new(sk, network);
1115
1116 let tx_handler = create_key_spend_tx_handler(&actor).1;
1119 let x = tx_handler
1120 .calculate_pubkey_spend_sighash(0, TapSighashType::Default)
1121 .unwrap();
1122 actor.sign_with_tweak(x, None, None).unwrap();
1123 }
1124
1125 #[tokio::test]
1126 async fn derive_winternitz_pk_uniqueness() {
1127 let paramset: &'static ProtocolParamset = ProtocolParamsetName::Regtest.into();
1128 let config = create_test_config_with_thread_name().await;
1129 let actor = Actor::new(config.secret_key, Network::Regtest);
1130
1131 let mut params = WinternitzDerivationPath::Kickoff(RoundIndex::Round(0), 0, paramset);
1132 let pk0 = actor.derive_winternitz_pk(params.clone()).unwrap();
1133 let pk1 = actor.derive_winternitz_pk(params).unwrap();
1134 assert_eq!(pk0, pk1);
1135
1136 params = WinternitzDerivationPath::Kickoff(RoundIndex::Round(0), 1, paramset);
1137 let pk2 = actor.derive_winternitz_pk(params).unwrap();
1138 assert_ne!(pk0, pk2);
1139 }
1140
1141 impl TweakCache {
1142 fn get_tweaked_xonly_key_cache_size(&self) -> usize {
1143 self.tweaked_key_cache.len()
1144 }
1145 fn get_tweaked_keypair_cache_size(&self) -> usize {
1146 self.tweaked_keypair_cache.len()
1147 }
1148 }
1149
1150 #[tokio::test]
1151 async fn test_tweak_cache() {
1152 let mut tweak_cache = TweakCache::default();
1153 let sk = SecretKey::new(&mut rand::thread_rng());
1154 let keypair = Keypair::from_secret_key(&SECP, &sk);
1155 let sk2 = SecretKey::new(&mut rand::thread_rng());
1156 let keypair2 = Keypair::from_secret_key(&SECP, &sk2);
1157 let sk3 = SecretKey::new(&mut rand::thread_rng());
1158 let keypair3 = Keypair::from_secret_key(&SECP, &sk3);
1159
1160 tweak_cache.get_tweaked_keypair(&keypair, None).unwrap();
1161 assert!(tweak_cache.get_tweaked_keypair_cache_size() == 1);
1162 tweak_cache
1163 .get_tweaked_keypair(&keypair, Some(TapNodeHash::assume_hidden([0x55; 32])))
1164 .unwrap();
1165 assert!(tweak_cache.get_tweaked_keypair_cache_size() == 2);
1166 tweak_cache
1167 .get_tweaked_keypair(&keypair, Some(TapNodeHash::assume_hidden([0x56; 32])))
1168 .unwrap();
1169 assert!(tweak_cache.get_tweaked_keypair_cache_size() == 3);
1170 tweak_cache
1171 .get_tweaked_keypair(&keypair, Some(TapNodeHash::assume_hidden([0x57; 32])))
1172 .unwrap();
1173 assert!(tweak_cache.get_tweaked_keypair_cache_size() == 4);
1174 tweak_cache
1175 .get_tweaked_keypair(&keypair, Some(TapNodeHash::assume_hidden([0x55; 32])))
1176 .unwrap();
1177 tweak_cache.get_tweaked_keypair(&keypair, None).unwrap();
1178 assert!(tweak_cache.get_tweaked_keypair_cache_size() == 4);
1179 tweak_cache.get_tweaked_keypair(&keypair2, None).unwrap();
1180 assert!(tweak_cache.get_tweaked_keypair_cache_size() == 5);
1181 let xonly_pk1 = keypair.x_only_public_key();
1182 let xonly_pk2 = keypair2.x_only_public_key();
1183 let xonly_pk3 = keypair3.x_only_public_key();
1184
1185 tweak_cache
1187 .get_tweaked_xonly_key(xonly_pk1.0, None)
1188 .unwrap();
1189 assert!(tweak_cache.get_tweaked_xonly_key_cache_size() == 1);
1190 tweak_cache
1191 .get_tweaked_xonly_key(xonly_pk1.0, Some(TapNodeHash::assume_hidden([0x55; 32])))
1192 .unwrap();
1193 assert!(tweak_cache.get_tweaked_xonly_key_cache_size() == 2);
1194 tweak_cache
1195 .get_tweaked_xonly_key(xonly_pk2.0, Some(TapNodeHash::assume_hidden([0x55; 32])))
1196 .unwrap();
1197 assert!(tweak_cache.get_tweaked_xonly_key_cache_size() == 3);
1198 tweak_cache
1199 .get_tweaked_xonly_key(xonly_pk3.0, Some(TapNodeHash::assume_hidden([0x55; 32])))
1200 .unwrap();
1201 assert!(tweak_cache.get_tweaked_xonly_key_cache_size() == 4);
1202 tweak_cache
1203 .get_tweaked_xonly_key(xonly_pk1.0, None)
1204 .unwrap();
1205 tweak_cache
1206 .get_tweaked_xonly_key(xonly_pk3.0, Some(TapNodeHash::assume_hidden([0x55; 32])))
1207 .unwrap();
1208 assert!(tweak_cache.get_tweaked_xonly_key_cache_size() == 4);
1209 }
1210
1211 #[tokio::test]
1212 async fn derive_winternitz_pk_fixed_pk() {
1213 let paramset: &'static ProtocolParamset = ProtocolParamsetName::Regtest.into();
1214 let actor = Actor::new(
1215 SecretKey::from_str("451F451F451F451F451F451F451F451F451F451F451F451F451F451F451F451F")
1216 .unwrap(),
1217 Network::Regtest,
1218 );
1219 let params = WinternitzDerivationPath::Kickoff(RoundIndex::Round(0), 1, paramset);
1222 let expected_pk = vec![
1223 101, 197, 179, 64, 250, 67, 109, 29, 241, 138, 5, 24, 94, 33, 175, 150, 152, 91, 168,
1224 177,
1225 ];
1226 assert_eq!(
1227 actor.derive_winternitz_pk(params).unwrap()[0].to_vec(),
1228 expected_pk
1229 );
1230
1231 let deposit_outpoint = OutPoint {
1232 txid: Txid::all_zeros(),
1233 vout: 1,
1234 };
1235
1236 let params = WinternitzDerivationPath::BitvmAssert(3, 0, 0, deposit_outpoint, paramset);
1237 let expected_pk = vec![
1238 175, 225, 87, 0, 121, 25, 91, 88, 22, 210, 26, 117, 146, 84, 228, 150, 199, 181, 186,
1239 33,
1240 ];
1241 assert_eq!(
1242 actor.derive_winternitz_pk(params).unwrap()[0].to_vec(),
1243 expected_pk
1244 );
1245
1246 let params = WinternitzDerivationPath::ChallengeAckHash(0, deposit_outpoint, paramset);
1247 let expected_pk = vec![
1248 247, 46, 220, 228, 70, 245, 147, 30, 64, 207, 189, 137, 222, 217, 244, 96, 68, 114,
1249 243, 13,
1250 ];
1251 assert_eq!(
1252 actor.derive_winternitz_pk(params).unwrap()[0].to_vec(),
1253 expected_pk
1254 );
1255 }
1256
1257 #[tokio::test]
1258 async fn sign_winternitz_signature() {
1259 let config = create_test_config_with_thread_name().await;
1260 let actor = Actor::new(config.secret_key, Network::Regtest);
1261
1262 let data = "iwantporscheasagiftpls".as_bytes().to_vec();
1263 let message_len = data.len() as u32 * 2;
1264 let paramset: &'static ProtocolParamset = ProtocolParamsetName::Regtest.into();
1265
1266 let deposit_outpoint = OutPoint {
1267 txid: Txid::all_zeros(),
1268 vout: 1,
1269 };
1270
1271 let path =
1272 WinternitzDerivationPath::BitvmAssert(message_len, 0, 0, deposit_outpoint, paramset);
1273 let params = winternitz::Parameters::new(message_len, paramset.winternitz_log_d);
1274
1275 let witness = actor
1276 .sign_winternitz_signature(path.clone(), data.clone())
1277 .unwrap();
1278 let pk = actor.derive_winternitz_pk(path.clone()).unwrap();
1279
1280 let winternitz = Winternitz::<BinarysearchVerifier, ToBytesConverter>::new();
1281 let check_sig_script = winternitz.checksig_verify(¶ms, &pk);
1282
1283 let message_checker = script! {
1284 for i in 0..message_len / 2 {
1285 {data[i as usize]}
1286 if i == message_len / 2 - 1 {
1287 OP_EQUAL
1288 } else {
1289 OP_EQUALVERIFY
1290 }
1291 }
1292 };
1293
1294 let script = script!({witness} {check_sig_script} {message_checker});
1295 let ret = execute_script(script);
1296 assert!(ret.success);
1297 }
1298
1299 #[tokio::test]
1300 async fn test_key_spend_signing() {
1301 let mut config = create_test_config_with_thread_name().await;
1303 let regtest = create_regtest_rpc(&mut config).await;
1304 let rpc = regtest.rpc();
1305 let sk = SecretKey::new(&mut thread_rng());
1306 let actor = Actor::new(sk, Network::Regtest);
1307
1308 let (tap_addr, spend_info) =
1310 create_taproot_address(&[], Some(actor.xonly_public_key), Network::Regtest);
1311 let prevtxo = bitcoin::TxOut {
1312 value: Amount::from_sat(50000), script_pubkey: tap_addr.script_pubkey(),
1314 };
1315
1316 let outpoint = rpc
1318 .send_to_address(&tap_addr, Amount::from_sat(50000))
1319 .await
1320 .unwrap();
1321
1322 rpc.mine_blocks(1).await.unwrap(); let mut builder = TxHandlerBuilder::new(TransactionType::Dummy)
1326 .add_input(
1328 NormalSignatureKind::Challenge,
1329 SpendableTxIn::new(outpoint, prevtxo.clone(), vec![], Some(spend_info.clone())),
1330 SpendPath::KeySpend,
1331 bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
1332 );
1333
1334 builder = builder.add_output(UnspentTxOut::new(
1336 bitcoin::TxOut {
1337 value: Amount::from_sat(49000), script_pubkey: actor.address.script_pubkey(),
1339 },
1340 vec![],
1341 None,
1342 ));
1343
1344 let mut txhandler = builder.finalize();
1345
1346 actor
1348 .tx_sign_and_fill_sigs(&mut txhandler, &[], None)
1349 .expect("Key spend signature with SighashNone should succeed");
1350
1351 let tx: &Transaction = txhandler.get_cached_tx();
1353
1354 let mempool_accept_result = rpc.test_mempool_accept(&[tx]).await.unwrap();
1356
1357 assert!(
1358 mempool_accept_result[0].allowed.unwrap(),
1359 "Transaction should be allowed in mempool. Rejection reason: {:?}",
1360 mempool_accept_result[0].reject_reason.as_ref().unwrap()
1361 );
1362
1363 let mut builder = TxHandlerBuilder::new(TransactionType::Dummy)
1365 .add_input(
1367 NormalSignatureKind::Reimburse2,
1368 SpendableTxIn::new(outpoint, prevtxo.clone(), vec![], Some(spend_info.clone())),
1369 SpendPath::KeySpend,
1370 bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
1371 );
1372
1373 builder = builder.add_output(UnspentTxOut::new(
1375 bitcoin::TxOut {
1376 value: Amount::from_sat(39000), script_pubkey: actor.address.script_pubkey(),
1378 },
1379 vec![],
1380 None,
1381 ));
1382
1383 let mut txhandler = builder.finalize();
1384
1385 actor
1387 .tx_sign_and_fill_sigs(&mut txhandler, &[], None)
1388 .expect("Key spend signature with SighashDefault should succeed");
1389
1390 let tx: &Transaction = txhandler.get_cached_tx();
1392
1393 let mempool_accept_result = rpc.test_mempool_accept(&[tx]).await.unwrap();
1395
1396 assert!(
1397 mempool_accept_result[0].allowed.unwrap(),
1398 "Transaction should be allowed in mempool. Rejection reason: {:?}",
1399 mempool_accept_result[0].reject_reason.as_ref().unwrap()
1400 );
1401 }
1402}