iop_morpheus_node/
state_holder.rs1use super::*;
2
3#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
4#[serde(rename_all = "camelCase")]
5pub struct TransactionIdWithHeight {
6 pub transaction_id: String,
7 pub height: BlockHeight,
8}
9
10#[derive(Default)]
11pub struct StateHolder {
12 corrupted: bool,
13 inner: Box<State>,
14}
15
16impl StateHolder {
17 pub const CORRUPTED_ERR_MSG: &'static str =
18 "Morpheus state is corrupt. All incoming changes will be ignored.";
19
20 pub fn is_corrupted(&self) -> bool {
21 self.corrupted
22 }
23
24 pub fn ensure_not_corrupted(&self) -> Result<()> {
25 ensure!(!self.corrupted, StateHolder::CORRUPTED_ERR_MSG);
26 Ok(())
27 }
28
29 pub fn state(&self) -> Result<&State> {
30 self.ensure_not_corrupted()?;
31 Ok(&self.inner)
32 }
33
34 pub fn dry_run(&self, asset: &MorpheusAsset) -> Result<Vec<OperationError>> {
35 if self.is_corrupted() {
36 return Ok(vec![OperationError {
37 invalid_operation_attempt: None,
38 message: StateHolder::CORRUPTED_ERR_MSG.to_owned(),
39 }]);
40 }
41
42 let temp = self.inner.clone();
43 let res = asset.operation_attempts.iter().try_fold(
44 temp,
45 |mut inner, op| -> Result<Box<State>, OperationError> {
46 inner.apply(Mutation::DoAttempt { txid: "dry_run", op }).map_err(|e| {
47 OperationError {
48 invalid_operation_attempt: Some(op.clone()),
49 message: e.to_string(),
50 }
51 })?;
52 Ok(inner)
53 },
54 );
55 let errors = match res {
57 Ok(_) => vec![],
58 Err(e) => vec![e],
59 };
60 Ok(errors)
61 }
62
63 pub fn block_applying(&mut self, height: BlockHeight) -> Result<()> {
64 self.ensure_not_corrupted()?;
65 self.may_corrupt_state(|inner| inner.apply(Mutation::SetBlockHeight { height }))
66 }
67
68 pub fn apply_transaction(&mut self, txid: &str, asset: &MorpheusAsset) -> Result<()> {
69 self.ensure_not_corrupted()?;
70 asset
71 .operation_attempts
72 .iter()
73 .try_for_each(|op| self.inner.apply(Mutation::RegisterAttempt { txid, op }))?;
74 let inner_res = asset.operation_attempts.iter().try_fold(
75 self.inner.clone(),
76 |mut inner, op| -> Result<Box<State>> {
77 inner.apply(Mutation::DoAttempt { txid, op })?;
78 Ok(inner)
79 },
80 );
81 match inner_res {
82 Ok(mut inner) => {
83 inner.apply(Mutation::ConfirmTxn { txid })?;
84 self.inner = inner;
85 Ok(())
86 }
87 Err(e) => {
88 self.inner.apply(Mutation::RejectTxn { txid })?;
89 Err(e)
90 }
91 }
92 }
93
94 pub fn block_reverting(&mut self, height: BlockHeight) -> Result<()> {
95 self.ensure_not_corrupted()?;
96 self.may_corrupt_state(|inner| inner.revert(Mutation::SetBlockHeight { height }))
97 }
98
99 pub fn revert_transaction(&mut self, txid: &str, asset: &MorpheusAsset) -> Result<()> {
100 self.ensure_not_corrupted()?;
101 self.may_corrupt_state(|inner| {
102 let confirmed_opt = inner.is_confirmed(txid);
103 ensure!(
104 confirmed_opt.is_some(),
105 "Transaction {} has not been applied, cannot revert.",
106 txid
107 );
108
109 if confirmed_opt.unwrap() {
111 inner.revert(Mutation::ConfirmTxn { txid })?;
112 asset.operation_attempts.iter().rev().try_for_each(|op| -> Result<()> {
113 inner.revert(Mutation::DoAttempt { txid, op })?;
114 Ok(())
115 })?;
116 } else {
117 inner.revert(Mutation::RejectTxn { txid })?;
118 }
119 asset.operation_attempts.iter().rev().try_for_each(|op| -> Result<()> {
120 inner.revert(Mutation::RegisterAttempt { txid, op })?;
121 Ok(())
122 })?;
123 Ok(())
124 })
125 }
126
127 fn may_corrupt_state(&mut self, action: impl FnOnce(&mut State) -> Result<()>) -> Result<()> {
128 if let Err(e) = action(&mut self.inner) {
129 self.corrupted = true;
130 Err(e)
131 } else {
132 Ok(())
133 }
134 }
135}