Skip to content

Commit

Permalink
impl matchers for asserts
Browse files Browse the repository at this point in the history
  • Loading branch information
atacann committed Feb 28, 2025
1 parent dc176a8 commit a97e1a8
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 64 deletions.
10 changes: 10 additions & 0 deletions core/src/builder/transaction/txhandler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use bitcoin::taproot::{self, LeafVersion};
use bitcoin::transaction::Version;
use bitcoin::{absolute, OutPoint, Script, Sequence, Transaction, Witness};
use bitcoin::{TapLeafHash, TapSighash, TapSighashType, TxOut, Txid};
use std::collections::BTreeMap;
use std::marker::PhantomData;

pub const DEFAULT_SEQUENCE: Sequence = Sequence::ENABLE_RBF_NO_LOCKTIME;
Expand Down Expand Up @@ -462,3 +463,12 @@ impl TxHandlerBuilder {
self.finalize().promote()
}
}

pub fn remove_txhandler_from_map<T: State>(
txhandlers: &mut BTreeMap<TransactionType, TxHandler<T>>,
tx_type: TransactionType,
) -> Result<TxHandler<T>, BridgeError> {
txhandlers
.remove(&tx_type)
.ok_or(BridgeError::TxHandlerNotFound(tx_type))
}
151 changes: 89 additions & 62 deletions core/src/states/kickoff.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
use std::collections::HashMap;

use bitcoin::OutPoint;
use bitcoin::{OutPoint, Txid, Witness};
use statig::prelude::*;

use crate::{
builder::transaction::{ContractContext, DepositData, TransactionType},
builder::transaction::{
remove_txhandler_from_map, ContractContext, DepositData, TransactionType,
},
errors::BridgeError,
rpc::clementine::KickoffId,
states::Duty,
utils,
};

use super::{BlockCache, BlockMatcher, Matcher, Owner, StateContext};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum KickoffEvent {
Challenged,
WatchtowerChallengeSent,
OperatorAssertSent,
WatchtowerChallengeSent {
watchtower_idx: u32,
challenge_txid: Txid,
},
OperatorAssertSent {
assert_idx: u32,
assert_txid: Txid,
},
KickoffFinalizerSpent,
BurnConnectorSpent,
}
Expand All @@ -26,12 +35,11 @@ pub struct KickoffStateMachine<T: Owner> {
pub(crate) matchers: HashMap<Matcher, KickoffEvent>,
pub(crate) dirty: bool,
kickoff_id: KickoffId,
num_operators: u32,
num_watchtowers: u32,
deposit_data: DepositData,
kickoff_height: u32,
watchtower_challenges: HashMap<u32, Vec<u8>>,
operator_asserts: HashMap<u32, Vec<u8>>,
watchtower_challenges: HashMap<u32, Witness>,
operator_asserts: HashMap<u32, Witness>,
watchtower_challenge_sent: bool,
operator_assert_sent: bool,
verifier_disprove_sent: bool,
Expand Down Expand Up @@ -61,7 +69,6 @@ impl<T: Owner> KickoffStateMachine<T> {
kickoff_id: KickoffId,
kickoff_height: u32,
deposit_data: DepositData,
num_operators: u32,
num_watchtowers: u32,
) -> Self {
Self {
Expand All @@ -76,7 +83,6 @@ impl<T: Owner> KickoffStateMachine<T> {
watchtower_challenge_sent: false,
operator_assert_sent: false,
verifier_disprove_sent: false,
num_operators,
num_watchtowers,
}
}
Expand All @@ -101,6 +107,34 @@ impl<T: Owner> KickoffStateMachine<T> {
context: &mut StateContext<T>,
) -> Response<State> {
match event {
KickoffEvent::WatchtowerChallengeSent {
watchtower_idx,
challenge_txid,
} => {
let tx = context
.cache
.txids
.get(challenge_txid)
.expect("Watchtower txid that got matched should be in cache");
// save challenge witness
self.watchtower_challenges
.insert(*watchtower_idx, tx.input[0].witness.clone());
Handled
}
KickoffEvent::OperatorAssertSent {
assert_idx,
assert_txid,
} => {
let tx = context
.cache
.txids
.get(assert_txid)
.expect("Assert txid that got matched should be in cache");
// save assert witness
self.operator_asserts
.insert(*assert_idx, tx.input[0].witness.clone());
Handled
}
_ => Super,
}
}
Expand All @@ -118,27 +152,54 @@ impl<T: Owner> KickoffStateMachine<T> {
.owner
.create_txhandlers(TransactionType::Kickoff, contract_context)
.await?;
let kickoff_txhandler = txhandlers
.remove(&TransactionType::Kickoff)
.ok_or(BridgeError::TxHandlerNotFound(TransactionType::Kickoff))?;
let kickoff_txhandler =
remove_txhandler_from_map(&mut txhandlers, TransactionType::Kickoff)?;

// add operator asserts
let kickoff_txid = kickoff_txhandler.get_txid();
for idx in 4..4 + self.num_operators {
let num_asserts = utils::COMBINED_ASSERT_DATA.num_steps.len();
for assert_idx in 0..num_asserts {
// TODO: use dedicated functions or smth else, not hardcoded here.
// It will be easier when we have data of operators/watchtowers that participated in the deposit in DepositData
let mini_assert_vout = 4 + assert_idx;
let operator_assert_txid = *remove_txhandler_from_map(
&mut txhandlers,
TransactionType::MiniAssert(assert_idx),
)?
.get_txid();
let matcher = Matcher::SpentUtxo(OutPoint {
txid: *kickoff_txid,
vout: idx,
vout: mini_assert_vout as u32,
});
self.matchers
.insert(matcher, KickoffEvent::OperatorAssertSent);
self.matchers.insert(
matcher,
KickoffEvent::OperatorAssertSent {
assert_txid: operator_assert_txid,
assert_idx: assert_idx as u32,
},
);
}
// add watchtower challenges
for idx in 4 + self.num_operators..4 + self.num_operators + self.num_watchtowers {
for watchtower_idx in 0..self.num_watchtowers {
// TODO: use dedicated functions or smth else, not hardcoded here.
// It will be easier when we have data of operators/watchtowers that participated in the deposit in DepositData
let watchtower_challenge_vout = 4 + num_asserts + watchtower_idx as usize * 2;
let watchtower_challenge_txid = *remove_txhandler_from_map(
&mut txhandlers,
TransactionType::WatchtowerChallenge(watchtower_idx as usize),
)?
.get_txid();
let matcher = Matcher::SpentUtxo(OutPoint {
txid: *kickoff_txid,
vout: idx,
vout: watchtower_challenge_vout as u32,
});
self.matchers
.insert(matcher, KickoffEvent::WatchtowerChallengeSent);
self.matchers.insert(
matcher,
KickoffEvent::WatchtowerChallengeSent {
watchtower_idx,
challenge_txid: watchtower_challenge_txid,
},
);
}
// add challenge tx
Ok(())
Expand All @@ -148,12 +209,16 @@ impl<T: Owner> KickoffStateMachine<T> {
pub(crate) async fn on_kickoff_started_entry(&mut self, context: &mut StateContext<T>) {
println!("Kickoff Started");
context
.capture_error(async |context| context.dispatch_duty(Duty::NewKickoff).await)
.capture_error(async |context| {
// Add all watchtower challenges and operator asserts to matchers
self.add_default_matchers(context).await?;
Ok(())
})
.await;
}

#[state(entry_action = "on_watchtower_challenge_entry")]
pub(crate) async fn watchtower_to_challenge(
#[state(entry_action = "on_challenge_entry")]
pub(crate) async fn challenged(
&mut self,
event: &KickoffEvent,
context: &mut StateContext<T>,
Expand All @@ -164,48 +229,10 @@ impl<T: Owner> KickoffStateMachine<T> {
}

#[action]
pub(crate) async fn on_watchtower_challenge_entry(&mut self, context: &mut StateContext<T>) {
pub(crate) async fn on_challenge_entry(&mut self, context: &mut StateContext<T>) {
println!("Watchtower Challenge Stage");
context
.capture_error(async |context| context.dispatch_duty(Duty::WatchtowerChallenge).await)
.await;
}

#[state(entry_action = "on_operator_assert_entry")]
pub(crate) async fn operator_to_assert(
&mut self,
event: &KickoffEvent,
context: &mut StateContext<T>,
) -> Response<State> {
match event {
_ => Super,
}
}

#[action]
pub(crate) async fn on_operator_assert_entry(&mut self, context: &mut StateContext<T>) {
println!("Operator Assert Stage");
context
.capture_error(async |context| context.dispatch_duty(Duty::OperatorAssert).await)
.await;
}

#[state(entry_action = "on_verifier_disprove_entry")]
pub(crate) async fn verifier_to_disprove(
&mut self,
event: &KickoffEvent,
context: &mut StateContext<T>,
) -> Response<State> {
match event {
_ => Super,
}
}

#[action]
pub(crate) async fn on_verifier_disprove_entry(&mut self, context: &mut StateContext<T>) {
println!("Verifier Disprove Stage");
context
.capture_error(async |context| context.dispatch_duty(Duty::VerifierDisprove).await)
.await;
}
}
2 changes: 0 additions & 2 deletions core/src/states/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,14 +281,12 @@ impl<T: Owner + 'static> StateManager<T> {
kickoff_id: crate::rpc::clementine::KickoffId,
block_height: u32,
deposit_data: DepositData,
num_operators: u32,
num_watchtowers: u32,
) -> Result<(), BridgeError> {
let machine = kickoff::KickoffStateMachine::<T>::new(
kickoff_id,
block_height,
deposit_data,
num_operators,
num_watchtowers,
);
let initialized_machine = machine
Expand Down

0 comments on commit a97e1a8

Please sign in to comment.