diff --git a/bitcoin-rpc-provider/src/lib.rs b/bitcoin-rpc-provider/src/lib.rs index 92d3b96b..99a8969f 100644 --- a/bitcoin-rpc-provider/src/lib.rs +++ b/bitcoin-rpc-provider/src/lib.rs @@ -7,6 +7,8 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; use bitcoin::consensus::encode::Error as EncodeError; +use bitcoin::hashes::hex::ToHex; +use bitcoin::hashes::serde; use bitcoin::psbt::PartiallySignedTransaction; use bitcoin::secp256k1::rand::thread_rng; use bitcoin::secp256k1::{PublicKey, SecretKey}; @@ -15,10 +17,12 @@ use bitcoin::{ Txid, }; use bitcoin::{Address, OutPoint, TxOut}; +use bitcoincore_rpc::jsonrpc::serde_json; +use bitcoincore_rpc::jsonrpc::serde_json::Value; use bitcoincore_rpc::{json, Auth, Client, RpcApi}; use bitcoincore_rpc_json::AddressType; use dlc_manager::error::Error as ManagerError; -use dlc_manager::{Blockchain, Signer, Utxo, Wallet}; +use dlc_manager::{Blockchain, ContractSignerProvider, SimpleSigner, Utxo, Wallet}; use json::EstimateMode; use lightning::chain::chaininterface::{ConfirmationTarget, FeeEstimator}; use log::error; @@ -102,7 +106,7 @@ impl BitcoinCoreProvider { pub fn new_from_rpc_client(rpc_client: Client) -> Self { let client = Arc::new(Mutex::new(rpc_client)); - let mut fees: HashMap = HashMap::new(); + let mut fees: HashMap = HashMap::with_capacity(7); fees.insert(ConfirmationTarget::OnChainSweep, AtomicU32::new(5000)); fees.insert( ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee, @@ -168,7 +172,57 @@ fn enc_err_to_manager_err(_e: EncodeError) -> ManagerError { Error::BitcoinError.into() } -impl Signer for BitcoinCoreProvider { +impl ContractSignerProvider for BitcoinCoreProvider { + type Signer = SimpleSigner; + + fn derive_signer_key_id(&self, _is_offer_party: bool, temp_id: [u8; 32]) -> [u8; 32] { + temp_id // fixme not safe + } + + fn derive_contract_signer(&self, keys_id: [u8; 32]) -> Result { + let label_map = self + .client + .lock() + .unwrap() + .call::>( + "getaddressesbylabel", + &[Value::String(keys_id.to_hex())], + ) + .map_err(rpc_err_to_manager_err)?; + + if let Some(address) = label_map.keys().next() { + // we should only have one address per keys_id + // if not something has gone wrong + assert_eq!(label_map.len(), 1); + + let pk = self + .client + .lock() + .unwrap() + .dump_private_key(address) + .map_err(rpc_err_to_manager_err)?; + Ok(SimpleSigner::new(pk.inner)) + } else { + let sk = SecretKey::new(&mut thread_rng()); + let network = self.get_network()?; + self.client + .lock() + .unwrap() + .import_private_key( + &PrivateKey { + compressed: true, + network, + inner: sk, + }, + Some(&keys_id.to_hex()), + Some(false), + ) + .map_err(rpc_err_to_manager_err)?; + + Ok(SimpleSigner::new(sk)) + } + } + fn get_secret_key_for_pubkey(&self, pubkey: &PublicKey) -> Result { let b_pubkey = bitcoin::PublicKey { compressed: true, @@ -182,60 +236,32 @@ impl Signer for BitcoinCoreProvider { .lock() .unwrap() .dump_private_key(&address) + .map_err(|e| { + eprintln!("error getting sk for pk {e:?}"); + e + }) .map_err(rpc_err_to_manager_err)?; Ok(pk.inner) } - fn sign_psbt_input( - &self, - psbt: &mut PartiallySignedTransaction, - input_index: usize, - ) -> Result<(), ManagerError> { - let outpoint = &psbt.unsigned_tx.input[input_index].previous_output; - let tx_out = if let Some(input) = psbt.inputs.get(input_index) { - if let Some(wit_utxo) = &input.witness_utxo { - Ok(wit_utxo.clone()) - } else if let Some(in_tx) = &input.non_witness_utxo { - Ok(in_tx.output[outpoint.vout as usize].clone()) - } else { - Err(ManagerError::InvalidParameters( - "No TxOut for PSBT input".to_string(), - )) - } - } else { - Err(ManagerError::InvalidParameters( - "No TxOut for PSBT input".to_string(), - )) - }?; - - let redeem_script = psbt - .inputs - .get(input_index) - .and_then(|i| i.redeem_script.clone()); - - let input = json::SignRawTransactionInput { - txid: outpoint.txid, - vout: outpoint.vout, - script_pub_key: tx_out.script_pubkey.clone(), - redeem_script, - amount: Some(Amount::from_sat(tx_out.value)), - }; - - let sign_result = self - .client + fn get_new_secret_key(&self) -> Result { + let sk = SecretKey::new(&mut thread_rng()); + let network = self.get_network()?; + self.client .lock() .unwrap() - .sign_raw_transaction_with_wallet(&psbt.unsigned_tx, Some(&[input]), None) + .import_private_key( + &PrivateKey { + compressed: true, + network, + inner: sk, + }, + None, + Some(false), + ) .map_err(rpc_err_to_manager_err)?; - let signed_tx = Transaction::consensus_decode(&mut sign_result.hex.as_slice()) - .map_err(enc_err_to_manager_err)?; - - psbt.inputs[input_index].final_script_sig = - Some(signed_tx.input[input_index].script_sig.clone()); - psbt.inputs[input_index].final_script_witness = - Some(signed_tx.input[input_index].witness.clone()); - Ok(()) + Ok(sk) } } @@ -249,27 +275,14 @@ impl Wallet for BitcoinCoreProvider { } fn get_new_change_address(&self) -> Result { - self.get_new_address() - } - - fn get_new_secret_key(&self) -> Result { - let sk = SecretKey::new(&mut thread_rng()); - let network = self.get_network()?; self.client .lock() .unwrap() - .import_private_key( - &PrivateKey { - compressed: true, - network, - inner: sk, - }, - None, - Some(false), + .call( + "getrawchangeaddress", + &[Value::Null, opt_into_json(Some(AddressType::Bech32))?], ) - .map_err(rpc_err_to_manager_err)?; - - Ok(sk) + .map_err(rpc_err_to_manager_err) } fn get_utxos_for_amount( @@ -321,6 +334,58 @@ impl Wallet for BitcoinCoreProvider { .import_address(address, None, Some(false)) .map_err(rpc_err_to_manager_err) } + + fn sign_psbt_input( + &self, + psbt: &mut PartiallySignedTransaction, + input_index: usize, + ) -> Result<(), ManagerError> { + let outpoint = &psbt.unsigned_tx.input[input_index].previous_output; + let tx_out = if let Some(input) = psbt.inputs.get(input_index) { + if let Some(wit_utxo) = &input.witness_utxo { + Ok(wit_utxo.clone()) + } else if let Some(in_tx) = &input.non_witness_utxo { + Ok(in_tx.output[outpoint.vout as usize].clone()) + } else { + Err(ManagerError::InvalidParameters( + "No TxOut for PSBT input".to_string(), + )) + } + } else { + Err(ManagerError::InvalidParameters( + "No TxOut for PSBT input".to_string(), + )) + }?; + + let redeem_script = psbt + .inputs + .get(input_index) + .and_then(|i| i.redeem_script.clone()); + + let input = json::SignRawTransactionInput { + txid: outpoint.txid, + vout: outpoint.vout, + script_pub_key: tx_out.script_pubkey.clone(), + redeem_script, + amount: Some(Amount::from_sat(tx_out.value)), + }; + + let sign_result = self + .client + .lock() + .unwrap() + .sign_raw_transaction_with_wallet(&psbt.unsigned_tx, Some(&[input]), None) + .map_err(rpc_err_to_manager_err)?; + let signed_tx = Transaction::consensus_decode(&mut sign_result.hex.as_slice()) + .map_err(enc_err_to_manager_err)?; + + psbt.inputs[input_index].final_script_sig = + Some(signed_tx.input[input_index].script_sig.clone()); + psbt.inputs[input_index].final_script_witness = + Some(signed_tx.input[input_index].witness.clone()); + + Ok(()) + } } impl Blockchain for BitcoinCoreProvider { @@ -479,3 +544,22 @@ fn poll_for_fee_estimates( std::thread::sleep(Duration::from_secs(60)); }); } + +/// Shorthand for converting a variable into a serde_json::Value. +fn into_json(val: T) -> bitcoincore_rpc::Result +where + T: serde::ser::Serialize, +{ + Ok(serde_json::to_value(val)?) +} + +/// Shorthand for converting an Option into an Option. +fn opt_into_json(opt: Option) -> Result +where + T: serde::ser::Serialize, +{ + match opt { + Some(val) => Ok(into_json(val).map_err(rpc_err_to_manager_err)?), + None => Ok(Value::Null), + } +} diff --git a/dlc-manager/src/channel/offered_channel.rs b/dlc-manager/src/channel/offered_channel.rs index b13a8dad..63d261df 100644 --- a/dlc-manager/src/channel/offered_channel.rs +++ b/dlc-manager/src/channel/offered_channel.rs @@ -8,7 +8,7 @@ use secp256k1_zkp::PublicKey; use crate::{ contract::offered_contract::OfferedContract, conversion_utils::get_tx_input_infos, - error::Error, ChannelId, ContractId, + error::Error, ChannelId, ContractId, KeysId, }; use super::party_points::PartyBasePoints; @@ -83,6 +83,7 @@ impl OfferedChannel { pub fn from_offer_channel( offer_channel: &OfferChannel, counter_party: PublicKey, + keys_id: KeysId, ) -> Result<(OfferedChannel, OfferedContract), Error> { let channel = OfferedChannel { offered_contract_id: offer_channel.temporary_contract_id, @@ -128,6 +129,7 @@ impl OfferedChannel { .map(|x| x.into()) .collect(), total_collateral: offer_channel.contract_info.get_total_collateral(), + keys_id, }; Ok((channel, contract)) diff --git a/dlc-manager/src/channel/ser.rs b/dlc-manager/src/channel/ser.rs index 2d8a60bd..3de28686 100644 --- a/dlc-manager/src/channel/ser.rs +++ b/dlc-manager/src/channel/ser.rs @@ -50,18 +50,18 @@ impl_dlc_writeable!(SignedChannel, { impl_dlc_writeable_enum!( SignedChannelState,; - (0, Established, {(signed_contract_id, writeable), (own_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (counter_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (buffer_transaction, writeable), (is_offer, writeable)}), - (1, SettledOffered, {(counter_payout, writeable), (next_per_update_point, writeable), (timeout, writeable)}), - (2, SettledReceived, {(own_payout, writeable), (counter_next_per_update_point, writeable)}), - (3, SettledAccepted, {(counter_next_per_update_point, writeable), (own_next_per_update_point, writeable), (settle_tx, writeable), (own_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (timeout, writeable), (own_payout, writeable)}), - (4, SettledConfirmed, {(settle_tx, writeable), (counter_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (own_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (counter_next_per_update_point, writeable), (own_next_per_update_point, writeable), (timeout, writeable), (own_payout, writeable) }), - (5, Settled, {(settle_tx, writeable), (counter_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (own_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature})}), - (6, RenewOffered, {(offered_contract_id, writeable), (counter_payout, writeable), (is_offer, writeable), (offer_next_per_update_point, writeable), (timeout, writeable)}), - (7, RenewAccepted, {(contract_id, writeable), (offer_per_update_point, writeable), (accept_per_update_point, writeable), (buffer_transaction, writeable), (buffer_script_pubkey, writeable), (accept_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (timeout, writeable), (own_payout, writeable)}), - (8, RenewConfirmed, {(contract_id, writeable), (offer_per_update_point, writeable), (accept_per_update_point, writeable), (buffer_transaction, writeable), (buffer_script_pubkey, writeable), (offer_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (accept_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (timeout, writeable), (own_payout, writeable)}), - (9, Closing, {(buffer_transaction, writeable), (signed_cet, writeable), (contract_id, writeable), (attestations, vec)}), + (0, Established, {(signed_contract_id, writeable), (own_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (counter_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (buffer_transaction, writeable), (is_offer, writeable), (keys_id, writeable)}), + (1, SettledOffered, {(counter_payout, writeable), (next_per_update_point, writeable), (timeout, writeable), (keys_id, writeable)}), + (2, SettledReceived, {(own_payout, writeable), (counter_next_per_update_point, writeable), (keys_id, writeable)}), + (3, SettledAccepted, {(counter_next_per_update_point, writeable), (own_next_per_update_point, writeable), (settle_tx, writeable), (own_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (timeout, writeable), (own_payout, writeable), (keys_id, writeable)}), + (4, SettledConfirmed, {(settle_tx, writeable), (counter_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (own_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (counter_next_per_update_point, writeable), (own_next_per_update_point, writeable), (timeout, writeable), (own_payout, writeable), (keys_id, writeable) }), + (5, Settled, {(settle_tx, writeable), (counter_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (own_settle_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (keys_id, writeable)}), + (6, RenewOffered, {(offered_contract_id, writeable), (counter_payout, writeable), (is_offer, writeable), (offer_next_per_update_point, writeable), (timeout, writeable), (keys_id, writeable)}), + (7, RenewAccepted, {(contract_id, writeable), (offer_per_update_point, writeable), (accept_per_update_point, writeable), (buffer_transaction, writeable), (buffer_script_pubkey, writeable), (accept_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (timeout, writeable), (own_payout, writeable), (keys_id, writeable)}), + (8, RenewConfirmed, {(contract_id, writeable), (offer_per_update_point, writeable), (accept_per_update_point, writeable), (buffer_transaction, writeable), (buffer_script_pubkey, writeable), (offer_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (accept_buffer_adaptor_signature, {cb_writeable, write_ecdsa_adaptor_signature, read_ecdsa_adaptor_signature}), (timeout, writeable), (own_payout, writeable), (keys_id, writeable)}), + (9, Closing, {(buffer_transaction, writeable), (signed_cet, writeable), (contract_id, writeable), (attestations, vec), (keys_id, writeable)}), (10, ClosedPunished, { (punishment_txid, writeable) }), - (11, CollaborativeCloseOffered, { (counter_payout, writeable), (offer_signature, writeable), (close_tx, writeable), (timeout, writeable) }) + (11, CollaborativeCloseOffered, { (counter_payout, writeable), (offer_signature, writeable), (close_tx, writeable), (timeout, writeable), (keys_id, writeable) }) ;;(12, Closed), (13, CounterClosed), (14, CollaborativelyClosed) ); diff --git a/dlc-manager/src/channel/signed_channel.rs b/dlc-manager/src/channel/signed_channel.rs index eeee9819..f7b82753 100644 --- a/dlc-manager/src/channel/signed_channel.rs +++ b/dlc-manager/src/channel/signed_channel.rs @@ -8,7 +8,7 @@ use dlc_messages::oracle_msgs::OracleAttestation; use lightning::ln::chan_utils::CounterpartyCommitmentSecrets; use secp256k1_zkp::{ecdsa::Signature, EcdsaAdaptorSignature, PublicKey}; -use crate::{ChannelId, ContractId}; +use crate::{ChannelId, ContractId, KeysId}; use super::party_points::PartyBasePoints; @@ -108,6 +108,8 @@ typed_enum!( /// Whether the local party is the one that initiated the latest channel /// state change. is_offer: bool, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `SettledOffered` state when the local party /// has sent a [`dlc_messages::channel::SettleOffer`] message. @@ -120,6 +122,8 @@ typed_enum!( /// The UNIX epoch at which the counter party will be considered /// unresponsive and the channel will be forced closed. timeout: u64, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `SettledReceived` state when the local party /// has received a [`dlc_messages::channel::SettleOffer`] message. @@ -129,6 +133,8 @@ typed_enum!( /// The per update point to be used by the counter party for the setup /// of the next channel state. counter_next_per_update_point: PublicKey, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `SettledAccepted` state when the local party /// has sent a [`dlc_messages::channel::SettleAccept`] message. @@ -149,6 +155,8 @@ typed_enum!( timeout: u64, /// The payout to the local party after settling the channel. own_payout: u64, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `SettledConfirmed` state when the local party /// has sent a [`dlc_messages::channel::SettleConfirm`] message. @@ -172,6 +180,8 @@ typed_enum!( timeout: u64, /// The payout to the local party after settling the channel. own_payout: u64, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `Settled` state when the local party /// has all the necessary information to close the channel with the last @@ -185,6 +195,8 @@ typed_enum!( /// The adaptor signature for the settle transaction generated by the /// local party. own_settle_adaptor_signature: EcdsaAdaptorSignature, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `RenewOffered` state when the local party /// has sent or received a [`dlc_messages::channel::RenewOffer`] message. @@ -201,6 +213,8 @@ typed_enum!( /// The UNIX epoch at which the counter party will be considered /// unresponsive and the channel will be forced closed. timeout: u64, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `RenewAccepted` state when the local party /// has sent a [`dlc_messages::channel::RenewAccept`] message. @@ -225,6 +239,8 @@ typed_enum!( timeout: u64, /// The payout to the local party attributed for closing the previous state. own_payout: u64, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `RenewConfirmed` state when the local party /// has sent a [`dlc_messages::channel::RenewConfirm`] message. @@ -252,6 +268,8 @@ typed_enum!( timeout: u64, /// The payout to the local party attributed for closing the previous state. own_payout: u64, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `Closing` state when the local party /// has broadcast a buffer transaction and is waiting to finalize the @@ -266,6 +284,8 @@ typed_enum!( contract_id: ContractId, /// The attestations used to decrypt the CET adaptor signature. attestations: Vec, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `Closed` state when it was force closed by /// the local party. @@ -293,6 +313,8 @@ typed_enum!( /// The UNIX epoch at which the counter party will be considered /// unresponsive and the channel will be forced closed. timeout: u64, + /// Keys Id for generating the signers + keys_id: KeysId, }, /// A [`SignedChannel`] is in `CollaborativelyClosed` state when it was /// collaboratively closed. @@ -321,6 +343,28 @@ impl SignedChannel { _ => None, } } + + /// Returns the contract's [`keys_id`] if it has one available. + /// This is used to derive keys + pub fn keys_id(&self) -> Option { + match &self.state { + SignedChannelState::Established { keys_id, .. } => Some(*keys_id), + SignedChannelState::SettledOffered { keys_id, .. } => Some(*keys_id), + SignedChannelState::SettledReceived { keys_id, .. } => Some(*keys_id), + SignedChannelState::SettledAccepted { keys_id, .. } => Some(*keys_id), + SignedChannelState::SettledConfirmed { keys_id, .. } => Some(*keys_id), + SignedChannelState::Settled { keys_id, .. } => Some(*keys_id), + SignedChannelState::RenewOffered { keys_id, .. } => Some(*keys_id), + SignedChannelState::RenewAccepted { keys_id, .. } => Some(*keys_id), + SignedChannelState::RenewConfirmed { keys_id, .. } => Some(*keys_id), + SignedChannelState::Closing { keys_id, .. } => Some(*keys_id), + SignedChannelState::Closed => None, + SignedChannelState::CounterClosed => None, + SignedChannelState::ClosedPunished { .. } => None, + SignedChannelState::CollaborativeCloseOffered { keys_id, .. } => Some(*keys_id), + SignedChannelState::CollaborativelyClosed => None, + } + } } /// A channel that had a successful setup. diff --git a/dlc-manager/src/channel_updater.rs b/dlc-manager/src/channel_updater.rs index 99d2f54f..85b6e388 100644 --- a/dlc-manager/src/channel_updater.rs +++ b/dlc-manager/src/channel_updater.rs @@ -20,7 +20,7 @@ use crate::{ }, error::Error, utils::get_new_temporary_id, - Blockchain, Signer, Time, Wallet, + Blockchain, ContractSigner, ContractSignerProvider, Time, Wallet, }; use bitcoin::{OutPoint, Script, Sequence, Transaction, TxIn, Witness}; use dlc::{ @@ -66,7 +66,7 @@ pub(crate) use get_signed_channel_state; /// Creates an [`OfferedChannel`] and an associated [`OfferedContract`] using /// the given parameter. -pub fn offer_channel( +pub fn offer_channel( secp: &Secp256k1, contract: &ContractInput, counter_party: &PublicKey, @@ -74,24 +74,30 @@ pub fn offer_channel( cet_nsequence: u32, refund_delay: u32, wallet: &W, + signer_provider: &SP, blockchain: &B, time: &T, ) -> Result<(OfferedChannel, OfferedContract), Error> where W::Target: Wallet, + SP::Target: ContractSignerProvider, B::Target: Blockchain, T::Target: Time, { - let (offer_params, _, funding_inputs_info) = crate::utils::get_party_params( - secp, + let id = get_new_temporary_id(); + let keys_id = signer_provider.derive_signer_key_id(true, id); + let signer = signer_provider.derive_contract_signer(keys_id)?; + let (offer_params, funding_inputs_info) = crate::utils::get_party_params( contract.offer_collateral, contract.fee_rate, wallet, + &signer, blockchain, )?; - let party_points = crate::utils::get_party_base_points(secp, wallet)?; + let party_points = crate::utils::get_party_base_points(secp, signer_provider)?; let offered_contract = OfferedContract::new( + id, contract, oracle_announcements.to_vec(), &offer_params, @@ -99,11 +105,12 @@ where counter_party, refund_delay, time.unix_time_now() as u32, + keys_id, ); let temporary_channel_id = get_new_temporary_id(); - let per_update_seed = wallet.get_new_secret_key()?; + let per_update_seed = signer_provider.get_new_secret_key()?; let first_per_update_point = PublicKey::from_secret_key( secp, @@ -131,30 +138,33 @@ where /// Move the given [`OfferedChannel`] and [`OfferedContract`] to an [`AcceptedChannel`] /// and [`AcceptedContract`], returning them as well as the [`AcceptChannel`] /// message to be sent to the counter party. -pub fn accept_channel_offer( +pub fn accept_channel_offer( secp: &Secp256k1, offered_channel: &OfferedChannel, offered_contract: &OfferedContract, wallet: &W, + signer_provider: &SP, blockchain: &B, ) -> Result<(AcceptedChannel, AcceptedContract, AcceptChannel), Error> where W::Target: Wallet, + SP::Target: ContractSignerProvider, B::Target: Blockchain, { assert_eq!(offered_channel.offered_contract_id, offered_contract.id); let total_collateral = offered_contract.total_collateral; - let (accept_params, _, funding_inputs) = crate::utils::get_party_params( - secp, + let signer = signer_provider.derive_contract_signer(offered_contract.keys_id)?; + let (accept_params, funding_inputs) = crate::utils::get_party_params( total_collateral - offered_contract.offer_params.collateral, offered_contract.fee_rate_per_vb, wallet, + &signer, blockchain, )?; - let per_update_seed = wallet.get_new_secret_key()?; + let per_update_seed = signer_provider.get_new_secret_key()?; let first_per_update_point = PublicKey::from_secret_key( secp, @@ -165,7 +175,7 @@ where .expect("to have generated a valid secret key."), ); - let accept_points = crate::utils::get_party_base_points(secp, wallet)?; + let accept_points = crate::utils::get_party_base_points(secp, signer_provider)?; let accept_revoke_params = accept_points.get_revokable_params( secp, @@ -199,7 +209,8 @@ where Sequence(offered_channel.cet_nsequence), )?; - let own_base_secret_key = wallet.get_secret_key_for_pubkey(&accept_points.own_basepoint)?; + let own_base_secret_key = + signer_provider.get_secret_key_for_pubkey(&accept_points.own_basepoint)?; let own_secret_key = derive_private_key(secp, &first_per_update_point, &own_base_secret_key); @@ -209,14 +220,12 @@ where &offered_channel.temporary_channel_id, ); - let own_fund_sk = wallet.get_secret_key_for_pubkey(&accept_params.fund_pubkey)?; - let buffer_adaptor_signature = get_tx_adaptor_signature( secp, &buffer_transaction, dlc_transactions.get_fund_output().value, &dlc_transactions.funding_script_pubkey, - &own_fund_sk, + &signer.get_secret_key()?, &offer_revoke_params.publish_pk.inner, )?; @@ -259,16 +268,18 @@ where /// to the given [`OfferedChannel`] and [`OfferedContract`], transforming them /// to a [`SignedChannel`] and [`SignedContract`], returning them as well as the /// [`SignChannel`] to be sent to the counter party. -pub fn verify_and_sign_accepted_channel( +pub fn verify_and_sign_accepted_channel( secp: &Secp256k1, offered_channel: &OfferedChannel, offered_contract: &OfferedContract, accept_channel: &AcceptChannel, cet_nsequence: u32, - signer: &S, + wallet: &W, + signer_provider: &SP, ) -> Result<(SignedChannel, SignedContract, SignChannel), Error> where - S::Target: Signer, + W::Target: Wallet, + SP::Target: ContractSignerProvider, { let (tx_input_infos, input_amount) = crate::conversion_utils::get_tx_input_infos(&accept_channel.funding_inputs)?; @@ -291,16 +302,14 @@ where }; let offer_own_base_secret = - signer.get_secret_key_for_pubkey(&offered_channel.party_points.own_basepoint)?; + signer_provider.get_secret_key_for_pubkey(&offered_channel.party_points.own_basepoint)?; let offer_own_sk = derive_private_key( secp, &offered_channel.per_update_point, &offer_own_base_secret, ); - - let offer_fund_sk = - signer.get_secret_key_for_pubkey(&offered_contract.offer_params.fund_pubkey)?; + let offer_fund_sk = signer_provider.derive_contract_signer(offered_contract.keys_id)?; let offer_revoke_params = offered_channel.party_points.get_revokable_params( secp, @@ -353,8 +362,8 @@ where &accept_channel.refund_signature, &accept_cet_adaptor_signatures, buffer_transaction.output[0].value, + wallet, &offer_own_sk, - signer, Some(buffer_script_pubkey), Some(accept_revoke_params.own_pk.inner), &dlc_transactions, @@ -376,7 +385,7 @@ where &buffer_transaction, dlc_transactions.get_fund_output().value, &dlc_transactions.funding_script_pubkey, - &offer_fund_sk, + &offer_fund_sk.get_secret_key()?, &accept_revoke_params.publish_pk.inner, )?; @@ -395,6 +404,7 @@ where counter_buffer_adaptor_signature: accept_channel.buffer_adaptor_signature, buffer_transaction, is_offer: true, + keys_id: offered_contract.keys_id, }, update_idx: INITIAL_UPDATE_NUMBER, channel_id, @@ -429,15 +439,15 @@ where /// Verify that the given [`SignChannel`] message is valid with respect to the /// given [`AcceptedChannel`] and [`AcceptedContract`], transforming them /// to a [`SignedChannel`] and [`SignedContract`], and returning them. -pub fn verify_signed_channel( +pub fn verify_signed_channel( secp: &Secp256k1, accepted_channel: &AcceptedChannel, accepted_contract: &AcceptedContract, sign_channel: &SignChannel, - signer: &S, + wallet: &W, ) -> Result<(SignedChannel, SignedContract, Transaction), Error> where - S::Target: Signer, + W::Target: Wallet, { let own_publish_pk = accepted_channel .accept_base_points @@ -467,7 +477,7 @@ where accepted_channel.buffer_transaction.output[0].value, Some(accepted_channel.buffer_script_pubkey.clone()), Some(counter_own_pk), - signer, + wallet, Some(accepted_channel.channel_id), )?; @@ -491,6 +501,7 @@ where counter_buffer_adaptor_signature: sign_channel.buffer_adaptor_signature, buffer_transaction: accepted_channel.buffer_transaction.clone(), is_offer: false, + keys_id: signed_contract.accepted_contract.offered_contract.keys_id, }, update_idx: INITIAL_UPDATE_NUMBER, fund_tx: signed_contract @@ -517,27 +528,28 @@ where /// Creates a [`SettleOffer`] message from the given [`SignedChannel`] and parameters, /// updating the state of the channel at the same time. Expects the /// channel to be in [`SignedChannelState::Established`] state. -pub fn settle_channel_offer( +pub fn settle_channel_offer( secp: &Secp256k1, channel: &mut SignedChannel, counter_payout: u64, peer_timeout: u64, - signer: &S, + signer_provider: &SP, time: &T, ) -> Result where - S::Target: Signer, + SP::Target: ContractSignerProvider, T::Target: Time, { - if let SignedChannelState::Established { .. } = channel.state { + let keys_id = if let SignedChannelState::Established { keys_id, .. } = channel.state { + keys_id } else { return Err(Error::InvalidState( "Signed channel was not in Established state as expected.".to_string(), )); - } + }; let per_update_seed_pk = channel.own_per_update_seed; - let per_update_seed = signer.get_secret_key_for_pubkey(&per_update_seed_pk)?; + let per_update_seed = signer_provider.get_secret_key_for_pubkey(&per_update_seed_pk)?; let per_update_secret = SecretKey::from_slice(&build_commitment_secret( per_update_seed.as_ref(), @@ -551,6 +563,7 @@ where counter_payout, next_per_update_point, timeout: time.unix_time_now() + peer_timeout, + keys_id, }; std::mem::swap(&mut channel.state, &mut state); @@ -572,16 +585,18 @@ pub fn on_settle_offer( signed_channel: &mut SignedChannel, settle_offer: &SettleOffer, ) -> Result<(), Error> { - if let SignedChannelState::Established { .. } = signed_channel.state { + let keys_id = if let SignedChannelState::Established { keys_id, .. } = signed_channel.state { + keys_id } else { return Err(Error::InvalidState( "Received settle offer while not in Established state.".to_string(), )); - } + }; let mut new_state = SignedChannelState::SettledReceived { own_payout: settle_offer.counter_payout, counter_next_per_update_point: settle_offer.next_per_update_point, + keys_id, }; std::mem::swap(&mut signed_channel.state, &mut new_state); @@ -593,33 +608,35 @@ pub fn on_settle_offer( /// Creates a [`SettleAccept`] message from the given [`SignedChannel`] and other /// parameters, updating the state of the channel at the same time. Expects the /// channel to be in [`SignedChannelState::SettledReceived`] state. -pub fn settle_channel_accept( +pub fn settle_channel_accept( secp: &Secp256k1, channel: &mut SignedChannel, csv_timelock: u32, lock_time: u32, peer_timeout: u64, - signer: &S, + signer_provider: &SP, time: &T, ) -> Result where - S::Target: Signer, + SP::Target: ContractSignerProvider, T::Target: Time, { - let (own_payout, counter_next_per_update_point) = if let SignedChannelState::SettledReceived { - own_payout, - counter_next_per_update_point, - } = channel.state - { - (own_payout, counter_next_per_update_point) - } else { - return Err(Error::InvalidState( - "Signed channel was not in SettledReceived state as expected.".to_string(), - )); - }; + let (own_payout, counter_next_per_update_point, keys_id) = + if let SignedChannelState::SettledReceived { + own_payout, + counter_next_per_update_point, + keys_id, + } = channel.state + { + (own_payout, counter_next_per_update_point, keys_id) + } else { + return Err(Error::InvalidState( + "Signed channel was not in SettledReceived state as expected.".to_string(), + )); + }; let per_update_seed_pk = channel.own_per_update_seed; - let per_update_seed = signer.get_secret_key_for_pubkey(&per_update_seed_pk)?; + let per_update_seed = signer_provider.get_secret_key_for_pubkey(&per_update_seed_pk)?; let per_update_secret = SecretKey::from_slice(&build_commitment_secret( per_update_seed.as_ref(), channel.update_idx - 1, @@ -638,7 +655,7 @@ where let fund_vout = channel.fund_output_index; let funding_script_pubkey = &channel.fund_script_pubkey; - let own_fund_sk = signer.get_secret_key_for_pubkey(&channel.own_params.fund_pubkey)?; + let contract_signer = signer_provider.derive_contract_signer(keys_id)?; let (settle_tx, settle_adaptor_signature) = get_settle_tx_and_adaptor_sig( secp, @@ -646,7 +663,7 @@ where fund_tx, fund_vout, funding_script_pubkey, - &own_fund_sk, + &contract_signer.get_secret_key()?, &channel.counter_points, &channel.own_points, &counter_next_per_update_point, @@ -665,6 +682,7 @@ where own_settle_adaptor_signature: settle_adaptor_signature, timeout: time.unix_time_now() + peer_timeout, own_payout, + keys_id, }; let msg = SettleAccept { @@ -680,26 +698,27 @@ where /// [`SettleAccept`] message, verifying the content of the message and updating /// the state of the channel at the same time. Expects the channel to be in /// [`SignedChannelState::SettledOffered`] state. -pub fn settle_channel_confirm( +pub fn settle_channel_confirm( secp: &Secp256k1, channel: &mut SignedChannel, settle_channel_accept: &SettleAccept, csv_timelock: u32, lock_time: u32, peer_timeout: u64, - signer: &S, + signer_provider: &SP, time: &T, ) -> Result where + SP::Target: ContractSignerProvider, T::Target: Time, - S::Target: Signer, { - let (counter_payout, next_per_update_point) = match channel.state { + let (counter_payout, next_per_update_point, keys_id) = match channel.state { SignedChannelState::SettledOffered { counter_payout, next_per_update_point, + keys_id, .. - } => (counter_payout, next_per_update_point), + } => (counter_payout, next_per_update_point, keys_id), _ => { return Err(Error::InvalidState( "Signed channel was not in SettledOffered state as expected.".to_string(), @@ -717,7 +736,7 @@ where let fund_vout = channel.fund_output_index; let funding_script_pubkey = &channel.fund_script_pubkey; - let own_fund_sk = signer.get_secret_key_for_pubkey(&channel.own_params.fund_pubkey)?; + let contract_signer = signer_provider.derive_contract_signer(keys_id)?; let (settle_tx, settle_adaptor_signature) = get_settle_tx_and_adaptor_sig( secp, @@ -725,7 +744,7 @@ where fund_tx, fund_vout, funding_script_pubkey, - &own_fund_sk, + &contract_signer.get_secret_key()?, &channel.own_points, &channel.counter_points, &settle_channel_accept.next_per_update_point, @@ -741,7 +760,7 @@ where )?; let per_update_seed_pk = channel.own_per_update_seed; - let per_update_seed = signer.get_secret_key_for_pubkey(&per_update_seed_pk)?; + let per_update_seed = signer_provider.get_secret_key_for_pubkey(&per_update_seed_pk)?; let prev_per_update_secret = SecretKey::from_slice(&build_commitment_secret( per_update_seed.as_ref(), @@ -756,6 +775,7 @@ where own_settle_adaptor_signature: settle_adaptor_signature, timeout: time.unix_time_now() + peer_timeout, own_payout: total_collateral - counter_payout, + keys_id, }; channel.state = state; @@ -773,32 +793,35 @@ where /// [`SettleConfirm`] message, validating the message and updating the state of /// the channel at the same time. Expects the channel to be in /// [`SignedChannelState::SettledAccepted`] state. -pub fn settle_channel_finalize( +pub fn settle_channel_finalize( secp: &Secp256k1, channel: &mut SignedChannel, settle_channel_confirm: &SettleConfirm, - signer: &S, + signer_provider: &SP, ) -> Result where - S::Target: Signer, + SP::Target: ContractSignerProvider, { let ( own_next_per_update_point, counter_next_per_update_point, settle_tx, own_settle_adaptor_signature, + keys_id, ) = match &channel.state { SignedChannelState::SettledAccepted { counter_next_per_update_point, own_next_per_update_point, settle_tx, own_settle_adaptor_signature, + keys_id, .. } => ( own_next_per_update_point, counter_next_per_update_point, settle_tx, own_settle_adaptor_signature, + *keys_id, ), _ => { return Err(Error::InvalidState( @@ -808,7 +831,7 @@ where }; let per_update_seed_pk = channel.own_per_update_seed; - let per_update_seed = signer.get_secret_key_for_pubkey(&per_update_seed_pk)?; + let per_update_seed = signer_provider.get_secret_key_for_pubkey(&per_update_seed_pk)?; let accept_revoke_params = channel.own_points.get_revokable_params( secp, @@ -853,6 +876,7 @@ where settle_tx: settle_tx.clone(), counter_settle_adaptor_signature: settle_channel_confirm.settle_adaptor_signature, own_settle_adaptor_signature: *own_settle_adaptor_signature, + keys_id, }; channel.own_per_update_point = *own_next_per_update_point; @@ -884,6 +908,7 @@ pub fn settle_channel_on_finalize( counter_next_per_update_point, own_next_per_update_point, own_settle_adaptor_signature, + keys_id, ) = match &channel.state { SignedChannelState::SettledConfirmed { settle_tx, @@ -891,6 +916,7 @@ pub fn settle_channel_on_finalize( counter_next_per_update_point, own_next_per_update_point, own_settle_adaptor_signature, + keys_id, .. } => ( settle_tx.clone(), @@ -898,6 +924,7 @@ pub fn settle_channel_on_finalize( *counter_next_per_update_point, *own_next_per_update_point, *own_settle_adaptor_signature, + *keys_id, ), _ => { return Err(Error::InvalidState( @@ -928,6 +955,7 @@ pub fn settle_channel_on_finalize( settle_tx, counter_settle_adaptor_signature, own_settle_adaptor_signature, + keys_id, }; channel.roll_back_state = None; @@ -955,7 +983,7 @@ pub fn reject_settle_offer(signed_channel: &mut SignedChannel) -> Result( +pub fn renew_offer( secp: &Secp256k1, signed_channel: &mut SignedChannel, contract_input: &ContractInput, @@ -964,14 +992,19 @@ pub fn renew_offer( refund_delay: u32, peer_timeout: u64, cet_nsequence: u32, - signer: &S, + signer_provider: &SP, time: &T, ) -> Result<(RenewOffer, OfferedContract), Error> where - S::Target: Signer, + SP::Target: ContractSignerProvider, T::Target: Time, { + let id = get_new_temporary_id(); + let keys_id = signed_channel + .keys_id() + .ok_or(Error::InvalidState("No keys_id available".to_string()))?; let mut offered_contract = OfferedContract::new( + id, contract_input, oracle_announcements, &signed_channel.own_params, @@ -979,13 +1012,15 @@ where &signed_channel.counter_party, refund_delay, time.unix_time_now() as u32, + keys_id, ); offered_contract.fund_output_serial_id = 0; offered_contract.fee_rate_per_vb = signed_channel.fee_rate_per_vb; - let per_update_seed = signer.get_secret_key_for_pubkey(&signed_channel.own_per_update_seed)?; + let per_update_seed = + signer_provider.get_secret_key_for_pubkey(&signed_channel.own_per_update_seed)?; let per_update_secret = SecretKey::from_slice(&build_commitment_secret( per_update_seed.as_ref(), @@ -1001,6 +1036,7 @@ where is_offer: true, counter_payout, timeout: time.unix_time_now() + peer_timeout, + keys_id, }; std::mem::swap(&mut signed_channel.state, &mut state); @@ -1029,17 +1065,18 @@ pub fn on_renew_offer( peer_timeout: u64, time: &T, ) -> Result - where - T::Target: Time, +where + T::Target: Time, { - if let SignedChannelState::Settled { .. } | SignedChannelState::Established { .. } = - signed_channel.state + let keys_id = if let SignedChannelState::Settled { keys_id, .. } + | SignedChannelState::Established { keys_id, .. } = signed_channel.state { + keys_id } else { return Err(Error::InvalidState( "Received renew offer while not in Settled or Established states.".to_string(), )); - } + }; let offered_contract = OfferedContract { id: renew_offer.temporary_contract_id, @@ -1056,6 +1093,7 @@ pub fn on_renew_offer( fee_rate_per_vb: signed_channel.fee_rate_per_vb, cet_locktime: renew_offer.cet_locktime, refund_locktime: renew_offer.refund_locktime, + keys_id, }; let mut state = SignedChannelState::RenewOffered { @@ -1064,6 +1102,7 @@ pub fn on_renew_offer( offer_next_per_update_point: renew_offer.next_per_update_point, is_offer: false, timeout: time.unix_time_now() + peer_timeout, + keys_id, }; std::mem::swap(&mut signed_channel.state, &mut state); @@ -1077,25 +1116,26 @@ pub fn on_renew_offer( /// parameters, updating the state of the channel and the associated contract the /// same time. Expects the channel to be in [`SignedChannelState::RenewOffered`] /// state. -pub fn accept_channel_renewal( +pub fn accept_channel_renewal( secp: &Secp256k1, signed_channel: &mut SignedChannel, offered_contract: &OfferedContract, cet_nsequence: u32, peer_timeout: u64, - signer: &S, + signer_provider: &SP, time: &T, ) -> Result<(AcceptedContract, RenewAccept), Error> where - S::Target: Signer, + SP::Target: ContractSignerProvider, T::Target: Time, { - let (offer_next_per_update_point, own_payout) = match signed_channel.state { + let (offer_next_per_update_point, own_payout, keys_id) = match signed_channel.state { SignedChannelState::RenewOffered { offer_next_per_update_point, counter_payout, + keys_id, .. - } => (offer_next_per_update_point, counter_payout), + } => (offer_next_per_update_point, counter_payout, keys_id), _ => { return Err(Error::InvalidState( "Signed channel was not in SettledOffered state as expected.".to_string(), @@ -1103,10 +1143,12 @@ where } }; - let own_fund_sk = signer.get_secret_key_for_pubkey(&signed_channel.own_params.fund_pubkey)?; + let contract_signer = signer_provider.derive_contract_signer(keys_id)?; + let own_base_secret_key = - signer.get_secret_key_for_pubkey(&signed_channel.own_points.own_basepoint)?; - let per_update_seed = signer.get_secret_key_for_pubkey(&signed_channel.own_per_update_seed)?; + signer_provider.get_secret_key_for_pubkey(&signed_channel.own_points.own_basepoint)?; + let per_update_seed = + signer_provider.get_secret_key_for_pubkey(&signed_channel.own_per_update_seed)?; let total_collateral = offered_contract.total_collateral; @@ -1152,7 +1194,7 @@ where &buffer_transaction, dlc_transactions.get_fund_output().value, &dlc_transactions.funding_script_pubkey, - &own_fund_sk, + &contract_signer.get_secret_key()?, &offer_revoke_params.publish_pk.inner, )?; @@ -1178,6 +1220,7 @@ where accept_buffer_adaptor_signature: buffer_adaptor_signature, timeout: time.unix_time_now() + peer_timeout, own_payout, + keys_id, }; signed_channel.state = state; @@ -1197,34 +1240,41 @@ where /// [`RenewAccept`] message, verifying the message and updating the state of the /// channel and associated contract the same time. Expects the channel to be in /// [`SignedChannelState::RenewOffered`] state. -pub fn verify_renew_accept_and_confirm( +pub fn verify_renew_accept_and_confirm( secp: &Secp256k1, renew_accept: &RenewAccept, signed_channel: &mut SignedChannel, offered_contract: &OfferedContract, cet_nsequence: u32, peer_timeout: u64, - signer: &S, + wallet: &W, + signer_provider: &SP, time: &T, ) -> Result<(SignedContract, RenewConfirm), Error> where - S::Target: Signer, + W::Target: Wallet, + SP::Target: ContractSignerProvider, T::Target: Time, { - let own_fund_sk = signer.get_secret_key_for_pubkey(&signed_channel.own_params.fund_pubkey)?; - let own_base_secret_key = - signer.get_secret_key_for_pubkey(&signed_channel.own_points.own_basepoint)?; + signer_provider.get_secret_key_for_pubkey(&signed_channel.own_points.own_basepoint)?; - let per_update_seed = signer.get_secret_key_for_pubkey(&signed_channel.own_per_update_seed)?; + let per_update_seed = + signer_provider.get_secret_key_for_pubkey(&signed_channel.own_per_update_seed)?; let prev_per_update_secret = SecretKey::from_slice(&build_commitment_secret( per_update_seed.as_ref(), signed_channel.update_idx, ))?; - let offer_per_update_point = - get_signed_channel_state!(signed_channel, RenewOffered, offer_next_per_update_point)?; + let (offer_per_update_point, keys_id) = get_signed_channel_state!( + signed_channel, + RenewOffered, + offer_next_per_update_point, + keys_id + )?; + + let contract_signer = signer_provider.derive_contract_signer(keys_id)?; let offer_revoke_params = signed_channel.own_points.get_revokable_params( secp, @@ -1271,8 +1321,8 @@ where &renew_accept.refund_signature, &cet_adaptor_signatures, buffer_transaction.output[0].value, + wallet, &offer_own_sk, - signer, Some(buffer_script_pubkey.clone()), Some(accept_revoke_params.own_pk.inner), &dlc_transactions, @@ -1294,7 +1344,7 @@ where &buffer_transaction, dlc_transactions.get_fund_output().value, &dlc_transactions.funding_script_pubkey, - &own_fund_sk, + &contract_signer.get_secret_key()?, &accept_revoke_params.publish_pk.inner, )?; @@ -1308,6 +1358,7 @@ where accept_buffer_adaptor_signature: renew_accept.buffer_adaptor_signature, timeout: time.unix_time_now() + peer_timeout, own_payout, + keys_id, }; signed_channel.state = state; @@ -1327,15 +1378,17 @@ where /// [`RenewAccept`] message, verifying the message and updating the state of the /// channel and associated contract the same time. Expects the channel to be in /// [`SignedChannelState::RenewAccepted`] state. -pub fn verify_renew_confirm_and_finalize( +pub fn verify_renew_confirm_and_finalize( secp: &Secp256k1, signed_channel: &mut SignedChannel, accepted_contract: &AcceptedContract, renew_confirm: &RenewConfirm, - signer: &S, + wallet: &W, + signer_provider: &SP, ) -> Result<(SignedContract, RenewFinalize), Error> where - S::Target: Signer, + W::Target: Wallet, + SP::Target: ContractSignerProvider, { let ( offer_per_update_point, @@ -1343,13 +1396,15 @@ where accept_buffer_adaptor_signature, buffer_transaction, buffer_script_pubkey, + keys_id, ) = get_signed_channel_state!( signed_channel, RenewAccepted, offer_per_update_point, accept_per_update_point, accept_buffer_adaptor_signature | buffer_transaction, - buffer_script_pubkey + buffer_script_pubkey, + keys_id )?; let own_publish_pk = signed_channel @@ -1381,7 +1436,7 @@ where buffer_transaction.output[0].value, Some(buffer_script_pubkey.clone()), Some(counter_own_pk), - signer, + wallet, Some(signed_channel.channel_id), )?; @@ -1391,6 +1446,7 @@ where counter_buffer_adaptor_signature: renew_confirm.buffer_adaptor_signature, buffer_transaction: buffer_transaction.clone(), is_offer: false, + keys_id: *keys_id, }; signed_channel.update_idx -= 1; @@ -1406,7 +1462,8 @@ where signed_channel.counter_per_update_point = offer_per_update_point; signed_channel.own_per_update_point = accept_per_update_point; - let per_update_seed = signer.get_secret_key_for_pubkey(&signed_channel.own_per_update_seed)?; + let per_update_seed = + signer_provider.get_secret_key_for_pubkey(&signed_channel.own_per_update_seed)?; let prev_per_update_secret = SecretKey::from_slice(&build_commitment_secret( per_update_seed.as_ref(), @@ -1433,6 +1490,7 @@ pub fn renew_channel_on_finalize( offer_buffer_adaptor_signature, accept_buffer_adaptor_signature, buffer_transaction, + keys_id, ) = get_signed_channel_state!( signed_channel, RenewConfirmed, @@ -1440,7 +1498,8 @@ pub fn renew_channel_on_finalize( offer_per_update_point, accept_per_update_point, offer_buffer_adaptor_signature, - accept_buffer_adaptor_signature | buffer_transaction + accept_buffer_adaptor_signature | buffer_transaction, + keys_id )?; let state = SignedChannelState::Established { @@ -1449,6 +1508,7 @@ pub fn renew_channel_on_finalize( own_buffer_adaptor_signature: offer_buffer_adaptor_signature, buffer_transaction: buffer_transaction.clone(), is_offer: true, + keys_id: *keys_id, }; signed_channel @@ -1493,15 +1553,15 @@ pub fn reject_renew_offer(signed_channel: &mut SignedChannel) -> Result( +pub fn offer_collaborative_close( secp: &Secp256k1, signed_channel: &mut SignedChannel, counter_payout: u64, - signer: &S, + signer_provider: &SP, time: &T, ) -> Result<(CollaborativeCloseOffer, Transaction), Error> where - S::Target: Signer, + SP::Target: ContractSignerProvider, T::Target: Time, { if counter_payout @@ -1529,7 +1589,10 @@ where fund_output_value, ); - let own_fund_sk = signer.get_secret_key_for_pubkey(&signed_channel.own_params.fund_pubkey)?; + let keys_id = signed_channel + .keys_id() + .ok_or(Error::InvalidState("No keys_id available".to_string()))?; + let contract_signer = signer_provider.derive_contract_signer(keys_id)?; let close_signature = dlc::util::get_raw_sig_for_tx_input( secp, @@ -1537,7 +1600,7 @@ where 0, &signed_channel.fund_script_pubkey, fund_output_value, - &own_fund_sk, + &contract_signer.get_secret_key()?, )?; let mut state = SignedChannelState::CollaborativeCloseOffered { @@ -1545,6 +1608,9 @@ where offer_signature: close_signature, close_tx: close_tx.clone(), timeout: time.unix_time_now() + super::manager::PEER_TIMEOUT, + keys_id: signed_channel + .keys_id() + .ok_or(Error::InvalidState("No keys_id available".to_string()))?, }; std::mem::swap(&mut state, &mut signed_channel.state); signed_channel.roll_back_state = Some(state); @@ -1603,6 +1669,9 @@ where offer_signature: close_offer.close_signature, close_tx, timeout: time.unix_time_now() + peer_timeout, + keys_id: signed_channel + .keys_id() + .ok_or(Error::InvalidState("No keys_id available".to_string()))?, }; std::mem::swap(&mut state, &mut signed_channel.state); @@ -1613,23 +1682,24 @@ where /// Accept an offer to collaboratively close the channel, signing the /// closing transaction and returning it. -pub fn accept_collaborative_close_offer( +pub fn accept_collaborative_close_offer( secp: &Secp256k1, signed_channel: &mut SignedChannel, - signer: &S, + signer_provider: &SP, ) -> Result where - S::Target: Signer, + SP::Target: ContractSignerProvider, { - let (offer_signature, close_tx) = get_signed_channel_state!( + let (offer_signature, close_tx, keys_id) = get_signed_channel_state!( signed_channel, CollaborativeCloseOffered, - offer_signature | close_tx + offer_signature | close_tx, + keys_id )?; let fund_out_amount = signed_channel.fund_tx.output[signed_channel.fund_output_index].value; - let own_fund_sk = signer.get_secret_key_for_pubkey(&signed_channel.own_params.fund_pubkey)?; + let contract_signer = signer_provider.derive_contract_signer(*keys_id)?; let mut close_tx = close_tx.clone(); @@ -1638,7 +1708,7 @@ where &mut close_tx, &offer_signature, &signed_channel.counter_params.fund_pubkey, - &own_fund_sk, + &contract_signer.get_secret_key()?, &signed_channel.fund_script_pubkey, fund_out_amount, 0, @@ -1769,28 +1839,29 @@ pub fn on_reject(signed_channel: &mut SignedChannel) -> Result<(), Error> { } /// Sign the buffer transaction and closing CET and update the state of the channel. -pub fn initiate_unilateral_close_established_channel( +pub fn initiate_unilateral_close_established_channel( secp: &Secp256k1, signed_channel: &mut SignedChannel, confirmed_contract: &SignedContract, contract_info: &ContractInfo, attestations: &[(usize, OracleAttestation)], adaptor_info: &AdaptorInfo, - signer: &S, + signer_provider: &SP, ) -> Result<(), Error> where - S::Target: Signer, + SP::Target: ContractSignerProvider, { - let (buffer_adaptor_signature, buffer_transaction) = get_signed_channel_state!( + let (buffer_adaptor_signature, buffer_transaction, keys_id) = get_signed_channel_state!( signed_channel, Established, - counter_buffer_adaptor_signature | buffer_transaction + counter_buffer_adaptor_signature | buffer_transaction, + keys_id )?; let mut buffer_transaction = buffer_transaction.clone(); let publish_base_secret = - signer.get_secret_key_for_pubkey(&signed_channel.own_points.publish_basepoint)?; + signer_provider.get_secret_key_for_pubkey(&signed_channel.own_points.publish_basepoint)?; let publish_sk = derive_private_key( secp, @@ -1800,14 +1871,14 @@ where let counter_buffer_signature = buffer_adaptor_signature.decrypt(&publish_sk)?; - let fund_sk = signer.get_secret_key_for_pubkey(&signed_channel.own_params.fund_pubkey)?; + let fund_sk = signer_provider.derive_contract_signer(*keys_id)?; dlc::util::sign_multi_sig_input( secp, &mut buffer_transaction, &counter_buffer_signature, &signed_channel.counter_params.fund_pubkey, - &fund_sk, + &fund_sk.get_secret_key()?, &signed_channel.fund_script_pubkey, signed_channel.fund_tx.output[signed_channel.fund_output_index].value, 0, @@ -1876,7 +1947,7 @@ where ) }; - let base_secret = signer.get_secret_key_for_pubkey(own_basepoint)?; + let base_secret = signer_provider.get_secret_key_for_pubkey(own_basepoint)?; let own_sk = derive_private_key(secp, own_per_update_point, &base_secret); dlc::channel::sign_cet( @@ -1896,30 +1967,32 @@ where signed_cet: cet, contract_id: confirmed_contract.accepted_contract.get_contract_id(), attestations: attestations.iter().map(|x| x.1.clone()).collect(), + keys_id: *keys_id, }; Ok(()) } /// Sign the settlement transaction and update the state of the channel. -pub fn close_settled_channel( +pub fn close_settled_channel( secp: &Secp256k1, signed_channel: &mut SignedChannel, - signer: &S, + signer_provider: &SP, ) -> Result where - S::Target: Signer, + SP::Target: ContractSignerProvider, { - let (counter_settle_adaptor_signature, settle_tx) = get_signed_channel_state!( + let (counter_settle_adaptor_signature, settle_tx, keys_id) = get_signed_channel_state!( signed_channel, Settled, - counter_settle_adaptor_signature | settle_tx + counter_settle_adaptor_signature | settle_tx, + keys_id )?; let mut settle_tx = settle_tx.clone(); let publish_base_secret = - signer.get_secret_key_for_pubkey(&signed_channel.own_points.publish_basepoint)?; + signer_provider.get_secret_key_for_pubkey(&signed_channel.own_points.publish_basepoint)?; let publish_sk = derive_private_key( secp, @@ -1929,14 +2002,14 @@ where let counter_settle_signature = counter_settle_adaptor_signature.decrypt(&publish_sk)?; - let fund_sk = signer.get_secret_key_for_pubkey(&signed_channel.own_params.fund_pubkey)?; + let fund_sk = signer_provider.derive_contract_signer(*keys_id)?; dlc::util::sign_multi_sig_input( secp, &mut settle_tx, &counter_settle_signature, &signed_channel.counter_params.fund_pubkey, - &fund_sk, + &fund_sk.get_secret_key()?, &signed_channel.fund_script_pubkey, signed_channel.fund_tx.output[signed_channel.fund_output_index].value, 0, diff --git a/dlc-manager/src/contract/accepted_contract.rs b/dlc-manager/src/contract/accepted_contract.rs index 1f93b17b..302f3208 100644 --- a/dlc-manager/src/contract/accepted_contract.rs +++ b/dlc-manager/src/contract/accepted_contract.rs @@ -109,13 +109,13 @@ mod tests { #[test] fn pnl_compute_test() { - let buf = include_bytes!("../../test_inputs/Accepted"); + let buf = include_bytes!("../../../dlc-sled-storage-provider/test_files/Accepted"); let accepted_contract: AcceptedContract = Readable::read(&mut Cursor::new(&buf)).unwrap(); let cets = &accepted_contract.dlc_transactions.cets; - assert_eq!(accepted_contract.compute_pnl(&cets[0]), 100000000); + assert_eq!(accepted_contract.compute_pnl(&cets[0]), 90000000); assert_eq!( accepted_contract.compute_pnl(&cets[cets.len() - 1]), - -100000000 + -11000000 ); } } diff --git a/dlc-manager/src/contract/contract_info.rs b/dlc-manager/src/contract/contract_info.rs index 5d11e0e7..bda783a0 100644 --- a/dlc-manager/src/contract/contract_info.rs +++ b/dlc-manager/src/contract/contract_info.rs @@ -3,6 +3,7 @@ use super::AdaptorInfo; use super::ContractDescriptor; use crate::error::Error; +use crate::ContractSigner; use bitcoin::{Script, Transaction}; use dlc::{OracleInfo, Payout}; use dlc_messages::oracle_msgs::{EventDescriptor, OracleAnnouncement}; @@ -11,6 +12,7 @@ use secp256k1_zkp::{ hashes::sha256, All, EcdsaAdaptorSignature, Message, PublicKey, Secp256k1, SecretKey, Verification, }; +use std::ops::Deref; pub(super) type OracleIndexAndPrefixLength = Vec<(usize, usize)>; @@ -61,15 +63,19 @@ impl ContractInfo { /// Uses the provided AdaptorInfo and SecretKey to generate the set of /// adaptor signatures for the contract. - pub fn get_adaptor_signatures( + pub fn get_adaptor_signatures( &self, secp: &Secp256k1, adaptor_info: &AdaptorInfo, - fund_privkey: &SecretKey, + signer: &S, funding_script_pubkey: &Script, fund_output_value: u64, cets: &[Transaction], - ) -> Result, Error> { + ) -> Result, Error> + where + S::Target: ContractSigner, + { + let fund_privkey = signer.get_secret_key()?; match adaptor_info { AdaptorInfo::Enum => match &self.contract_descriptor { ContractDescriptor::Enum(e) => e.get_adaptor_signatures( @@ -77,7 +83,7 @@ impl ContractInfo { &self.get_oracle_infos(), self.threshold, cets, - fund_privkey, + &fund_privkey, funding_script_pubkey, fund_output_value, ), @@ -85,7 +91,7 @@ impl ContractInfo { }, AdaptorInfo::Numerical(trie) => Ok(trie.sign( secp, - fund_privkey, + &fund_privkey, funding_script_pubkey, fund_output_value, cets, @@ -93,7 +99,7 @@ impl ContractInfo { )?), AdaptorInfo::NumericalWithDifference(trie) => Ok(trie.sign( secp, - fund_privkey, + &fund_privkey, funding_script_pubkey, fund_output_value, cets, diff --git a/dlc-manager/src/contract/offered_contract.rs b/dlc-manager/src/contract/offered_contract.rs index aa793b65..b81ab39f 100644 --- a/dlc-manager/src/contract/offered_contract.rs +++ b/dlc-manager/src/contract/offered_contract.rs @@ -8,6 +8,7 @@ use crate::utils::get_new_serial_id; use super::contract_info::ContractInfo; use super::contract_input::ContractInput; use super::{ContractDescriptor, FundingInputInfo}; +use crate::KeysId; use dlc::PartyParams; use dlc_messages::oracle_msgs::OracleAnnouncement; use dlc_messages::OfferDlc; @@ -44,6 +45,8 @@ pub struct OfferedContract { pub cet_locktime: u32, /// The time at which the contract becomes refundable. pub refund_locktime: u32, + /// Keys Id for generating the signers + pub(crate) keys_id: KeysId, } impl OfferedContract { @@ -75,6 +78,7 @@ impl OfferedContract { /// Creates a new [`OfferedContract`] from the given parameters. pub fn new( + id: [u8; 32], contract: &ContractInput, oracle_announcements: Vec>, offer_params: &PartyParams, @@ -82,6 +86,7 @@ impl OfferedContract { counter_party: &PublicKey, refund_delay: u32, cet_locktime: u32, + keys_id: KeysId, ) -> Self { let total_collateral = contract.offer_collateral + contract.accept_collateral; @@ -102,7 +107,7 @@ impl OfferedContract { }) .collect::>(); OfferedContract { - id: crate::utils::get_new_temporary_id(), + id, is_offer_party: true, contract_info, offer_params: offer_params.clone(), @@ -113,6 +118,7 @@ impl OfferedContract { cet_locktime, refund_locktime: latest_maturity + refund_delay, counter_party: *counter_party, + keys_id, } } @@ -120,6 +126,7 @@ impl OfferedContract { pub fn try_from_offer_dlc( offer_dlc: &OfferDlc, counter_party: PublicKey, + keys_id: KeysId, ) -> Result { let contract_info = get_contract_info_and_announcements(&offer_dlc.contract_info)?; @@ -146,6 +153,7 @@ impl OfferedContract { funding_inputs_info: offer_dlc.funding_inputs.iter().map(|x| x.into()).collect(), total_collateral: offer_dlc.contract_info.get_total_collateral(), counter_party, + keys_id, }) } } diff --git a/dlc-manager/src/contract/ser.rs b/dlc-manager/src/contract/ser.rs index 1b77de59..e22ff19c 100644 --- a/dlc-manager/src/contract/ser.rs +++ b/dlc-manager/src/contract/ser.rs @@ -99,7 +99,8 @@ impl_dlc_writeable!(OfferedContract, { (fee_rate_per_vb, writeable), (cet_locktime, writeable), (refund_locktime, writeable), - (counter_party, writeable) + (counter_party, writeable), + (keys_id, writeable) }); impl_dlc_writeable_external!(RangeInfo, range_info, { (cet_index, usize), (adaptor_index, usize)}); impl_dlc_writeable_enum!(AdaptorInfo,;; (0, Numerical, write_multi_oracle_trie, read_multi_oracle_trie), (1, NumericalWithDifference, write_multi_oracle_trie_with_diff, read_multi_oracle_trie_with_diff); (2, Enum)); diff --git a/dlc-manager/src/contract_updater.rs b/dlc-manager/src/contract_updater.rs index 4cf9fd03..94150d1a 100644 --- a/dlc-manager/src/contract_updater.rs +++ b/dlc-manager/src/contract_updater.rs @@ -21,13 +21,12 @@ use crate::{ }, conversion_utils::get_tx_input_infos, error::Error, - Blockchain, ChannelId, Signer, Time, Wallet, + Blockchain, ChannelId, ContractSigner, ContractSignerProvider, Time, Wallet, }; /// Creates an [`OfferedContract`] and [`OfferDlc`] message from the provided /// contract and oracle information. -pub fn offer_contract( - secp: &Secp256k1, +pub fn offer_contract( contract_input: &ContractInput, oracle_announcements: Vec>, refund_delay: u32, @@ -35,23 +34,29 @@ pub fn offer_contract( wallet: &W, blockchain: &B, time: &T, + signer_provider: &SP, ) -> Result<(OfferedContract, OfferDlc), Error> where W::Target: Wallet, B::Target: Blockchain, T::Target: Time, + SP::Target: ContractSignerProvider, { contract_input.validate()?; - let (party_params, _, funding_inputs_info) = crate::utils::get_party_params( - secp, + let id = crate::utils::get_new_temporary_id(); + let keys_id = signer_provider.derive_signer_key_id(true, id); + let signer = signer_provider.derive_contract_signer(keys_id)?; + let (party_params, funding_inputs_info) = crate::utils::get_party_params( contract_input.offer_collateral, contract_input.fee_rate, wallet, + &signer, blockchain, )?; let offered_contract = OfferedContract::new( + id, contract_input, oracle_announcements, &party_params, @@ -59,6 +64,7 @@ where counter_party, refund_delay, time.unix_time_now() as u32, + keys_id, ); let offer_msg: OfferDlc = (&offered_contract).into(); @@ -68,23 +74,26 @@ where /// Creates an [`AcceptedContract`] and produces /// the accepting party's cet adaptor signatures. -pub fn accept_contract( +pub fn accept_contract( secp: &Secp256k1, offered_contract: &OfferedContract, wallet: &W, + signer_provider: &SP, blockchain: &B, -) -> Result<(AcceptedContract, AcceptDlc), crate::Error> +) -> Result<(AcceptedContract, AcceptDlc), Error> where W::Target: Wallet, B::Target: Blockchain, + SP::Target: ContractSignerProvider, { let total_collateral = offered_contract.total_collateral; - let (accept_params, fund_secret_key, funding_inputs) = crate::utils::get_party_params( - secp, + let signer = signer_provider.derive_contract_signer(offered_contract.keys_id)?; + let (accept_params, funding_inputs) = crate::utils::get_party_params( total_collateral - offered_contract.offer_params.collateral, offered_contract.fee_rate_per_vb, wallet, + &signer, blockchain, )?; @@ -106,7 +115,7 @@ where offered_contract, &accept_params, &funding_inputs, - &fund_secret_key, + &signer.get_secret_key()?, fund_output_value, None, &dlc_transactions, @@ -216,14 +225,16 @@ pub(crate) fn accept_contract_internal( /// Verifies the information of the accepting party [`Accept` message](dlc_messages::AcceptDlc), /// creates a [`SignedContract`], and generates the offering party CET adaptor signatures. -pub fn verify_accepted_and_sign_contract( +pub fn verify_accepted_and_sign_contract( secp: &Secp256k1, offered_contract: &OfferedContract, accept_msg: &AcceptDlc, - signer: &S, + wallet: &W, + signer_provider: &SP, ) -> Result<(SignedContract, SignDlc), Error> where - S::Target: Signer, + W::Target: Wallet, + SP::Target: ContractSignerProvider, { let (tx_input_infos, input_amount) = get_tx_input_infos(&accept_msg.funding_inputs)?; @@ -258,8 +269,8 @@ where offered_contract.fund_output_serial_id, )?; let fund_output_value = dlc_transactions.get_fund_output().value; - let fund_privkey = - signer.get_secret_key_for_pubkey(&offered_contract.offer_params.fund_pubkey)?; + + let signer = signer_provider.derive_contract_signer(offered_contract.keys_id)?; let (signed_contract, adaptor_sigs) = verify_accepted_and_sign_contract_internal( secp, offered_contract, @@ -272,8 +283,8 @@ where &accept_msg.refund_signature, &cet_adaptor_signatures, fund_output_value, - &fund_privkey, - signer, + wallet, + &signer, None, None, &dlc_transactions, @@ -310,7 +321,7 @@ fn populate_psbt( Ok(()) } -pub(crate) fn verify_accepted_and_sign_contract_internal( +pub(crate) fn verify_accepted_and_sign_contract_internal( secp: &Secp256k1, offered_contract: &OfferedContract, accept_params: &PartyParams, @@ -318,15 +329,15 @@ pub(crate) fn verify_accepted_and_sign_contract_internal( refund_signature: &Signature, cet_adaptor_signatures: &[EcdsaAdaptorSignature], input_value: u64, - adaptor_secret: &SecretKey, - signer: &S, + wallet: &W, + signer: &X, input_script_pubkey: Option