Skip to content

Commit

Permalink
Create ContractSignerProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
benthecarman committed Feb 1, 2024
1 parent a6b5e4e commit fefdc2f
Show file tree
Hide file tree
Showing 43 changed files with 1,237 additions and 434 deletions.
220 changes: 154 additions & 66 deletions bitcoin-rpc-provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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;
Expand Down Expand Up @@ -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<ConfirmationTarget, AtomicU32> = HashMap::new();
let mut fees: HashMap<ConfirmationTarget, AtomicU32> = HashMap::with_capacity(7);
fees.insert(ConfirmationTarget::OnChainSweep, AtomicU32::new(5000));
fees.insert(
ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee,
Expand Down Expand Up @@ -168,7 +172,61 @@ 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<Self::Signer, ManagerError> {
let label_map = self
.client
.lock()
.unwrap()
.call::<HashMap<Address, Value>>(
"getaddressesbylabel",
&[Value::String(keys_id.to_hex())],
)
.map_err(rpc_err_to_manager_err)?;

// we should only have one address per keys_id
// if not something has gone wrong
assert_eq!(label_map.len(), 1);

if let Some(address) = label_map.into_keys().next() {
let pk = self
.client
.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(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<SecretKey, ManagerError> {
let b_pubkey = bitcoin::PublicKey {
compressed: true,
Expand All @@ -182,60 +240,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<SecretKey, ManagerError> {
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)
}
}

Expand All @@ -249,27 +279,14 @@ impl Wallet for BitcoinCoreProvider {
}

fn get_new_change_address(&self) -> Result<Address, ManagerError> {
self.get_new_address()
}

fn get_new_secret_key(&self) -> Result<SecretKey, ManagerError> {
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(
Expand Down Expand Up @@ -321,6 +338,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 {
Expand Down Expand Up @@ -479,3 +548,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<T>(val: T) -> bitcoincore_rpc::Result<Value>
where
T: serde::ser::Serialize,
{
Ok(serde_json::to_value(val)?)
}

/// Shorthand for converting an Option into an Option<serde_json::Value>.
fn opt_into_json<T>(opt: Option<T>) -> Result<Value, ManagerError>
where
T: serde::ser::Serialize,
{
match opt {
Some(val) => Ok(into_json(val).map_err(rpc_err_to_manager_err)?),
None => Ok(Value::Null),
}
}
4 changes: 3 additions & 1 deletion dlc-manager/src/channel/offered_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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))
Expand Down
22 changes: 11 additions & 11 deletions dlc-manager/src/channel/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
);

Expand Down
Loading

0 comments on commit fefdc2f

Please sign in to comment.