Skip to main content

ethexe_common/
validators.rs

1// Copyright (C) Gear Technologies Inc.
2// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
3
4//! Non-empty validator list wrapper used across ethexe.
5
6use crate::Address;
7use alloc::vec::Vec;
8use derive_more::{Deref, DerefMut, Display, IntoIterator};
9use nonempty::NonEmpty;
10use parity_scale_codec::{Decode, Encode};
11use scale_info::{TypeInfo, build::Fields};
12
13/// [`ValidatorsVec`] is a wrapper over non-empty vector of [`Address`].
14/// It is needed because `NonEmpty` does not implement `Encode` and `Decode`.
15#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Deref, DerefMut, IntoIterator)]
16pub struct ValidatorsVec(NonEmpty<Address>);
17
18impl Encode for ValidatorsVec {
19    fn encode(&self) -> Vec<u8> {
20        Into::<Vec<_>>::into(self.0.clone()).encode()
21    }
22}
23
24impl Decode for ValidatorsVec {
25    fn decode<I: parity_scale_codec::Input>(
26        input: &mut I,
27    ) -> Result<Self, parity_scale_codec::Error> {
28        let inner: Vec<Address> = Decode::decode(input)?;
29        NonEmpty::from_vec(inner)
30            .map(Self)
31            .ok_or(parity_scale_codec::Error::from(
32                "Failed to decode ValidatorsVec: empty vector",
33            ))
34    }
35}
36
37impl TypeInfo for ValidatorsVec {
38    type Identity = Self;
39
40    fn type_info() -> scale_info::Type {
41        scale_info::Type::builder()
42            .path(scale_info::Path::new("ValidatorsVec", module_path!()))
43            .composite(Fields::unnamed().field(|f| f.ty::<Vec<Address>>()))
44    }
45}
46
47#[derive(Debug, Display)]
48#[display("ValidatorsVec cannot be created from an empty collection")]
49pub struct EmptyValidatorsError;
50
51#[cfg(feature = "std")]
52impl std::error::Error for EmptyValidatorsError {}
53
54#[cfg(feature = "mock")]
55impl FromIterator<Address> for ValidatorsVec {
56    #[track_caller]
57    fn from_iter<T: IntoIterator<Item = Address>>(iter: T) -> Self {
58        let vec: Vec<Address> = iter.into_iter().collect();
59        NonEmpty::from_vec(vec)
60            .map(ValidatorsVec)
61            .expect("ValidatorsVec cannot be created from an empty collection")
62    }
63}
64
65impl TryFrom<Vec<Address>> for ValidatorsVec {
66    type Error = EmptyValidatorsError;
67
68    fn try_from(value: Vec<Address>) -> Result<Self, Self::Error> {
69        NonEmpty::from_vec(value)
70            .map(Self)
71            .ok_or(EmptyValidatorsError)
72    }
73}
74
75impl TryFrom<Vec<alloy_primitives::Address>> for ValidatorsVec {
76    type Error = EmptyValidatorsError;
77
78    fn try_from(value: Vec<alloy_primitives::Address>) -> Result<Self, Self::Error> {
79        let vec: Vec<Address> = value.into_iter().map(Into::into).collect();
80        NonEmpty::from_vec(vec)
81            .map(Self)
82            .ok_or(EmptyValidatorsError)
83    }
84}
85
86impl From<NonEmpty<Address>> for ValidatorsVec {
87    fn from(value: NonEmpty<Address>) -> Self {
88        Self(value)
89    }
90}
91
92impl From<ValidatorsVec> for Vec<Address> {
93    fn from(value: ValidatorsVec) -> Self {
94        value.0.into()
95    }
96}
97
98impl From<ValidatorsVec> for Vec<gear_core::ids::ActorId> {
99    fn from(value: ValidatorsVec) -> Self {
100        value.into_iter().map(Address::into).collect()
101    }
102}