Skip to content

Commit

Permalink
WalletSwapCoin: Split into two classes + add trait
Browse files Browse the repository at this point in the history
Convert WalletSwapCoin into Incoming/OutgoingSwapCoin, and add a
WalletSwapCoin trait for common functionality
  • Loading branch information
GeneFerneau committed Jul 30, 2021
1 parent 237c8ae commit 3d67620
Show file tree
Hide file tree
Showing 5 changed files with 407 additions and 196 deletions.
167 changes: 105 additions & 62 deletions src/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use rand::RngCore;

use crate::error::Error;
use crate::messages::ConfirmedCoinSwapTxInfo;
use crate::wallet_sync::{create_multisig_redeemscript, Wallet, WalletSwapCoin, NETWORK};
use crate::wallet_sync::{
create_multisig_redeemscript, IncomingSwapCoin, OutgoingSwapCoin, Wallet, NETWORK,
};

//TODO should be configurable somehow
//relatively low value for now so that its easier to test on regtest
Expand All @@ -44,6 +46,9 @@ pub trait SwapCoin {
fn get_multisig_redeemscript(&self) -> Script;
fn get_contract_tx(&self) -> Transaction;
fn get_contract_redeemscript(&self) -> Script;
fn get_other_privkey(&self) -> Option<&SecretKey>;
fn get_contract_privkey(&self) -> Option<&SecretKey>;
fn get_hash_preimage(&self) -> Option<&[u8; 32]>;
fn get_funding_amount(&self) -> u64;
fn verify_contract_tx_receiver_sig(&self, sig: &Signature) -> bool;
fn verify_contract_tx_sender_sig(&self, sig: &Signature) -> bool;
Expand Down Expand Up @@ -454,79 +459,105 @@ fn verify_contract_tx_sig(
secp.verify(&sighash, sig, &pubkey.key).is_ok()
}

impl SwapCoin for WalletSwapCoin {
fn get_multisig_redeemscript(&self) -> Script {
let secp = Secp256k1::new();
create_multisig_redeemscript(
&self.other_pubkey,
&PublicKey {
compressed: true,
key: secp256k1::PublicKey::from_secret_key(&secp, &self.my_privkey),
},
)
}
macro_rules! impl_swapcoin {
($coin:ident) => {
impl SwapCoin for $coin {
fn get_multisig_redeemscript(&self) -> Script {
let secp = Secp256k1::new();
create_multisig_redeemscript(
&self.other_pubkey,
&PublicKey {
compressed: true,
key: secp256k1::PublicKey::from_secret_key(&secp, &self.my_privkey),
},
)
}

fn get_contract_tx(&self) -> Transaction {
self.contract_tx.clone()
}
fn get_contract_tx(&self) -> Transaction {
self.contract_tx.clone()
}

fn get_contract_redeemscript(&self) -> Script {
self.contract_redeemscript.clone()
}
fn get_contract_redeemscript(&self) -> Script {
self.contract_redeemscript.clone()
}

fn get_funding_amount(&self) -> u64 {
self.funding_amount
}
fn get_other_privkey(&self) -> Option<&SecretKey> {
self.other_privkey.as_ref()
}

fn verify_contract_tx_receiver_sig(&self, sig: &Signature) -> bool {
self.verify_contract_tx_sig(sig)
}
fn get_contract_privkey(&self) -> Option<&SecretKey> {
Some(self.get_lock_privkey())
}

fn verify_contract_tx_sender_sig(&self, sig: &Signature) -> bool {
self.verify_contract_tx_sig(sig)
}
fn get_hash_preimage(&self) -> Option<&[u8; 32]> {
self.hash_preimage.as_ref()
}

fn apply_privkey(&mut self, privkey: SecretKey) -> Result<(), Error> {
let secp = Secp256k1::new();
let pubkey = PublicKey {
compressed: true,
key: secp256k1::PublicKey::from_secret_key(&secp, &privkey),
};
if pubkey != self.other_pubkey {
return Err(Error::Protocol("not correct privkey"));
fn get_funding_amount(&self) -> u64 {
self.funding_amount
}

fn verify_contract_tx_receiver_sig(&self, sig: &Signature) -> bool {
self.verify_contract_tx_sig(sig)
}

fn verify_contract_tx_sender_sig(&self, sig: &Signature) -> bool {
self.verify_contract_tx_sig(sig)
}

fn apply_privkey(&mut self, privkey: SecretKey) -> Result<(), Error> {
let secp = Secp256k1::new();
let pubkey = PublicKey {
compressed: true,
key: secp256k1::PublicKey::from_secret_key(&secp, &privkey),
};
if pubkey != self.other_pubkey {
return Err(Error::Protocol("not correct privkey"));
}
self.other_privkey = Some(privkey);
Ok(())
}
}
self.other_privkey = Some(privkey);
Ok(())
}
};
}

impl WalletSwapCoin {
//"_with_my_privkey" as opposed to with other_privkey
pub fn sign_contract_tx_with_my_privkey(
&self,
contract_tx: &Transaction,
) -> Result<Signature, Error> {
let multisig_redeemscript = self.get_multisig_redeemscript();
Ok(sign_contract_tx(
contract_tx,
&multisig_redeemscript,
self.funding_amount,
&self.my_privkey,
)
.map_err(|_| Error::Protocol("error with signing contract tx"))?)
}
impl_swapcoin!(IncomingSwapCoin);
impl_swapcoin!(OutgoingSwapCoin);

macro_rules! sign_and_verify_contract {
($coin:ident) => {
impl $coin {
//"_with_my_privkey" as opposed to with other_privkey
pub fn sign_contract_tx_with_my_privkey(
&self,
contract_tx: &Transaction,
) -> Result<Signature, Error> {
let multisig_redeemscript = self.get_multisig_redeemscript();
Ok(sign_contract_tx(
contract_tx,
&multisig_redeemscript,
self.funding_amount,
&self.my_privkey,
)
.map_err(|_| Error::Protocol("error with signing contract tx"))?)
}

pub fn verify_contract_tx_sig(&self, sig: &Signature) -> bool {
verify_contract_tx_sig(
&self.contract_tx,
&self.get_multisig_redeemscript(),
self.funding_amount,
&self.other_pubkey,
sig,
)
}
pub fn verify_contract_tx_sig(&self, sig: &Signature) -> bool {
verify_contract_tx_sig(
&self.contract_tx,
&self.get_multisig_redeemscript(),
self.funding_amount,
&self.other_pubkey,
sig,
)
}
}
};
}

sign_and_verify_contract!(IncomingSwapCoin);
sign_and_verify_contract!(OutgoingSwapCoin);

impl SwapCoin for WatchOnlySwapCoin {
fn get_multisig_redeemscript(&self) -> Script {
create_multisig_redeemscript(&self.sender_pubkey, &self.receiver_pubkey)
Expand All @@ -540,6 +571,18 @@ impl SwapCoin for WatchOnlySwapCoin {
self.contract_redeemscript.clone()
}

fn get_other_privkey(&self) -> Option<&SecretKey> {
None
}

fn get_contract_privkey(&self) -> Option<&SecretKey> {
None
}

fn get_hash_preimage(&self) -> Option<&[u8; 32]> {
None
}

fn get_funding_amount(&self) -> u64 {
self.funding_amount
}
Expand Down
11 changes: 6 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,17 +191,18 @@ fn display_wallet_balance(wallet_file_name: &PathBuf, long_form: Option<bool>) {
compressed: true,
key: bitcoin::secp256k1::PublicKey::from_secret_key(
&secp,
&swapcoin.contract_privkey,
swapcoin.get_contract_privkey().unwrap(),
),
};
let type_string = if contract_pubkey
== read_hashlock_pubkey_from_contract(&swapcoin.contract_redeemscript).unwrap()
== read_hashlock_pubkey_from_contract(&swapcoin.get_contract_redeemscript())
.unwrap()
{
"hashlock"
} else {
assert_eq!(
contract_pubkey,
read_timelock_pubkey_from_contract(&swapcoin.contract_redeemscript)
read_timelock_pubkey_from_contract(&swapcoin.get_contract_redeemscript())
.unwrap()
);
"timelock"
Expand All @@ -214,8 +215,8 @@ fn display_wallet_balance(wallet_file_name: &PathBuf, long_form: Option<bool>) {
if long_form { &"" } else { &txid[58..64] },
utxo.vout,
type_string,
if swapcoin.hash_preimage.is_some() { "known" } else { "unknown" },
read_locktime_from_contract(&swapcoin.contract_redeemscript)
if swapcoin.get_hash_preimage().is_some() { "known" } else { "unknown" },
read_locktime_from_contract(&swapcoin.get_contract_redeemscript())
.expect("unable to read locktime from contract"),
utxo.confirmations,
utxo.amount
Expand Down
48 changes: 31 additions & 17 deletions src/maker_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::messages::{
SendersContractSig, SignReceiversContractTx, SignSendersAndReceiversContractTxes,
SignSendersContractTx, SwapCoinPrivateKey, TakerToMakerMessage,
};
use crate::wallet_sync::{CoreAddressLabelType, Wallet, WalletSwapCoin};
use crate::wallet_sync::{CoreAddressLabelType, IncomingSwapCoin, OutgoingSwapCoin, Wallet};

//TODO
//this using of strings to indicate allowed methods doesnt fit aesthetically
Expand Down Expand Up @@ -58,8 +58,8 @@ struct ConnectionState {
//None means that the taker connection is open to doing a number of things
//listed in the NEWLY_CONNECTED_TAKER_... const
allowed_method: Option<&'static str>,
incoming_swapcoins: Option<Vec<WalletSwapCoin>>,
outgoing_swapcoins: Option<Vec<WalletSwapCoin>>,
incoming_swapcoins: Option<Vec<IncomingSwapCoin>>,
outgoing_swapcoins: Option<Vec<OutgoingSwapCoin>>,
pending_funding_txes: Option<Vec<Transaction>>,
}

Expand Down Expand Up @@ -366,7 +366,7 @@ fn handle_proof_of_funding(

log::trace!(target: "maker", "proof of funding valid, creating own funding txes");

connection_state.incoming_swapcoins = Some(Vec::<WalletSwapCoin>::new());
connection_state.incoming_swapcoins = Some(Vec::<IncomingSwapCoin>::new());
for (funding_info, &funding_output_index, &funding_output, &incoming_swapcoin_keys) in izip!(
proof.confirmed_funding_txes.iter(),
funding_output_indexes.iter(),
Expand Down Expand Up @@ -401,7 +401,7 @@ fn handle_proof_of_funding(
.incoming_swapcoins
.as_mut()
.unwrap()
.push(WalletSwapCoin::new(
.push(IncomingSwapCoin::new(
coin_privkey,
coin_other_pubkey,
my_receivers_contract_tx.clone(),
Expand Down Expand Up @@ -520,10 +520,10 @@ fn handle_senders_and_receivers_contract_sigs(
let mut w = wallet.write().unwrap();
incoming_swapcoins
.iter()
.for_each(|incoming_swapcoin| w.add_swapcoin(incoming_swapcoin.clone()));
.for_each(|incoming_swapcoin| w.add_incoming_swapcoin(incoming_swapcoin.clone()));
outgoing_swapcoins
.iter()
.for_each(|outgoing_swapcoin| w.add_swapcoin(outgoing_swapcoin.clone()));
.for_each(|outgoing_swapcoin| w.add_outgoing_swapcoin(outgoing_swapcoin.clone()));
w.update_swap_coins_list()?;

//TODO add coin to watchtowers
Expand Down Expand Up @@ -553,12 +553,20 @@ fn handle_sign_receivers_contract_tx(
let mut sigs = Vec::<Signature>::new();
for receivers_contract_tx_info in message.txes {
sigs.push(
wallet
if let Some(c) = wallet
.read()
.unwrap()
.find_swapcoin(&receivers_contract_tx_info.multisig_redeemscript)
.ok_or(Error::Protocol("multisig_redeemscript not found"))?
.sign_contract_tx_with_my_privkey(&receivers_contract_tx_info.contract_tx)?,
.find_incoming_swapcoin(&receivers_contract_tx_info.multisig_redeemscript)
{
c.sign_contract_tx_with_my_privkey(&receivers_contract_tx_info.contract_tx)?
} else {
wallet
.read()
.unwrap()
.find_outgoing_swapcoin(&receivers_contract_tx_info.multisig_redeemscript)
.ok_or(Error::Protocol("multisig_redeemscript not found"))?
.sign_contract_tx_with_my_privkey(&receivers_contract_tx_info.contract_tx)?
},
);
}
Ok(Some(MakerToTakerMessage::ReceiversContractSig(
Expand All @@ -575,7 +583,7 @@ fn handle_hash_preimage(
let mut wallet_mref = wallet.write().unwrap();
for multisig_redeemscript in message.senders_multisig_redeemscripts {
let mut incoming_swapcoin = wallet_mref
.find_swapcoin_mut(&multisig_redeemscript)
.find_incoming_swapcoin_mut(&multisig_redeemscript)
.ok_or(Error::Protocol("senders multisig_redeemscript not found"))?;
if read_hashvalue_from_contract(&incoming_swapcoin.contract_redeemscript)
.map_err(|_| Error::Protocol("unable to read hashvalue from contract"))?
Expand All @@ -591,7 +599,7 @@ fn handle_hash_preimage(
let mut swapcoin_private_keys = Vec::<SwapCoinPrivateKey>::new();
for multisig_redeemscript in message.receivers_multisig_redeemscripts {
let outgoing_swapcoin = wallet_ref
.find_swapcoin(&multisig_redeemscript)
.find_outgoing_swapcoin(&multisig_redeemscript)
.ok_or(Error::Protocol("receivers multisig_redeemscript not found"))?;
if read_hashvalue_from_contract(&outgoing_swapcoin.contract_redeemscript)
.map_err(|_| Error::Protocol("unable to read hashvalue from contract"))?
Expand Down Expand Up @@ -619,10 +627,16 @@ fn handle_private_key_handover(
) -> Result<Option<MakerToTakerMessage>, Error> {
let mut wallet_ref = wallet.write().unwrap();
for swapcoin_private_key in message.swapcoin_private_keys {
wallet_ref
.find_swapcoin_mut(&swapcoin_private_key.multisig_redeemscript)
.ok_or(Error::Protocol("multisig_redeemscript not found"))?
.apply_privkey(swapcoin_private_key.key)?
if let Some(c) =
wallet_ref.find_incoming_swapcoin_mut(&swapcoin_private_key.multisig_redeemscript)
{
c.apply_privkey(swapcoin_private_key.key)?
} else {
wallet_ref
.find_outgoing_swapcoin_mut(&swapcoin_private_key.multisig_redeemscript)
.ok_or(Error::Protocol("multisig_redeemscript not found"))?
.apply_privkey(swapcoin_private_key.key)?
}
}
wallet_ref.update_swap_coins_list()?;
println!("successfully completed coinswap");
Expand Down
Loading

0 comments on commit 3d67620

Please sign in to comment.