Skip to main content

bark/exit/models/
mod.rs

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