iota_sdk/client/api/block_builder/input_selection/core/requirement/
alias.rs1use super::{Error, InputSelection, Requirement};
5use crate::{
6 client::{api::input_selection::Burn, secret::types::InputSigningData},
7 types::block::output::{AliasId, AliasTransition, Output, OutputId},
8};
9
10pub(crate) fn is_alias_transition<'a>(
11 input: &Output,
12 input_id: OutputId,
13 outputs: &[Output],
14 burn: impl Into<Option<&'a Burn>>,
15) -> Option<AliasTransition> {
16 if let Output::Alias(alias_input) = &input {
17 let alias_id = alias_input.alias_id_non_null(&input_id);
18 for output in outputs.iter() {
20 if let Output::Alias(alias_output) = output {
21 if *alias_output.alias_id() == alias_id {
22 if alias_output.state_index() == alias_input.state_index() {
23 return Some(AliasTransition::Governance);
25 } else {
26 return Some(AliasTransition::State);
28 }
29 }
30 }
31 }
32 if let Some(burn) = burn.into() {
33 if burn.aliases().contains(&alias_id) {
34 return Some(AliasTransition::Governance);
35 }
36 }
37 }
38 None
39}
40
41pub(crate) fn is_alias_with_id_non_null(output: &Output, alias_id: &AliasId) -> bool {
44 if let Output::Alias(alias) = output {
45 alias.alias_id() == alias_id
46 } else {
47 false
48 }
49}
50
51pub(crate) fn is_alias_with_id(output: &Output, output_id: &OutputId, alias_id: &AliasId) -> bool {
53 if let Output::Alias(alias) = output {
54 &alias.alias_id_non_null(output_id) == alias_id
55 } else {
56 false
57 }
58}
59
60impl InputSelection {
61 pub(crate) fn fulfill_alias_requirement(
63 &mut self,
64 alias_id: AliasId,
65 alias_transition: AliasTransition,
66 ) -> Result<Vec<(InputSigningData, Option<AliasTransition>)>, Error> {
67 if alias_transition.is_state()
69 && self
70 .burn
71 .as_ref()
72 .map_or(false, |burn| burn.aliases.contains(&alias_id))
73 {
74 return Err(Error::UnfulfillableRequirement(Requirement::Alias(
75 alias_id,
76 alias_transition,
77 )));
78 }
79
80 let selected_input = self
81 .selected_inputs
82 .iter()
83 .find(|input| is_alias_with_id(&input.output, input.output_id(), &alias_id));
84
85 if !alias_transition.is_state() && selected_input.is_some() {
88 log::debug!(
89 "{alias_id:?}/{alias_transition:?} requirement already fulfilled by {:?}",
90 selected_input.unwrap().output_id()
91 );
92 return Ok(Vec::new());
93 }
94
95 let available_index = self
96 .available_inputs
97 .iter()
98 .position(|input| is_alias_with_id(&input.output, input.output_id(), &alias_id));
99
100 if selected_input.is_none() && available_index.is_none() {
102 return Err(Error::UnfulfillableRequirement(Requirement::Alias(
103 alias_id,
104 alias_transition,
105 )));
106 }
107
108 if !alias_transition.is_state() {
110 let input = self.available_inputs.swap_remove(available_index.unwrap());
112
113 log::debug!(
114 "{alias_id:?}/{alias_transition:?} requirement fulfilled by {:?}",
115 input.output_id()
116 );
117
118 return Ok(vec![(input, None)]);
120 }
121
122 let input = selected_input.unwrap_or_else(|| &self.available_inputs[available_index.unwrap()]);
127
128 if is_alias_transition(&input.output, *input.output_id(), &self.outputs, self.burn.as_ref())
129 == Some(AliasTransition::Governance)
130 {
131 return Err(Error::UnfulfillableRequirement(Requirement::Alias(
132 alias_id,
133 alias_transition,
134 )));
135 }
136
137 if let Some(available_index) = available_index {
138 let input = self.available_inputs.swap_remove(available_index);
140
141 log::debug!(
142 "{alias_id:?}/{alias_transition:?} requirement fulfilled by {:?}",
143 input.output_id()
144 );
145
146 return Ok(vec![(input, None)]);
147 }
148
149 log::debug!(
150 "{alias_id:?}/{alias_transition:?} requirement already fulfilled by {:?}",
151 selected_input.unwrap().output_id()
152 );
153
154 Ok(Vec::new())
155 }
156}