1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
crate::ix!();

//-------------------------------------------[.cpp/bitcoin/src/net_permissions.h]

lazy_static!{
    /*
    extern const std::vector<std::string> NET_PERMISSIONS_DOC;
    */
}

bitflags!{
    pub struct NetPermissionFlags: u32 {

        const None = 0;

        /*
         | Can query bloomfilter even if
         | 
         | -peerbloomfilters is false
         |
         */
        const BloomFilter = 1 << 1;

        /*
         | Relay and accept transactions from
         | this peer, even if -blocksonly is true
         | This peer is also not subject to limits
         | on how many transaction INVs are tracked
         |
         */
        const Relay = 1 << 3;

        /*
         | Always relay transactions from this
         | peer, even if already in mempool Keep
         | parameter interaction: forcerelay
         | implies relay
         |
         */
        const ForceRelay = (1 << 2) | Self::Relay.bits;

        /*
         | Allow getheaders during IBD and block-download
         | after maxuploadtarget limit
         |
         */
        const Download = 1 << 6;

        /*
         | Can't be banned/disconnected/discouraged
         | for misbehavior
         |
         */
        const NoBan = (1 << 4) | Self::Download.bits;

        /*
         | Can query the mempool
         |
         */
        const Mempool = 1 << 5;

        /*
         | Can request addrs without hitting a
         | privacy-preserving cache, and send
         | us unlimited amounts of addrs.
         |
         */
        const Addr = 1 << 7;

        /*
         | True if the user did not specifically
         | set fine grained permissions
         |
         */
        const Implicit = 1 << 31;

        const All = 
            Self::BloomFilter.bits 
            | Self::ForceRelay.bits 
            | Self::Relay.bits 
            | Self::NoBan.bits 
            | Self::Mempool.bits 
            | Self::Download.bits 
            | Self::Addr.bits;
    }
}

impl Default for NetPermissionFlags {
    fn default() -> Self {
        NetPermissionFlags::None
    }
}

///------------------------
#[derive(Clone)]
pub struct NetPermissions {
    pub flags: NetPermissionFlags,
}

impl NetPermissions {

    #[inline] pub fn has_flag(
        flags: &NetPermissionFlags,
        f:     NetPermissionFlags) -> bool {
        
        todo!();
        /*
            using t = typename std::underlying_type<NetPermissionFlags>::type;
            return (static_cast<t>(flags) & static_cast<t>(f)) == static_cast<t>(f);
        */
    }
    
    #[inline] pub fn add_flag(
        flags: &mut NetPermissionFlags,
        f:     NetPermissionFlags)  {
        
        todo!();
        /*
            flags = flags | f;
        */
    }

    /**
      | ClearFlag is only called with `f` ==
      | NetPermissionFlags::Implicit.
      |
      | If that should change in the future, be
      | aware that ClearFlag should not be called
      | with a subflag of a multiflag,
      | e.g. NetPermissionFlags::Relay or
      | NetPermissionFlags::Download, as that
      | would leave `flags` in an invalid state
      | corresponding to none of the existing
      | flags.
      */
    #[inline] pub fn clear_flag(
        flags: &mut NetPermissionFlags,
        f:     NetPermissionFlags)  {
        
        todo!();
        /*
            assert(f == NetPermissionFlags::Implicit);
            using t = typename std::underlying_type<NetPermissionFlags>::type;
            flags = static_cast<NetPermissionFlags>(static_cast<t>(flags) & ~static_cast<t>(f));
        */
    }
    
    pub fn to_strings(&mut self, flags: NetPermissionFlags) -> Vec<String> {
        
        todo!();
        /*
            std::vector<std::string> strings;
        if (NetPermissions::HasFlag(flags, NetPermissionFlags::BloomFilter)) strings.push_back("bloomfilter");
        if (NetPermissions::HasFlag(flags, NetPermissionFlags::NoBan)) strings.push_back("noban");
        if (NetPermissions::HasFlag(flags, NetPermissionFlags::ForceRelay)) strings.push_back("forcerelay");
        if (NetPermissions::HasFlag(flags, NetPermissionFlags::Relay)) strings.push_back("relay");
        if (NetPermissions::HasFlag(flags, NetPermissionFlags::Mempool)) strings.push_back("mempool");
        if (NetPermissions::HasFlag(flags, NetPermissionFlags::Download)) strings.push_back("download");
        if (NetPermissions::HasFlag(flags, NetPermissionFlags::Addr)) strings.push_back("addr");
        return strings;
        */
    }
}

///------------------------
#[derive(Clone)]
pub struct NetWhitebindPermissions {
    pub base:    NetPermissions,
    pub service: Service,
}

impl NetWhitebindPermissions {

    pub fn try_parse(&mut self, 
        str_:   &String,
        output: &mut NetWhitebindPermissions,
        error:  &mut BilingualStr) -> bool {
        
        todo!();
        /*
            NetPermissionFlags flags;
        size_t offset;
        if (!TryParsePermissionFlags(str, flags, offset, error)) return false;

        const std::string strBind = str.substr(offset);
        CService addrBind;
        if (!Lookup(strBind, addrBind, 0, false)) {
            error = ResolveErrMsg("whitebind", strBind);
            return false;
        }
        if (addrBind.GetPort() == 0) {
            error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
            return false;
        }

        output.m_flags = flags;
        output.m_service = addrBind;
        error = Untranslated("");
        return true;
        */
    }
}

///------------------------
#[derive(Clone)]
pub struct NetWhitelistPermissions {
    pub base:   NetPermissions,
    pub subnet: SubNet,
}

impl NetWhitelistPermissions {

    pub fn try_parse(&mut self, 
        str_:   &String,
        output: &mut NetWhitelistPermissions,
        error:  &mut BilingualStr) -> bool {
        
        todo!();
        /*
            NetPermissionFlags flags;
        size_t offset;
        if (!TryParsePermissionFlags(str, flags, offset, error)) return false;

        const std::string net = str.substr(offset);
        CSubNet subnet;
        LookupSubNet(net, subnet);
        if (!subnet.IsValid()) {
            error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
            return false;
        }

        output.m_flags = flags;
        output.m_subnet = subnet;
        error = Untranslated("");
        return true;
        */
    }
}

//-------------------------------------------[.cpp/bitcoin/src/net_permissions.cpp]

lazy_static!{
    static ref NET_PERMISSIONS_DOC: Vec<&'static str> = vec!{
        "bloomfilter (allow requesting BIP37 filtered blocks and transactions)",
        "noban (do not ban for misbehavior; implies download)",
        "forcerelay (relay transactions that are already in the mempool; implies relay)",
        "relay (relay even in -blocksonly mode, and unlimited transaction announcements)",
        "mempool (allow requesting BIP35 mempool contents)",
        "download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)",
        "addr (responses to GETADDR avoid hitting the cache and contain random records with the most up-to-date info)"
    };
}

/**
   Parse the following format:
   "perm1,perm2@xxxxxx"
  */
pub fn try_parse_permission_flags(
        str_:   &String,
        output: &mut NetPermissionFlags,
        readen: &mut usize,
        error:  &mut BilingualStr) -> bool {
    
    todo!();
        /*
            NetPermissionFlags flags = NetPermissionFlags::None;
        const auto atSeparator = str.find('@');

        // if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
        if (atSeparator == std::string::npos) {
            NetPermissions::AddFlag(flags, NetPermissionFlags::Implicit);
            readen = 0;
        }
        // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
        else {
            readen = 0;
            // permissions == perm1,perm2
            const auto permissions = str.substr(0, atSeparator);
            while (readen < permissions.length()) {
                const auto commaSeparator = permissions.find(',', readen);
                const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
                // permission == perm1
                const auto permission = permissions.substr(readen, len);
                readen += len; // We read "perm1"
                if (commaSeparator != std::string::npos) readen++; // We read ","

                if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, NetPermissionFlags::BloomFilter);
                else if (permission == "noban") NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);
                else if (permission == "forcerelay") NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay);
                else if (permission == "mempool") NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);
                else if (permission == "download") NetPermissions::AddFlag(flags, NetPermissionFlags::Download);
                else if (permission == "all") NetPermissions::AddFlag(flags, NetPermissionFlags::All);
                else if (permission == "relay") NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);
                else if (permission == "addr") NetPermissions::AddFlag(flags, NetPermissionFlags::Addr);
                else if (permission.length() == 0); // Allow empty entries
                else {
                    error = strprintf(_("Invalid P2P permission: '%s'"), permission);
                    return false;
                }
            }
            readen++;
        }

        output = flags;
        error = Untranslated("");
        return true;
        */
}