Skip to content

Commit

Permalink
Watchtower challenge sigs collected
Browse files Browse the repository at this point in the history
  • Loading branch information
ekrembal committed Dec 22, 2024
1 parent 27dcdb0 commit b89d52c
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 77 deletions.
13 changes: 13 additions & 0 deletions core/src/builder/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,16 @@ pub fn generate_relative_timelock_script(
.push_opcode(OP_CHECKSIG)
.into_script()
}

pub fn actor_with_preimage_script(
actor_taproot_xonly_pk: XOnlyPublicKey,
hash: &[u8; 20],
) -> ScriptBuf {
Builder::new()
.push_opcode(OP_HASH160)
.push_slice(hash)
.push_opcode(OP_EQUALVERIFY)
.push_x_only_key(&actor_taproot_xonly_pk)
.push_opcode(OP_CHECKSIG)
.into_script()
}
128 changes: 84 additions & 44 deletions core/src/builder/sighash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub async fn dummy(
kickoff_txid,
nofn_xonly_pk,
config.num_watchtowers as u32,
watchtower_wots,
watchtower_wots.clone(),
network,
);

Expand All @@ -92,6 +92,27 @@ pub async fn dummy(
0,
)?;

let wcp_txid = watchtower_challenge_page_tx_handler.tx.compute_txid();

for i in 0..config.num_watchtowers {
let mut watchtower_challenge_txhandler =
builder::transaction::create_watchtower_challenge_txhandler(
wcp_txid,
i,
watchtower_wots[i].clone(),
&[0u8; 20],
nofn_xonly_pk,
*operator_xonly_pk,
network,
);

let _yield = Actor::convert_tx_to_sighash_script_spend(
&mut watchtower_challenge_txhandler,
0,
0,
)?;
}

let time2_tx = builder::transaction::create_time2_tx(
*operator_xonly_pk,
time_txid,
Expand Down Expand Up @@ -122,32 +143,31 @@ pub fn create_nofn_sighash_stream(
network: bitcoin::Network,
) -> impl Stream<Item = Result<TapSighash, BridgeError>> {
try_stream! {
let move_tx = builder::transaction::create_move_tx(
deposit_outpoint,
nofn_xonly_pk,
bridge_amount_sats,
network,
);
let move_txid = move_tx.compute_txid();

let operators: Vec<(secp256k1::XOnlyPublicKey, bitcoin::Address, Txid)> =
db.get_operators(None).await?;

if operators.len() < config.num_operators {
panic!("Not enough operators");
}
let move_tx = builder::transaction::create_move_tx(
deposit_outpoint,
nofn_xonly_pk,
bridge_amount_sats,
network,
);
let move_txid = move_tx.compute_txid();

let operators: Vec<(secp256k1::XOnlyPublicKey, bitcoin::Address, Txid)> =
db.get_operators(None).await?;

if operators.len() < config.num_operators {
panic!("Not enough operators");
}


for (operator_idx, (operator_xonly_pk, operator_reimburse_address, collateral_funding_txid)) in
operators.iter().enumerate()
{

// get the watchtower winternitz pubkeys for this operator
let watchtower_challenge_wots: Vec<_> = (0..config.num_watchtowers)
.map(|i| db.get_winternitz_public_keys(None, i as u32, operator_idx as u32))
.collect();
let watchtower_challenge_wots= futures::future::try_join_all(watchtower_challenge_wots).await?;

.map(|i| db.get_winternitz_public_keys(None, i as u32, operator_idx as u32))
.collect();
let watchtower_challenge_wots =
futures::future::try_join_all(watchtower_challenge_wots).await?;

let mut input_txid = *collateral_funding_txid;
let mut input_amunt = collateral_funding_amount;
Expand Down Expand Up @@ -184,37 +204,57 @@ pub fn create_nofn_sighash_stream(
kickoff_txid,
nofn_xonly_pk,
config.num_watchtowers as u32,
watchtower_wots,
watchtower_wots.clone(),
network,
);

yield Actor::convert_tx_to_sighash_pubkey_spend(
&mut watchtower_challenge_page_tx_handler,
0,
)?;
yield Actor::convert_tx_to_sighash_pubkey_spend(
&mut watchtower_challenge_page_tx_handler,
0,
)?;

let wcp_txid = watchtower_challenge_page_tx_handler.tx.compute_txid();

let time2_tx = builder::transaction::create_time2_tx(
*operator_xonly_pk,
time_txid,
input_amunt,
network,
);
for i in 0..config.num_watchtowers {
let mut watchtower_challenge_txhandler = builder::transaction::create_watchtower_challenge_txhandler(
wcp_txid,
i,
watchtower_wots[i].clone(),
&[0u8; 20],
nofn_xonly_pk,
*operator_xonly_pk,
network,
);

input_txid = time2_tx.compute_txid();
input_amunt = time2_tx.output[0].value;
}
yield Actor::convert_tx_to_sighash_script_spend(
&mut watchtower_challenge_txhandler,
0,
0,
)?;
}
// First iterate over operators
// For each operator, iterate over time txs
// For each time tx, create kickoff txid
// using kickoff txid, create watchtower challenge page
// yield watchtower challenge page sighash
// yield watchtower challenge tx sighash per watchtower
// yield sighash_single|anyonecanpay sighash for challenge tx
// TBC

// yield Actor::convert_tx_to_sighash_script_spend(&mut timeout_tx_handler, 0, 0)?;

let time2_tx = builder::transaction::create_time2_tx(
*operator_xonly_pk,
time_txid,
input_amunt,
network,
);

input_txid = time2_tx.compute_txid();
input_amunt = time2_tx.output[0].value;
}
}
// First iterate over operators
// For each operator, iterate over time txs
// For each time tx, create kickoff txid
// using kickoff txid, create watchtower challenge page
// yield watchtower challenge page sighash
// yield watchtower challenge tx sighash per watchtower
// yield sighash_single|anyonecanpay sighash for challenge tx
// TBC

// yield Actor::convert_tx_to_sighash_script_spend(&mut timeout_tx_handler, 0, 0)?;
}
}

pub fn create_timout_tx_sighash_stream(
Expand Down
61 changes: 47 additions & 14 deletions core/src/builder/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,31 +405,64 @@ pub fn create_watchtower_challenge_page_txhandler(
}
}

pub fn create_watchtower_challenge_page_2_txhandler(
wcp_utxo: UTXO,
pub fn create_watchtower_challenge_txhandler(
wcp_txid: Txid,
watchtower_idx: usize,
watchtower_wots: Vec<[u8; 20]>,
operator_unlock_hash: &[u8; 20],
nofn_xonly_pk: XOnlyPublicKey,
operator_xonly_pk: XOnlyPublicKey,
network: bitcoin::Network,
) -> TxHandler {
let tx_ins = create_tx_ins(vec![wcp_utxo.outpoint]);
let tx_ins = create_tx_ins(vec![OutPoint {
txid: wcp_txid,
vout: watchtower_idx as u32,
}]);

let nofn_1week = builder::script::generate_relative_timelock_script(nofn_xonly_pk, 7 * 24 * 6);
let (nofn_or_nofn_1week, _) =
builder::address::create_taproot_address(&[nofn_1week], Some(nofn_xonly_pk), network);
// TODO: This also needs to include nofn + operator preimage hash
let script_pubkey = nofn_or_nofn_1week.script_pubkey();
let operator_with_preimage =
builder::script::actor_with_preimage_script(operator_xonly_pk, operator_unlock_hash);
let (nofn_or_nofn_1week, _) = builder::address::create_taproot_address(
&[operator_with_preimage, nofn_1week],
None,
network,
);

let tx_outs = vec![TxOut {
value: wcp_utxo.txout.value - MOVE_TX_MIN_RELAY_FEE,
script_pubkey,
}];
let tx_outs = vec![
TxOut {
value: Amount::from_sat(1000), // TODO: Hand calculate this
script_pubkey: nofn_or_nofn_1week.script_pubkey(),
},
builder::script::anyone_can_spend_txout(),
];

let wcptx2 = create_btc_tx(tx_ins, tx_outs);

// Calculate prevouts:
let verifier =
winternitz::Winternitz::<winternitz::ListpickVerifier, winternitz::TabledConverter>::new();
let wots_params = winternitz::Parameters::new(240, 4);

let mut x = verifier.checksig_verify(&wots_params, watchtower_wots.as_ref());
x = x.push_x_only_key(&nofn_xonly_pk);
x = x.push_opcode(OP_CHECKSIG); // TODO: Add checksig in the beginning
let watchtower_challenge_script = x.compile();
let (watchtower_challenge_addr, watchtower_challenge_taproot_spend_info) =
builder::address::create_taproot_address(
&[watchtower_challenge_script.clone()],
None,
network,
);

let prevouts = vec![TxOut {
value: Amount::from_sat(2000), // TOOD: Hand calculate this
script_pubkey: watchtower_challenge_addr.script_pubkey(), // TODO: Add winternitz checks here
}];
TxHandler {
tx: wcptx2,
prevouts: vec![wcp_utxo.txout.clone()],
scripts: vec![vec![]],
taproot_spend_infos: vec![],
prevouts,
scripts: vec![vec![watchtower_challenge_script]],
taproot_spend_infos: vec![watchtower_challenge_taproot_spend_info],
}
}

Expand Down
24 changes: 11 additions & 13 deletions core/src/rpc/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ use crate::{
builder::sighash::create_nofn_sighash_stream,
errors::BridgeError,
musig2::{aggregate_nonces, MuSigPubNonce},
rpc::{
clementine::{self, DepositSignSession},
verifier::NUM_REQUIRED_SIGS,
},
rpc::clementine::{self, DepositSignSession},
ByteArray32, ByteArray66, EVMAddress,
};
use bitcoin::{hashes::Hash, Amount};
Expand Down Expand Up @@ -221,15 +218,18 @@ impl ClementineAggregator for Aggregator {
tracing::debug!("Parsed deposit params");

// generate nonces from all verifiers
let num_required_sigs = self.config.num_operators
* self.config.num_time_txs
* (1 + self.config.num_watchtowers);
let (first_responses, mut nonce_streams) =
self.create_nonce_streams(NUM_REQUIRED_SIGS as u32).await?;
self.create_nonce_streams(num_required_sigs as u32).await?;

// Open the streams for deposit_sign for each verifier
let mut partial_sig_streams = try_join_all(self.verifier_clients.iter().map(|v| {
let mut client = v.clone(); // Clone each client to avoid mutable borrow
// https://github.com/hyperium/tonic/issues/33#issuecomment-538150828
async move {
let (tx, rx) = tokio::sync::mpsc::channel(128);
let (tx, rx) = tokio::sync::mpsc::channel(1280);
let receiver_stream = tokio_stream::wrappers::ReceiverStream::new(rx);
// let x = tokio_stream::iter(1..usize::MAX).map(|i| i.to_string());
let stream = client.deposit_sign(receiver_stream).await?;
Expand Down Expand Up @@ -268,7 +268,7 @@ impl ClementineAggregator for Aggregator {
// Open the streams for deposit_finalize
let deposit_finalize_streams = try_join_all(deposit_finalize_clients.iter_mut().map(|v| {
async move {
let (tx, rx) = tokio::sync::mpsc::channel(128);
let (tx, rx) = tokio::sync::mpsc::channel(1280);
let receiver_stream = tokio_stream::wrappers::ReceiverStream::new(rx);

// Move `client` into this async block and use it directly
Expand Down Expand Up @@ -310,8 +310,11 @@ impl ClementineAggregator for Aggregator {
self.config.bridge_amount_sats,
self.config.network,
));
let num_required_sigs = self.config.num_operators
* self.config.num_time_txs
* (1 + self.config.num_watchtowers);

for _ in 0..NUM_REQUIRED_SIGS {
for _ in 0..num_required_sigs {
// Get the next nonce from each stream
let pub_nonces = try_join_all(nonce_streams.iter_mut().map(|s| async {
s.next()
Expand Down Expand Up @@ -380,11 +383,6 @@ impl ClementineAggregator for Aggregator {
}
}

// for (future, _) in deposit_finalize_streams.iter_mut() {
// let x = future;
// let x = future.await.unwrap();
// }

tracing::debug!("Waiting for deposit finalization");

let move_tx_partial_sigs = try_join_all(
Expand Down
16 changes: 10 additions & 6 deletions core/src/rpc/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;
use tonic::{async_trait, Request, Response, Status, Streaming};

pub const NUM_REQUIRED_SIGS: usize = 4;

#[async_trait]
impl ClementineVerifier for Verifier {
type NonceGenStream = ReceiverStream<Result<NonceGenResponse, Status>>;
Expand Down Expand Up @@ -241,7 +239,7 @@ impl ClementineVerifier for Verifier {
};

// now stream the nonces
let (tx, rx) = mpsc::channel(128);
let (tx, rx) = mpsc::channel(1280);
tokio::spawn(async move {
// First send the session id
let response = NonceGenResponse {
Expand All @@ -268,7 +266,7 @@ impl ClementineVerifier for Verifier {
) -> Result<Response<Self::DepositSignStream>, Status> {
let mut in_stream = req.into_inner();

let (tx, rx) = mpsc::channel(128);
let (tx, rx) = mpsc::channel(1280);

tracing::info!("Received deposit sign request");

Expand Down Expand Up @@ -349,6 +347,9 @@ impl ClementineVerifier for Verifier {
verifier.config.bridge_amount_sats,
verifier.config.network,
));
let num_required_sigs = verifier.config.num_operators
* verifier.config.num_time_txs
* (1 + verifier.config.num_watchtowers);

while let Some(result) = in_stream.message().await.unwrap() {
let agg_nonce = match result
Expand Down Expand Up @@ -382,7 +383,7 @@ impl ClementineVerifier for Verifier {
tx.send(Ok(partial_sig)).await.unwrap();

nonce_idx += 1;
if nonce_idx == NUM_REQUIRED_SIGS {
if nonce_idx == num_required_sigs {
break;
}
}
Expand Down Expand Up @@ -462,6 +463,9 @@ impl ClementineVerifier for Verifier {
self.config.bridge_amount_sats,
self.config.network,
));
let num_required_sigs = self.config.num_operators
* self.config.num_time_txs
* (1 + self.config.num_watchtowers);

let mut nonce_idx: usize = 0;
while let Some(result) = in_stream.message().await.unwrap() {
Expand Down Expand Up @@ -489,7 +493,7 @@ impl ClementineVerifier for Verifier {
tracing::debug!("Final Signature Verified");

nonce_idx += 1;
if nonce_idx == NUM_REQUIRED_SIGS {
if nonce_idx == num_required_sigs {
break;
}
}
Expand Down

0 comments on commit b89d52c

Please sign in to comment.