Skip to main content

bark/exit/models/
states.rs

1use std::collections::HashSet;
2use std::fmt;
3
4use bitcoin::Txid;
5
6use bitcoin_ext::{BlockHeight, BlockRef};
7
8use crate::exit::models::ExitState;
9
10#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
11pub struct ExitTx {
12	pub txid: Txid,
13	pub status: ExitTxStatus,
14}
15
16#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
17#[serde(tag = "type", rename_all = "kebab-case")]
18pub enum ExitTxStatus {
19	#[default]
20	VerifyInputs,
21	AwaitingInputConfirmation {
22		txids: HashSet<Txid>
23	},
24	AwaitingCpfpBroadcast,
25	AwaitingConfirmation {
26		child_txid: Txid,
27		origin: ExitTxOrigin,
28	},
29	Confirmed {
30		child_txid: Txid,
31		block: BlockRef,
32		origin: ExitTxOrigin,
33	},
34}
35
36impl ExitTxStatus {
37	pub fn child_txid(&self) -> Option<&Txid> {
38		match self {
39			ExitTxStatus::AwaitingConfirmation { child_txid, .. } => Some(child_txid),
40			ExitTxStatus::Confirmed { child_txid, .. } => Some(child_txid),
41			_ => None,
42		}
43	}
44
45	pub fn confirmed_in(&self) -> Option<&BlockRef> {
46		match self {
47			ExitTxStatus::Confirmed { block, .. } => Some(block),
48			_ => None,
49		}
50	}
51}
52
53impl fmt::Display for ExitTxStatus {
54	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55		fmt::Debug::fmt(self, f)
56	}
57}
58
59#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
60#[serde(tag = "type", rename_all = "kebab-case")]
61pub enum ExitTxOrigin {
62	Wallet {
63		confirmed_in: Option<BlockRef>
64	},
65	Mempool,
66	Block {
67		confirmed_in: BlockRef
68	},
69}
70
71impl ExitTxOrigin {
72	pub fn confirmed_in(&self) -> Option<BlockRef> {
73		match self {
74			ExitTxOrigin::Wallet { confirmed_in } => *confirmed_in,
75			ExitTxOrigin::Mempool => None,
76			ExitTxOrigin::Block { confirmed_in } => Some(*confirmed_in),
77		}
78	}
79
80	/// Returns a copy of this origin reflecting the given confirmation state, preserving the
81	/// origin kind where it makes sense. A `Wallet` origin keeps its kind (we still know it's
82	/// ours) and updates its `confirmed_in`; mempool/block origins become `Block` once confirmed
83	/// and `Mempool` otherwise.
84	pub fn with_confirmed_in(self, confirmed_in: Option<BlockRef>) -> ExitTxOrigin {
85		match (self, confirmed_in) {
86			(ExitTxOrigin::Wallet { .. }, _) => ExitTxOrigin::Wallet { confirmed_in },
87			(_, Some(confirmed_in)) => ExitTxOrigin::Block { confirmed_in },
88			(_, None) => ExitTxOrigin::Mempool,
89		}
90	}
91}
92
93impl fmt::Display for ExitTxOrigin {
94	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95		fmt::Debug::fmt(self, f)
96	}
97}
98
99#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
100pub struct ExitStartState {
101	pub tip_height: BlockHeight,
102}
103
104#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
105pub struct ExitProcessingState {
106	pub tip_height: BlockHeight,
107	pub transactions: Vec<ExitTx>,
108}
109
110#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
111pub struct ExitAwaitingDeltaState {
112	pub tip_height: BlockHeight,
113	pub confirmed_block: BlockRef,
114	pub claimable_height: BlockHeight,
115}
116
117#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
118pub struct ExitClaimableState {
119	pub tip_height: BlockHeight,
120	pub claimable_since: BlockRef,
121	pub last_scanned_block: Option<BlockRef>,
122}
123
124#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
125pub struct ExitClaimInProgressState {
126	pub tip_height: BlockHeight,
127	pub claimable_since: BlockRef,
128	pub claim_txid: Txid,
129}
130
131#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
132pub struct ExitClaimedState {
133	pub tip_height: BlockHeight,
134	pub txid: Txid,
135	pub block: BlockRef,
136}
137
138/// Terminal state reached when the exit cannot proceed because the VTXO has already been
139/// consumed by something other than this exit (e.g. the server forfeited it in a round).
140/// No exit transactions can be broadcast at this point; the caller should cancel the
141/// associated movement and remove the exit from active tracking.
142#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
143pub struct ExitVtxoAlreadySpentState {
144	pub tip_height: BlockHeight,
145}
146
147impl Into<ExitState> for ExitStartState {
148	fn into(self) -> ExitState {
149		ExitState::Start(self)
150	}
151}
152
153impl Into<ExitState> for ExitProcessingState {
154	fn into(self) -> ExitState {
155		ExitState::Processing(self)
156	}
157}
158
159impl Into<ExitState> for ExitAwaitingDeltaState {
160	fn into(self) -> ExitState {
161		ExitState::AwaitingDelta(self)
162	}
163}
164
165impl Into<ExitState> for ExitClaimableState {
166	fn into(self) -> ExitState {
167		ExitState::Claimable(self)
168	}
169}
170
171impl Into<ExitState> for ExitClaimInProgressState {
172	fn into(self) -> ExitState {
173		ExitState::ClaimInProgress(self)
174	}
175}
176
177impl Into<ExitState> for ExitClaimedState {
178	fn into(self) -> ExitState {
179		ExitState::Claimed(self)
180	}
181}
182
183impl Into<ExitState> for ExitVtxoAlreadySpentState {
184	fn into(self) -> ExitState {
185		ExitState::VtxoAlreadySpent(self)
186	}
187}