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:
commit
0420e41c2e
@ -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) {
|
||||
|
||||
@ -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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user