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