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
crate::ix!();

impl AddrManInner {

    pub fn select(&self, new_only: bool) -> (Address,i64) {
        
        if self.random.borrow().is_empty() {
            return Default::default();
        }

        if new_only && self.n_new == 0 {
            return Default::default();
        }

        // Use a 50% chance for choosing between
        // tried and new table entries.
        if !new_only && (self.n_tried > 0 && (self.n_new == 0 || self.insecure_rand.borrow_mut().randbool() == false)) {

            //  use a tried node
            let mut chance_factor: f64 = 1.0;

            loop {

                // Pick a tried bucket, and an
                // initial position in that
                // bucket.
                let n_kbucket:     usize = self.insecure_rand.borrow_mut().randrange(ADDRMAN_TRIED_BUCKET_COUNT as u64).try_into().unwrap();
                let n_kbucket_pos: usize = self.insecure_rand.borrow_mut().randrange(ADDRMAN_BUCKET_SIZE as u64).try_into().unwrap();

                // Iterate over the positions of
                // that bucket, starting at the
                // initial one, and looping
                // around.
                let mut i = 0;

                for i in 0..ADDRMAN_BUCKET_SIZE {

                    if self.vv_tried[n_kbucket][(n_kbucket_pos + i) % ADDRMAN_BUCKET_SIZE] != -1 {
                        break;
                    }
                }

                // If the bucket is entirely
                // empty, start over with
                // a (likely) different one.
                if i == ADDRMAN_BUCKET_SIZE {
                    continue;
                }

                //  Find the entry to return.
                let n_id: i32 = self.vv_tried[n_kbucket][(n_kbucket_pos + i) % ADDRMAN_BUCKET_SIZE];;

                let it_found = self.map_info.get(&n_id);

                assert!(it_found.is_some());

                let info: &AddrInfo = it_found.unwrap();

                // With probability GetChance()
                // * fChanceFactor, return the
                // entry.
                if (self.insecure_rand.borrow_mut().randbits(30) as f64) < chance_factor * info.get_chance(None) * ((1 << 30) as f64) {

                    log_print!(
                        bc_log::addrman, 
                        "Selected %s from tried\n", 
                        info.to_string()
                    );

                    return (info.address.clone(), info.n_last_try);
                }

                // Otherwise start over with
                // a (likely) different bucket,
                // and increased chance factor.
                chance_factor *= 1.2;
            }
        } else {

            //  use a new node
            let mut chance_factor: f64 = 1.0;;

            loop {

                // Pick a new bucket, and an
                // initial position in that
                // bucket.
                let n_ubucket:     usize = self.insecure_rand.borrow_mut().randrange(ADDRMAN_NEW_BUCKET_COUNT as u64).try_into().unwrap();
                let n_ubucket_pos: usize = self.insecure_rand.borrow_mut().randrange(ADDRMAN_BUCKET_SIZE as u64).try_into().unwrap();

                // Iterate over the positions of
                // that bucket, starting at the
                // initial one, and looping
                // around.
                let mut i = 0;

                for i in 0..ADDRMAN_BUCKET_SIZE {
                    if self.vv_new[n_ubucket][(n_ubucket_pos + i) % ADDRMAN_BUCKET_SIZE] != -1 {
                        break;
                    }
                }

                // If the bucket is entirely
                // empty, start over with
                // a (likely) different one.
                if i == ADDRMAN_BUCKET_SIZE {
                    continue;
                }

                //  Find the entry to return.
                let n_id: usize = {
                    let idx: usize = (n_ubucket_pos + i) % ADDRMAN_BUCKET_SIZE;
                    self.vv_new[n_ubucket][idx].try_into().unwrap()
                };

                let it_found = self.map_info.get(&n_id.try_into().unwrap());

                assert!(it_found.is_some());

                let info: &AddrInfo = it_found.unwrap();

                // With probability GetChance()
                // * fChanceFactor, return the
                // entry.
                if (self.insecure_rand.borrow_mut().randbits(30) as f64) < chance_factor * info.get_chance(None) * ((1 << 30) as f64) {

                    log_print!(
                        bc_log::addrman, 
                        "Selected %s from new\n", 
                        info.to_string()
                    );

                    return (info.address.clone(), info.n_last_try);
                }

                // Otherwise start over with
                // a (likely) different bucket,
                // and increased chance factor.
                chance_factor *= 1.2;
            }
        }
    }
}