diff --git a/rust/chains/tw_bitcoin/src/babylon/conditions.rs b/rust/chains/tw_bitcoin/src/babylon/conditions.rs index b5b31556391..e31b97ddb92 100644 --- a/rust/chains/tw_bitcoin/src/babylon/conditions.rs +++ b/rust/chains/tw_bitcoin/src/babylon/conditions.rs @@ -2,7 +2,7 @@ // // Copyright © 2017 Trust Wallet. -use crate::babylon::covenant_committee::CovenantCommittee; +use crate::babylon::multi_sig_ordered::MultiSigOrderedKeys; use tw_hash::H32; use tw_keypair::schnorr; use tw_utxo::script::standard_script::opcodes::*; @@ -10,8 +10,6 @@ use tw_utxo::script::Script; const VERIFY: bool = true; const NO_VERIFY: bool = false; -/// We always require only one finality provider to sign. -const FINALITY_PROVIDERS_QUORUM: u32 = 1; /// https://github.com/babylonchain/babylon/blob/dev/docs/transaction-impl-spec.md#op_return-output-description /// ```txt @@ -27,8 +25,8 @@ pub fn new_op_return_script( let mut buf = Vec::with_capacity(71); buf.extend_from_slice(tag.as_slice()); buf.push(version); - buf.extend_from_slice(staker_key.as_slice()); - buf.extend_from_slice(finality_provider_key.as_slice()); + buf.extend_from_slice(staker_key.bytes().as_slice()); + buf.extend_from_slice(finality_provider_key.bytes().as_slice()); buf.extend_from_slice(&locktime.to_be_bytes()); let mut s = Script::new(); @@ -61,7 +59,7 @@ pub fn new_timelock_script(staker_key: &schnorr::XOnlyPublicKey, locktime: u16) /// ``` pub fn new_unbonding_script( staker_key: &schnorr::XOnlyPublicKey, - covenants: &CovenantCommittee, + covenants: &MultiSigOrderedKeys, ) -> Script { let mut s = Script::with_capacity(64); append_single_sig(&mut s, staker_key, VERIFY); @@ -89,16 +87,16 @@ pub fn new_unbonding_script( /// ``` pub fn new_slashing_script( staker_key: &schnorr::XOnlyPublicKey, - finality_providers_keys: &[schnorr::XOnlyPublicKey], - covenants: &CovenantCommittee, + finality_providers_keys: &MultiSigOrderedKeys, + covenants: &MultiSigOrderedKeys, ) -> Script { let mut s = Script::with_capacity(64); append_single_sig(&mut s, staker_key, VERIFY); // We need to run verify to clear the stack, as finality provider multisig is in the middle of the script. append_multi_sig( &mut s, - finality_providers_keys, - FINALITY_PROVIDERS_QUORUM, + finality_providers_keys.public_keys_ordered(), + finality_providers_keys.quorum(), VERIFY, ); // Covenant multisig is always last in script so we do not run verify and leave @@ -114,7 +112,7 @@ pub fn new_slashing_script( } fn append_single_sig(dst: &mut Script, key: &schnorr::XOnlyPublicKey, verify: bool) { - dst.push_slice(key.as_slice()); + dst.push_slice(key.bytes().as_slice()); if verify { dst.push(OP_CHECKSIGVERIFY); } else { @@ -138,7 +136,7 @@ fn append_multi_sig( } for (i, pk_xonly) in pubkeys.iter().enumerate() { - dst.push_slice(pk_xonly.as_slice()); + dst.push_slice(pk_xonly.bytes().as_slice()); if i == 0 { dst.push(OP_CHECKSIG); } else { diff --git a/rust/chains/tw_bitcoin/src/babylon/mod.rs b/rust/chains/tw_bitcoin/src/babylon/mod.rs index 3e7b1f03873..c59063ae77d 100644 --- a/rust/chains/tw_bitcoin/src/babylon/mod.rs +++ b/rust/chains/tw_bitcoin/src/babylon/mod.rs @@ -3,7 +3,7 @@ // Copyright © 2017 Trust Wallet. pub mod conditions; -pub mod covenant_committee; +pub mod multi_sig_ordered; pub mod proto_builder; pub mod spending_data; pub mod spending_info; diff --git a/rust/chains/tw_bitcoin/src/babylon/covenant_committee.rs b/rust/chains/tw_bitcoin/src/babylon/multi_sig_ordered.rs similarity index 77% rename from rust/chains/tw_bitcoin/src/babylon/covenant_committee.rs rename to rust/chains/tw_bitcoin/src/babylon/multi_sig_ordered.rs index 4c8bd4becdd..9faa7256f18 100644 --- a/rust/chains/tw_bitcoin/src/babylon/covenant_committee.rs +++ b/rust/chains/tw_bitcoin/src/babylon/multi_sig_ordered.rs @@ -13,17 +13,17 @@ use tw_utxo::signature::BitcoinSchnorrSignature; type OptionalSignature = Option; type PubkeySigMap = BTreeMap; -pub struct CovenantCommittee { +pub struct MultiSigOrderedKeys { pks: Vec, quorum: u32, } -impl CovenantCommittee { +impl MultiSigOrderedKeys { /// Sort the keys in lexicographical order. pub fn new(mut pks: Vec, quorum: u32) -> SigningResult { if pks.is_empty() { return SigningError::err(SigningErrorType::Error_invalid_params) - .context("No covenant public keys provided"); + .context("No public keys provided"); } if pks.len() < quorum as usize { @@ -35,11 +35,11 @@ impl CovenantCommittee { // TODO it's not optimal to use a `HashSet` because the keys are sorted already. if !pks.iter().all_unique() { return SigningError::err(SigningErrorType::Error_invalid_params) - .context("Covenant committee public keys must be unique"); + .context("Public keys must be unique"); } pks.sort(); - Ok(CovenantCommittee { pks, quorum }) + Ok(MultiSigOrderedKeys { pks, quorum }) } pub fn public_keys_ordered(&self) -> &[schnorr::XOnlyPublicKey] { @@ -50,28 +50,25 @@ impl CovenantCommittee { self.quorum } - pub fn with_partial_signatures<'a, I>( - self, - sigs: I, - ) -> SigningResult + pub fn with_partial_signatures<'a, I>(self, sigs: I) -> SigningResult where I: IntoIterator, { - let mut pk_sig_map = CovenantCommitteeSignatures::checked(self.pks, self.quorum); + let mut pk_sig_map = MultiSigOrdered::checked(self.pks, self.quorum); pk_sig_map.set_partial_signatures(sigs)?; - pk_sig_map.check_covenant_quorum()?; + pk_sig_map.check_quorum()?; Ok(pk_sig_map) } } #[derive(Clone, Debug)] -pub struct CovenantCommitteeSignatures { +pub struct MultiSigOrdered { pk_sig_map: PubkeySigMap, quorum: u32, } -impl CovenantCommitteeSignatures { - /// `pk_sig_map` and `quorum` must be checked at [`CovenantCommittee::new`] already. +impl MultiSigOrdered { + /// `pk_sig_map` and `quorum` must be checked at [`MultiSigOrderedKeys::new`] already. fn checked(pks: Vec, quorum: u32) -> Self { let mut pk_sig_map = PubkeySigMap::new(); @@ -80,7 +77,7 @@ impl CovenantCommitteeSignatures { pk_sig_map.insert(pk, None); } - CovenantCommitteeSignatures { pk_sig_map, quorum } + MultiSigOrdered { pk_sig_map, quorum } } fn set_partial_signatures<'a, I>(&mut self, sigs: I) -> SigningResult<()> @@ -88,30 +85,30 @@ impl CovenantCommitteeSignatures { I: IntoIterator, { // Set the signatures for the specific public keys. - // There can be less signatures than covenant public keys, but not less than `covenant_quorum`. + // There can be less signatures than public keys, but not less than `quorum`. for (pk, sig) in sigs { // Find the signature of the corresponding public key. let pk_sig = self .pk_sig_map .get_mut(pk) .or_tw_err(SigningErrorType::Error_invalid_params) - .context("Signature provided for an unknown covenant committee")?; + .context("Signature provided for an unknown public key")?; // Only one signature per public key allowed. if pk_sig.is_some() { return SigningError::err(SigningErrorType::Error_invalid_params) - .context("Duplicate covenant committee public key"); + .context("Duplicate public key"); } *pk_sig = Some(sig.clone()); } Ok(()) } - fn check_covenant_quorum(&self) -> SigningResult<()> { + fn check_quorum(&self) -> SigningResult<()> { let sig_num = self.pk_sig_map.values().filter(|sig| sig.is_some()).count(); if sig_num < self.quorum as usize { return SigningError::err(SigningErrorType::Error_invalid_params).context(format!( - "Number of covenant committee signatures '{sig_num}' is less than quorum '{}'", + "Number of signatures '{sig_num}' is less than quorum '{}'", self.quorum )); } diff --git a/rust/chains/tw_bitcoin/src/babylon/proto_builder/mod.rs b/rust/chains/tw_bitcoin/src/babylon/proto_builder/mod.rs index 7c58bbbc74f..8f3f6224bd6 100644 --- a/rust/chains/tw_bitcoin/src/babylon/proto_builder/mod.rs +++ b/rust/chains/tw_bitcoin/src/babylon/proto_builder/mod.rs @@ -2,7 +2,7 @@ // // Copyright © 2017 Trust Wallet. -use crate::babylon::covenant_committee::CovenantCommittee; +use crate::babylon::multi_sig_ordered::MultiSigOrderedKeys; use crate::babylon::tx_builder::BabylonStakingParams; use std::borrow::Cow; use tw_coin_entry::error::prelude::*; @@ -14,6 +14,10 @@ use tw_utxo::signature::BitcoinSchnorrSignature; pub mod output_protobuf; pub mod utxo_protobuf; +/// We always require only one finality provider to sign, +/// even if there are multiple finality providers in the script. +const FINALITY_PROVIDERS_QUORUM: u32 = 1; + pub fn staking_params_from_proto( params: &Option, ) -> SigningResult { @@ -30,22 +34,30 @@ pub fn staking_params_from_proto( .try_into() .tw_err(|_| SigningErrorType::Error_invalid_params) .context("stakingTime cannot be greater than 65535")?; - let finality_provider = parse_schnorr_pk(¶ms.finality_provider_public_key) - .context("Invalid finalityProviderPublicKeys")?; let covenants_pks = parse_schnorr_pks(¶ms.covenant_committee_public_keys) .context("Invalid covenantCommitteePublicKeys")?; - let covenants = CovenantCommittee::new(covenants_pks, params.covenant_quorum)?; + let covenants = MultiSigOrderedKeys::new(covenants_pks, params.covenant_quorum) + .context("Invalid covenantCommitteePublicKeys")?; + + let finality_provider = parse_schnorr_pk(¶ms.finality_provider_public_key) + .context("Invalid finalityProviderPublicKey")?; + let finality_providers = + MultiSigOrderedKeys::new(vec![finality_provider], FINALITY_PROVIDERS_QUORUM) + .context("Invalid finalityProviderPublicKey")?; Ok(BabylonStakingParams { staker, staking_locktime, - finality_provider, + finality_providers, covenants, }) } -pub fn parse_schnorr_pk(bytes: &Cow<[u8]>) -> SigningResult { +pub fn parse_schnorr_pk(bytes: T) -> SigningResult +where + T: AsRef<[u8]>, +{ schnorr::XOnlyPublicKey::try_from(bytes.as_ref()).into_tw() } @@ -57,7 +69,7 @@ pub fn parse_schnorr_pubkey_sig( pubkey_sig: &Proto::PublicKeySignature, sighash_ty: SighashType, ) -> SigningResult<(schnorr::XOnlyPublicKey, BitcoinSchnorrSignature)> { - let pk = parse_schnorr_pk(&pubkey_sig.public_key)?; + let pk = parse_schnorr_pk(pubkey_sig.public_key.as_ref())?; let sig = schnorr::Signature::try_from(pubkey_sig.signature.as_ref()) .tw_err(|_| SigningErrorType::Error_invalid_params) .context("Invalid signature")?; diff --git a/rust/chains/tw_bitcoin/src/babylon/proto_builder/output_protobuf.rs b/rust/chains/tw_bitcoin/src/babylon/proto_builder/output_protobuf.rs index 92680634b69..f7be9a9dbc9 100644 --- a/rust/chains/tw_bitcoin/src/babylon/proto_builder/output_protobuf.rs +++ b/rust/chains/tw_bitcoin/src/babylon/proto_builder/output_protobuf.rs @@ -57,7 +57,7 @@ impl<'a, Context: UtxoContext> BabylonOutputProtobuf for OutputProtobuf<'a, Cont Ok(self.prepare_builder()?.babylon_staking_op_return( &tag, &staker, - &finality_provider, + finality_provider, staking_locktime, )) } diff --git a/rust/chains/tw_bitcoin/src/babylon/spending_data.rs b/rust/chains/tw_bitcoin/src/babylon/spending_data.rs index 3eb3ac0558c..5b50ad66e0b 100644 --- a/rust/chains/tw_bitcoin/src/babylon/spending_data.rs +++ b/rust/chains/tw_bitcoin/src/babylon/spending_data.rs @@ -2,7 +2,7 @@ // // Copyright © 2017 Trust Wallet. -use crate::babylon::covenant_committee::CovenantCommitteeSignatures; +use crate::babylon::multi_sig_ordered::MultiSigOrdered; use tw_memory::Data; use tw_utxo::script::standard_script::claims; use tw_utxo::script::Script; @@ -15,14 +15,14 @@ pub struct BabylonUnbondingPath { control_block: Data, /// Signatures signed by covenant committees. /// Sorted by covenant committees public keys in reverse order. - covenant_committee_signatures: CovenantCommitteeSignatures, + covenant_committee_signatures: MultiSigOrdered, } impl BabylonUnbondingPath { pub fn new( unbonding_script: Script, control_block: Data, - covenant_committee_signatures: CovenantCommitteeSignatures, + covenant_committee_signatures: MultiSigOrdered, ) -> Self { BabylonUnbondingPath { unbonding_script, diff --git a/rust/chains/tw_bitcoin/src/babylon/spending_info.rs b/rust/chains/tw_bitcoin/src/babylon/spending_info.rs index 78b1ad9290f..9257803e34d 100644 --- a/rust/chains/tw_bitcoin/src/babylon/spending_info.rs +++ b/rust/chains/tw_bitcoin/src/babylon/spending_info.rs @@ -20,7 +20,7 @@ lazy_static! { schnorr::PublicKey::try_from(UNSPENDABLE_KEY_PATH_BYTES.as_slice()) .expect("Expected a valid unspendable key path"); pub static ref UNSPENDABLE_KEY_PATH_XONLY: bitcoin::key::UntweakedPublicKey = - bitcoin::key::UntweakedPublicKey::from_slice(UNSPENDABLE_KEY_PATH.x_only().as_slice()) + bitcoin::key::UntweakedPublicKey::from_slice(UNSPENDABLE_KEY_PATH.x_only().bytes().as_slice()) .expect("Expected a valid unspendable key path"); } @@ -33,14 +33,16 @@ pub struct StakingSpendInfo { impl StakingSpendInfo { pub fn new(params: &BabylonStakingParams) -> SigningResult { - let fp_xonly = [params.finality_provider.clone()]; let staker_xonly = params.staker.x_only(); let timelock_script = conditions::new_timelock_script(&staker_xonly, params.staking_locktime); let unbonding_script = conditions::new_unbonding_script(&staker_xonly, ¶ms.covenants); - let slashing_script = - conditions::new_slashing_script(&staker_xonly, &fp_xonly, ¶ms.covenants); + let slashing_script = conditions::new_slashing_script( + &staker_xonly, + ¶ms.finality_providers, + ¶ms.covenants, + ); // IMPORTANT - order and leaf depths are important! let spend_info = bitcoin::taproot::TaprootBuilder::new() @@ -50,7 +52,7 @@ impl StakingSpendInfo { .expect("Leaf added at a valid depth") .add_leaf(1, slashing_script.clone().into()) .expect("Leaf added at a valid depth") - .finalize(&secp256k1::SECP256K1, UNSPENDABLE_KEY_PATH_XONLY.clone()) + .finalize(secp256k1::SECP256K1, *UNSPENDABLE_KEY_PATH_XONLY) .expect("Expected a valid Taproot tree"); Ok(StakingSpendInfo { @@ -98,13 +100,15 @@ pub struct UnbondingSpendInfo { impl UnbondingSpendInfo { pub fn new(params: &BabylonStakingParams) -> SigningResult { - let fp_xonly = [params.finality_provider.clone()]; let staker_xonly = params.staker.x_only(); let timelock_script = conditions::new_timelock_script(&staker_xonly, params.staking_locktime); - let slashing_script = - conditions::new_slashing_script(&staker_xonly, &fp_xonly, ¶ms.covenants); + let slashing_script = conditions::new_slashing_script( + &staker_xonly, + ¶ms.finality_providers, + ¶ms.covenants, + ); // IMPORTANT - order and leaf depths are important! let spend_info = bitcoin::taproot::TaprootBuilder::new() @@ -112,7 +116,7 @@ impl UnbondingSpendInfo { .expect("Leaf added at a valid depth") .add_leaf(1, timelock_script.clone().into()) .expect("Leaf added at a valid depth") - .finalize(&secp256k1::SECP256K1, UNSPENDABLE_KEY_PATH_XONLY.clone()) + .finalize(secp256k1::SECP256K1, *UNSPENDABLE_KEY_PATH_XONLY) .expect("Expected a valid Taproot tree"); Ok(UnbondingSpendInfo { diff --git a/rust/chains/tw_bitcoin/src/babylon/tx_builder/mod.rs b/rust/chains/tw_bitcoin/src/babylon/tx_builder/mod.rs index ed6c2786e62..f2ad565b831 100644 --- a/rust/chains/tw_bitcoin/src/babylon/tx_builder/mod.rs +++ b/rust/chains/tw_bitcoin/src/babylon/tx_builder/mod.rs @@ -2,7 +2,7 @@ // // Copyright © 2017 Trust Wallet. -use crate::babylon::covenant_committee::CovenantCommittee; +use crate::babylon::multi_sig_ordered::MultiSigOrderedKeys; use tw_keypair::schnorr; pub mod output; @@ -14,6 +14,6 @@ pub type BabylonUnbondingParams = BabylonStakingParams; pub struct BabylonStakingParams { pub staker: schnorr::PublicKey, pub staking_locktime: u16, - pub finality_provider: schnorr::XOnlyPublicKey, - pub covenants: CovenantCommittee, + pub finality_providers: MultiSigOrderedKeys, + pub covenants: MultiSigOrderedKeys, } diff --git a/rust/chains/tw_bitcoin/src/modules/psbt.rs b/rust/chains/tw_bitcoin/src/modules/psbt.rs index 9f107c1219e..58bb5d54a58 100644 --- a/rust/chains/tw_bitcoin/src/modules/psbt.rs +++ b/rust/chains/tw_bitcoin/src/modules/psbt.rs @@ -3,7 +3,6 @@ // Copyright © 2017 Trust Wallet. use bitcoin::psbt::Psbt; -use tw_encoding::hex::DecodeHex; use tw_utxo::transaction::standard_transaction::Transaction; /// Finalizes the [Partially Signed Bitcoin Transaction](Psbt) @@ -25,36 +24,3 @@ pub fn update_psbt_signed(psbt: &mut Psbt, signed_tx: &Transaction) { } } } - -// 11c64b7f21cc44a64c982da18db19f5fb31e6512610d0f0f79b12814d53c200cd5589fd869efa4d4f6143b7dba4f7884a2bf8f1db20afa4ff7724bad2a84681a -// 22349d945a8627ab359cc4a4aa747a00c44282d6234bf932256794e77ebf5f244f4dc5ccd8c1a91d050a5107bcf863cc12428e7c34b295ed9318014a7026cbb0 -// 885a26f7ccaa1c02239deb8ff94560c44491b4a7ddc5158be1f79a07fd82485879158323910c71e64562240e56f9542be3354be5ddfb10445146bfd60e25a78b -// 2042d4ed84856b24fd73a3e5fd91878cc13d8811dd6ee97258a627e52e639d0b37ad2017921cf156ccb4e73d428f996ed11b245313e37e27c978ac4d2cc21eca4672e4ac2049766ccd9e3cd94343e2040474a77fb37cdfd30530d05f9f1e96ae1e2102c86eba2076d1ae01f8fb6bf30108731c884cddcf57ef6eef2d9d9559e130894e0e40c62cba529c -// c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0b50d6b23527ea75dfcadcee29f64568f1b1772f2456649cc8c33201fcff0c93f5eed1a7cb2bd4335325aa437ec9ec5f2effe1f51aa9dc41da14b0642482cc0c7 -#[test] -fn test_foo() { - use tw_encoding::hex::DecodeHex; - use tw_encoding::hex::ToHex; - use tw_hash::H256; - use tw_keypair::schnorr; - use tw_keypair::traits::VerifyingKeyTrait; - - let x = "70736274ff01005e0200000001f29e073986649ca2c5b9896d9cc606790df58587d4a267e9f90610bc4bffe8690000000000960000000191740000000000002251205d1b83f2e2991c2d80226a54d89255768a77905d63d0d5f51d18476143f90a8e000000000001012b3075000000000000225120fd1b7665d4c5211d0b98600d4915ae7181b0cd7fcac1edc973e2fbc954360a126215c050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac08cec39f47bbd70eeda791f6b48a4bf906e878c87f6e5ca3f650008f39f1d4a51e77ab126d8d0a6c6ca6c2f1c0d31141352fb95112aa2bbd4390a7e4481e3d8dc27209789cdd12bc90bbd73445718f8a709956eb3cce362716a3425610abb75ea1132ad029600b2c001172050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac00000".decode_hex().unwrap(); - let y = Psbt::deserialize(&x).unwrap(); - println!("PSBT:"); - println!("{}", serde_json::to_string(&y).unwrap()); - - // bitcoin::taproot::TaprootSpendInfo::control_block() - // println!("merkle_root: {}", y.inputs[0].tap_scripts.iter().next().unwrap().) - - let sighash = H256::from("478673e3ea9442f7f51072f0516ebeb1d4b9e5e812b0d052ee9edfa3dba431a2"); - let pk = schnorr::PublicKey::try_from( - "039789cdd12bc90bbd73445718f8a709956eb3cce362716a3425610abb75ea1132" - .decode_hex() - .unwrap() - .as_slice(), - ) - .unwrap(); - let sig = schnorr::Signature::from_bytes("2856dd1927e5f95fdc45346261f17455130244f5d3db225ceaef292ed233b66104fea4eb343f7f9ee99a8ee6d67b4e5a95d660bf0299b67d37a96e08e6839be8".decode_hex().unwrap().as_slice()).unwrap(); - assert!(pk.verify(sig, sighash)); -} diff --git a/rust/chains/tw_bitcoin/tests/babylon_staking.rs b/rust/chains/tw_bitcoin/tests/babylon_staking.rs index 25c4e0576fe..801d7cfc4fe 100644 --- a/rust/chains/tw_bitcoin/tests/babylon_staking.rs +++ b/rust/chains/tw_bitcoin/tests/babylon_staking.rs @@ -7,23 +7,21 @@ use bitcoin::taproot::TaprootBuilder; use bitcoin::ScriptBuf; use secp256k1::{PublicKey, SECP256K1}; use tw_bitcoin::babylon::conditions; +use tw_bitcoin::babylon::multi_sig_ordered::MultiSigOrderedKeys; use tw_encoding::hex::{DecodeHex, ToHex}; -use tw_hash::H256; use tw_keypair::schnorr; const BABYLON_MERKLE_ROOTS: &str = include_str!("data/babylon_staking_merkle_roots.json"); const BABYLON_TRANSACTIONS: &str = include_str!("data/babylon_staking_transactions.json"); -/// Parses a JSON string as a XOnly public key bytes. -fn parse_pk(value: &serde_json::Value) -> H256 { +fn parse_pk(value: &serde_json::Value) -> schnorr::XOnlyPublicKey { let pk = value.as_str().unwrap().decode_hex().unwrap(); schnorr::PublicKey::try_from(pk.as_slice()) .unwrap() .x_only() - .bytes() } -fn parse_pks(value: &serde_json::Value) -> Vec { +fn parse_pks(value: &serde_json::Value) -> Vec { value.as_array().unwrap().iter().map(parse_pk).collect() } @@ -42,6 +40,10 @@ fn test_babylon_scripts() { let staker_public_key = parse_pk(¶ms["staker_public_key"]); let staker_time = params["staking_time"].as_u64().unwrap() as u16; + let covenants = MultiSigOrderedKeys::new(covenant_public_keys, convenant_quorum).unwrap(); + let finality_providers = + MultiSigOrderedKeys::new(finality_provider_public_keys, 1).unwrap(); + let expected_timelock_script = expected["staking_transaction_timelock_script_hex"] .as_str() .unwrap(); @@ -53,31 +55,27 @@ fn test_babylon_scripts() { .unwrap(); let timelock_script = conditions::new_timelock_script(&staker_public_key, staker_time); - let unbonding_script = conditions::new_unbonding_script( - &staker_public_key, - covenant_public_keys.clone(), - convenant_quorum, - ) - .expect(name); - let slashing_script = conditions::new_slashing_script( - &staker_public_key, - finality_provider_public_keys, - covenant_public_keys, - convenant_quorum, - ) - .expect(name); + let unbonding_script = conditions::new_unbonding_script(&staker_public_key, &covenants); + let slashing_script = + conditions::new_slashing_script(&staker_public_key, &finality_providers, &covenants); assert_eq!( timelock_script.as_slice().to_hex(), - expected_timelock_script + expected_timelock_script, + "Test '{}' Invalid timelock script", + name ); assert_eq!( unbonding_script.as_slice().to_hex(), - expected_unbonding_script + expected_unbonding_script, + "Test '{}' Invalid unbonding script", + name ); assert_eq!( slashing_script.as_slice().to_hex(), - expected_slashing_script + expected_slashing_script, + "Test '{}' Invalid slashing script", + name ); } } diff --git a/rust/tw_keypair/src/schnorr/public.rs b/rust/tw_keypair/src/schnorr/public.rs index d179231d526..bd6c0c86f2d 100644 --- a/rust/tw_keypair/src/schnorr/public.rs +++ b/rust/tw_keypair/src/schnorr/public.rs @@ -33,7 +33,6 @@ impl PublicKey { pub fn x_only(&self) -> XOnlyPublicKey { let (x_only_pubkey, _parity) = self.public.x_only_public_key(); XOnlyPublicKey { - bytes: H256::from(x_only_pubkey.serialize()), public: x_only_pubkey, } } @@ -66,17 +65,12 @@ impl<'a> TryFrom<&'a [u8]> for PublicKey { #[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] pub struct XOnlyPublicKey { - pub(crate) bytes: H256, pub(crate) public: secp256k1::XOnlyPublicKey, } impl XOnlyPublicKey { pub fn bytes(&self) -> H256 { - self.bytes - } - - pub fn as_slice(&self) -> &[u8] { - self.bytes.as_slice() + H256::from(self.public.serialize()) } } @@ -104,9 +98,8 @@ impl<'a> TryFrom<&'a [u8]> for XOnlyPublicKey { value }; - let bytes = H256::try_from(x_only_slice).map_err(|_| KeyPairError::InvalidPublicKey)?; let public = secp256k1::XOnlyPublicKey::from_slice(x_only_slice) .map_err(|_| KeyPairError::InvalidPublicKey)?; - Ok(XOnlyPublicKey { bytes, public }) + Ok(XOnlyPublicKey { public }) } }