Merge #413: Check for same sequence in recovery paths

9c30c0dff2dab6251a8c462f7a38c884318942c9 Check for same sequence recovery paths (edouard)

Pull request description:

ACKs for top commit:
  edouardparis:
    Self-ACK 9c30c0dff2dab6251a8c462f7a38c884318942c9

Tree-SHA512: 65fae3f119c0873ee523aa7974b1d221b682c264559ccb7267c53913a33461d12f4c60346f3cbaa6ea5e356f64b18a2471ad8461a2a3e369a65d0029366e0713
This commit is contained in:
edouard 2023-04-06 14:18:58 +02:00
commit 0420e41c2e
No known key found for this signature in database
GPG Key ID: E65F7A089C20DC8F
2 changed files with 105 additions and 73 deletions

View File

@ -49,6 +49,7 @@ pub struct RecoveryPath {
keys: Vec<DescriptorKey>,
threshold: usize,
sequence: u16,
duplicate_sequence: bool,
}
impl RecoveryPath {
@ -57,11 +58,14 @@ impl RecoveryPath {
keys: vec![DescriptorKey::default()],
threshold: 1,
sequence: u16::MAX,
duplicate_sequence: false,
}
}
fn valid(&self) -> bool {
!self.keys.is_empty() && !self.keys.iter().any(|k| k.key.is_none())
!self.keys.is_empty()
&& !self.keys.iter().any(|k| k.key.is_none())
&& !self.duplicate_sequence
}
fn check_network(&mut self, network: Network) {
@ -73,6 +77,7 @@ impl RecoveryPath {
fn view(&self) -> Element<message::DefinePath> {
view::recovery_path_view(
self.sequence,
self.duplicate_sequence,
self.threshold,
self.keys
.iter()
@ -143,6 +148,8 @@ impl DefineDescriptor {
let mut duplicate_keys = HashSet::new();
let mut all_names: HashMap<String, Fingerprint> = HashMap::new();
let mut duplicate_names = HashSet::new();
let mut all_sequence = HashSet::new();
let mut duplicate_sequence = HashSet::new();
for spending_key in &self.spending_keys {
if let Some(key) = &spending_key.key {
if let Some(fg) = all_names.get(&spending_key.name) {
@ -159,7 +166,12 @@ impl DefineDescriptor {
}
}
}
for path in &self.recovery_paths {
for path in &mut self.recovery_paths {
if all_sequence.contains(&path.sequence) {
duplicate_sequence.insert(path.sequence);
} else {
all_sequence.insert(path.sequence);
}
for recovery_key in &path.keys {
if let Some(key) = &recovery_key.key {
if let Some(fg) = all_names.get(&recovery_key.name) {
@ -185,6 +197,7 @@ impl DefineDescriptor {
}
for path in &mut self.recovery_paths {
path.duplicate_sequence = duplicate_sequence.contains(&path.sequence);
for recovery_key in path.keys.iter_mut() {
if let Some(key) = &recovery_key.key {
recovery_key.duplicate_key = duplicate_keys.contains(key);
@ -342,6 +355,7 @@ impl Step for DefineDescriptor {
if let Some(path) = self.recovery_paths.get_mut(i) {
path.sequence = seq;
}
self.check_for_duplicate();
}
message::DefinePath::EditSequence => {
if let Some(path) = self.recovery_paths.get(i) {

View File

@ -278,46 +278,49 @@ pub fn define_descriptor<'a>(
pub fn recovery_path_view(
sequence: u16,
duplicate_sequence: bool,
recovery_threshold: usize,
recovery_keys: Vec<Element<message::DefinePath>>,
) -> Element<message::DefinePath> {
Container::new(
Column::new().push(defined_sequence(sequence)).push(
Row::new()
.align_items(Alignment::Center)
.push_maybe(if recovery_keys.len() > 1 {
Some(threshsold_input::threshsold_input(
recovery_threshold,
recovery_keys.len(),
message::DefinePath::ThresholdEdited,
))
} else {
None
})
.push(
scrollable(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(Row::with_children(recovery_keys).spacing(5))
.push(
Button::new(
Container::new(icon::plus_icon().size(50))
.width(Length::Units(150))
.height(Length::Units(150))
.align_y(alignment::Vertical::Center)
.align_x(alignment::Horizontal::Center),
Column::new()
.push(defined_sequence(sequence, duplicate_sequence))
.push(
Row::new()
.align_items(Alignment::Center)
.push_maybe(if recovery_keys.len() > 1 {
Some(threshsold_input::threshsold_input(
recovery_threshold,
recovery_keys.len(),
message::DefinePath::ThresholdEdited,
))
} else {
None
})
.push(
scrollable(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(Row::with_children(recovery_keys).spacing(5))
.push(
Button::new(
Container::new(icon::plus_icon().size(50))
.width(Length::Units(150))
.height(Length::Units(150))
.align_y(alignment::Vertical::Center)
.align_x(alignment::Horizontal::Center),
)
.width(Length::Units(150))
.height(Length::Units(150))
.style(theme::Button::TransparentBorder)
.on_press(message::DefinePath::AddKey),
)
.width(Length::Units(150))
.height(Length::Units(150))
.style(theme::Button::TransparentBorder)
.on_press(message::DefinePath::AddKey),
)
.padding(5),
)
.horizontal_scroll(Properties::new().width(3).scroller_width(3)),
),
),
.padding(5),
)
.horizontal_scroll(Properties::new().width(3).scroller_width(3)),
),
),
)
.padding(5)
.style(theme::Container::Card(theme::Card::Border))
@ -1032,46 +1035,61 @@ pub fn install<'a>(
)
}
pub fn defined_sequence<'a>(sequence: u16) -> Element<'a, message::DefinePath> {
pub fn defined_sequence<'a>(
sequence: u16,
duplicate_sequence: bool,
) -> Element<'a, message::DefinePath> {
let (n_years, n_months, n_days, n_hours, n_minutes) = duration_from_sequence(sequence);
Container::new(
Row::new()
.width(Length::Fill)
.align_items(Alignment::Center)
.push(
Container::new(
Column::new()
.spacing(5)
.push(text(format!("Available after {} blocks", sequence)).bold())
.push(
[
(n_years, "y"),
(n_months, "m"),
(n_days, "d"),
(n_hours, "h"),
(n_minutes, "mn"),
]
.iter()
.fold(
Row::new().spacing(5),
|row, (n, unit)| {
row.push_maybe(if *n > 0 {
Some(text(format!("{}{}", n, unit,)))
} else {
None
})
},
),
),
Column::new()
.spacing(5)
.push_maybe(if duplicate_sequence {
Some(
text("No two recovery paths may become available at the very same date.")
.small()
.style(color::legacy::ALERT),
)
.padding(5)
.align_y(alignment::Vertical::Center),
)
} else {
None
})
.push(
button::border(Some(icon::pencil_icon()), "Edit")
.on_press(message::DefinePath::EditSequence),
)
.spacing(15),
Row::new()
.align_items(Alignment::Center)
.push(
Container::new(
Column::new()
.spacing(5)
.push(text(format!("Available after {} blocks", sequence)).bold())
.push(
[
(n_years, "y"),
(n_months, "m"),
(n_days, "d"),
(n_hours, "h"),
(n_minutes, "mn"),
]
.iter()
.fold(
Row::new().spacing(5),
|row, (n, unit)| {
row.push_maybe(if *n > 0 {
Some(text(format!("{}{}", n, unit,)))
} else {
None
})
},
),
),
)
.padding(5)
.align_y(alignment::Vertical::Center),
)
.push(
button::border(Some(icon::pencil_icon()), "Edit")
.on_press(message::DefinePath::EditSequence),
)
.spacing(15),
),
)
.padding(5)
.into()