1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>
16

            
17
use {
18
    super::*,
19
    dp_core::ParaId,
20
    frame_support::{dispatch::DispatchErrorWithPostInfo, pallet_prelude::*},
21
    serde::{de::DeserializeOwned, Serialize},
22
    tp_traits::{apply, derive_scale_codec, derive_storage_traits},
23
};
24

            
25
pub type StringOf<T> = BoundedVec<u8, <T as Config>::MaxStringLen>;
26
pub type StringListOf<T> = BoundedVec<StringOf<T>, <T as Config>::MaxNodeUrlCount>;
27

            
28
#[apply(derive_scale_codec)]
29
#[derive(RuntimeDebugNoBound, PartialEqNoBound, EqNoBound, CloneNoBound, MaxEncodedLen)]
30
#[scale_info(skip_type_params(T))]
31
pub struct Profile<T: Config> {
32
    /// Which para ids this profile is willing to accept providing services to.
33
    pub para_ids: ParaIdsFilter<T>,
34

            
35
    /// Specifies how the profile is willing to be assigned, mainly in terms of payment.
36
    pub assignment_request: ProviderRequestOf<T>,
37

            
38
    /// URLs to directly connect to this node RPC. Multiple URLs can be used to expose different
39
    /// protocols (ws, wss, https, etc).
40
    pub direct_rpc_urls: StringListOf<T>,
41

            
42
    /// URLs to connect to a proxy/load balancer represented by this profile. Multiple URLs can be
43
    /// used to expose different protocols (ws, wss, https, etc).
44
    pub proxy_rpc_urls: StringListOf<T>,
45

            
46
    /// URL to connect to the node as a bootnode. URL should be in MultiAddress format.
47
    pub bootnode_url: Option<StringOf<T>>,
48

            
49
    /// Kind of node this profile is running, which determines which services it can provide.
50
    pub node_type: NodeType,
51

            
52
    /// Freeform field to provide additional informations.
53
    pub additional_info: StringOf<T>,
54
}
55

            
56
impl<T: Config> Profile<T> {
57
    pub fn strings_len(&self) -> usize {
58
        let mut len = 0;
59
        len += self.direct_rpc_urls.iter().map(|x| x.len()).sum::<usize>();
60
        len += self.proxy_rpc_urls.iter().map(|x| x.len()).sum::<usize>();
61
        len += self.bootnode_url.iter().map(|x| x.len()).sum::<usize>();
62
        len += self.additional_info.len();
63
        len
64
    }
65
}
66

            
67
#[apply(derive_scale_codec)]
68
#[derive(RuntimeDebugNoBound, PartialEqNoBound, EqNoBound, CloneNoBound, MaxEncodedLen)]
69
#[scale_info(skip_type_params(T))]
70
pub enum ParaIdsFilter<T: Config> {
71
    AnyParaId,
72
    Whitelist(BoundedBTreeSet<ParaId, T::MaxParaIdsVecLen>),
73
    Blacklist(BoundedBTreeSet<ParaId, T::MaxParaIdsVecLen>),
74
}
75

            
76
impl<T: Config> ParaIdsFilter<T> {
77
    #[allow(clippy::len_without_is_empty)]
78
    pub fn len(&self) -> usize {
79
        match self {
80
            Self::AnyParaId => 0,
81
            Self::Whitelist(list) | Self::Blacklist(list) => list.len(),
82
        }
83
    }
84

            
85
163
    pub fn can_assign(&self, para_id: &ParaId) -> bool {
86
163
        match self {
87
162
            ParaIdsFilter::AnyParaId => true,
88
1
            ParaIdsFilter::Whitelist(list) => list.contains(para_id),
89
            ParaIdsFilter::Blacklist(list) => !list.contains(para_id),
90
        }
91
163
    }
92
}
93

            
94
#[apply(derive_storage_traits)]
95
#[derive(MaxEncodedLen, DecodeWithMemTracking)]
96
pub enum NodeType {
97
    Substrate,
98
    Frontier,
99
}
100

            
101
/// Profile with additional data:
102
/// - the account id which created (and manage) the profile
103
/// - the amount deposited to register the profile
104
#[apply(derive_scale_codec)]
105
#[derive(RuntimeDebugNoBound, PartialEqNoBound, EqNoBound, CloneNoBound, MaxEncodedLen)]
106
#[scale_info(skip_type_params(T))]
107
pub struct RegisteredProfile<T: Config> {
108
    pub account: T::AccountId,
109
    pub deposit: BalanceOf<T>,
110
    pub profile: Profile<T>,
111
    /// There can be at most 1 assignment per profile.
112
    pub assignment: Option<(ParaId, AssignmentWitnessOf<T>)>,
113
}
114

            
115
/// Allows to process various kinds of payment options for assignments.
116
pub trait AssignmentProcessor<AccountId> {
117
    /// Providers requests which kind of payment it accepts.
118
    type ProviderRequest: tp_traits::StorageTraits + Serialize + DeserializeOwned + MaxEncodedLen;
119
    /// Extra parameter the assigner provides.
120
    type AssignerParameter: tp_traits::StorageTraits + Serialize + DeserializeOwned;
121
    /// Represents the succesful outcome of the assignment.
122
    type AssignmentWitness: tp_traits::StorageTraits + Serialize + DeserializeOwned + MaxEncodedLen;
123

            
124
    fn try_start_assignment(
125
        assigner: AccountId,
126
        provider: AccountId,
127
        request: &Self::ProviderRequest,
128
        extra: Self::AssignerParameter,
129
    ) -> Result<Self::AssignmentWitness, DispatchErrorWithPostInfo>;
130

            
131
    fn try_stop_assignment(
132
        provider: AccountId,
133
        witness: Self::AssignmentWitness,
134
    ) -> Result<(), DispatchErrorWithPostInfo>;
135

            
136
    // The values returned by the following functions should match with each other.
137
    #[cfg(feature = "runtime-benchmarks")]
138
    fn benchmark_provider_request() -> Self::ProviderRequest;
139

            
140
    #[cfg(feature = "runtime-benchmarks")]
141
    fn benchmark_assigner_parameter() -> Self::AssignerParameter;
142

            
143
    #[cfg(feature = "runtime-benchmarks")]
144
    fn benchmark_assignment_witness() -> Self::AssignmentWitness;
145
}