bark/exit/models/
mod.rs

1
2mod error;
3mod package;
4mod states;
5
6pub use self::package::{ExitTransactionPackage, TransactionInfo, ChildTransactionInfo};
7pub use self::error::ExitError;
8pub use self::states::{
9	ExitTx, ExitTxStatus, ExitTxOrigin, ExitStartState, ExitProcessingState, ExitAwaitingDeltaState,
10	ExitClaimableState, ExitClaimInProgressState, ExitClaimedState,
11};
12
13use ark::VtxoId;
14use bitcoin::Txid;
15
16use bitcoin_ext::{BlockDelta, BlockHeight, BlockRef, TxStatus};
17
18/// A utility type to wrap ExitState children so they can be easily serialized. This also helps with
19/// debugging a lot!
20#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
21#[serde(tag = "type", rename_all = "kebab-case")]
22pub enum ExitState {
23	Start(ExitStartState),
24	Processing(ExitProcessingState),
25	AwaitingDelta(ExitAwaitingDeltaState),
26	Claimable(ExitClaimableState),
27	ClaimInProgress(ExitClaimInProgressState),
28	Claimed(ExitClaimedState),
29}
30
31impl ExitState {
32	pub fn new_start(tip: BlockHeight) -> Self {
33		ExitState::Start(ExitStartState { tip_height: tip })
34	}
35
36	pub fn new_processing<T: IntoIterator<Item = Txid>>(tip: BlockHeight, txids: T) -> Self {
37		ExitState::Processing(ExitProcessingState {
38			tip_height: tip,
39			transactions: txids.into_iter()
40				.map(|id| ExitTx {
41					txid: id,
42					status: ExitTxStatus::VerifyInputs,
43				})
44				.collect::<Vec<_>>(),
45		})
46	}
47
48	pub fn new_processing_from_transactions(tip: BlockHeight, transactions: Vec<ExitTx>) -> Self {
49		ExitState::Processing(ExitProcessingState {
50			tip_height: tip,
51			transactions,
52		})
53	}
54
55	pub fn new_awaiting_delta(
56		tip: BlockHeight,
57		confirmed_block: BlockRef,
58		wait_delta: BlockDelta
59	) -> Self {
60		debug_assert_ne!(wait_delta, 0, "wait delta must be non-zero");
61		let claimable_height = confirmed_block.height + wait_delta as BlockHeight;
62		ExitState::AwaitingDelta(ExitAwaitingDeltaState {
63			tip_height: tip,
64			confirmed_block,
65			claimable_height,
66		})
67	}
68
69	pub fn new_claimable(
70		tip: BlockHeight,
71		claimable_since: BlockRef,
72		last_scanned_block: Option<BlockRef>
73	) -> Self {
74		ExitState::Claimable(ExitClaimableState {
75			tip_height: tip,
76			claimable_since,
77			last_scanned_block,
78		})
79	}
80
81	pub fn new_claim_in_progress(
82		tip: BlockHeight,
83		claimable_since: BlockRef,
84		claim_txid: Txid
85	) -> Self {
86		ExitState::ClaimInProgress(ExitClaimInProgressState {
87			tip_height: tip,
88			claimable_since,
89			claim_txid,
90		})
91	}
92
93	pub fn new_claimed(tip: BlockHeight, txid: Txid, block: BlockRef) -> Self {
94		ExitState::Claimed(ExitClaimedState {
95			tip_height: tip,
96			txid,
97			block,
98		})
99	}
100
101	pub fn is_pending(&self) -> bool {
102		match self {
103			ExitState::Start(_) => true,
104			ExitState::Processing(_) => true,
105			ExitState::AwaitingDelta(_) => true,
106			_ => false,
107		}
108	}
109
110	pub fn requires_confirmations(&self) -> bool {
111		match self {
112			ExitState::Processing(s) => {
113				s.transactions.iter().any(|s| match s.status {
114					ExitTxStatus::AwaitingInputConfirmation { .. } => true,
115					ExitTxStatus::BroadcastWithCpfp { .. } => true,
116					_ => false,
117				})
118			},
119			ExitState::AwaitingDelta(_) => true,
120			ExitState::ClaimInProgress(_) => true,
121			_ => false,
122		}
123	}
124
125	/// Indicates whether the state relies on network updates during wallet sync to check whether
126	/// the exit can be spent
127	pub fn requires_network_update(&self) -> bool {
128		match self {
129			// If all transactions are either confirmed or already broadcast we can count Processing
130			// as requiring network updates since we don't need to create more exit packages.
131			ExitState::Processing(s) => s.transactions.iter().all(|s| match s.status {
132				ExitTxStatus::BroadcastWithCpfp { .. } => true,
133				ExitTxStatus::Confirmed { .. } => true,
134				_ => false,
135			}),
136			ExitState::AwaitingDelta(_) => true,
137			ExitState::Claimable(_) => true,
138			ExitState::ClaimInProgress(_) => true,
139			_ => false,
140		}
141	}
142
143	pub fn claimable_height(&self) -> Option<BlockHeight> {
144		match self {
145			ExitState::AwaitingDelta(s) => Some(s.claimable_height),
146			ExitState::Claimable(s) => Some(s.claimable_since.height),
147			ExitState::ClaimInProgress(s) => Some(s.claimable_since.height),
148			_ => None,
149		}
150	}
151}
152
153#[derive(Debug, Clone, PartialEq, Eq)]
154pub struct ExitProgressStatus {
155	/// The ID of the VTXO that is being unilaterally exited
156	pub vtxo_id: VtxoId,
157	/// The current state of the exit transaction
158	pub state: ExitState,
159	/// Any error that occurred during the exit process
160	pub error: Option<ExitError>,
161}
162
163#[derive(Debug, Clone, PartialEq, Eq)]
164pub struct ExitTransactionStatus {
165	/// The ID of the VTXO that is being unilaterally exited
166	pub vtxo_id: VtxoId,
167	/// The current state of the exit transaction
168	pub state: ExitState,
169	/// The history of each state the exit transaction has gone through
170	pub history: Option<Vec<ExitState>>,
171	/// Each exit transaction package required for the unilateral exit
172	pub transactions: Vec<ExitTransactionPackage>,
173}
174
175#[derive(Clone, Copy, Debug,  Eq, PartialEq)]
176pub struct ExitChildStatus {
177	pub txid: Txid,
178	pub status: TxStatus,
179	pub origin: ExitTxOrigin,
180}