2
This file is part of TON Blockchain Library.
4
TON Blockchain Library is free software: you can redistribute it and/or modify
5
it under the terms of the GNU Lesser General Public License as published by
6
the Free Software Foundation, either version 2 of the License, or
7
(at your option) any later version.
9
TON Blockchain Library 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 Lesser General Public License for more details.
14
You should have received a copy of the GNU Lesser General Public License
15
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
17
Copyright 2017-2020 Telegram Systems LLP
19
#include "td/utils/tl_storers.h"
20
#include "td/utils/crypto.h"
21
#include "td/utils/tl_parsers.h"
22
#include "td/utils/Random.h"
24
#include "td/utils/format.h"
26
#include "keys/encryptor.h"
28
#include "auto/tl/ton_api.hpp"
30
#include "dht-remote-node.hpp"
31
#include "dht-bucket.hpp"
40
void DhtBucket::get_nearest_nodes(DhtKeyId id, td::uint32 bit, DhtNodesList &vec, td::uint32 k) {
41
if (active_nodes_.size() == 0) {
44
std::map<DhtKeyId, size_t> list;
46
for (size_t i = 0; i < active_nodes_.size(); i++) {
47
auto &node = active_nodes_[i];
49
list.emplace(id ^ node->get_key(), i);
53
for (auto it = list.begin(); it != list.end() && vec.size() < k; it++) {
54
vec.push_back(active_nodes_[it->second]->get_node());
58
td::uint32 DhtBucket::active_cnt() {
60
for (auto &node : active_nodes_) {
68
td::Status DhtBucket::add_full_node(DhtKeyId id, DhtNode newnode, td::actor::ActorId<adnl::Adnl> adnl,
69
adnl::AdnlNodeIdShort self_id, td::int32 our_network_id, bool set_active) {
70
for (auto &node : active_nodes_) {
71
if (node && node->get_key() == id) {
73
return node->receive_ping(std::move(newnode), adnl, self_id);
75
return node->update_value(std::move(newnode), adnl, self_id);
79
for (size_t i = 0; i < backup_nodes_.size(); ++i) {
80
auto &node = backup_nodes_[i];
81
if (node && node->get_key() == id) {
83
TRY_STATUS(node->receive_ping(std::move(newnode), adnl, self_id));
84
if (node->is_ready()) {
87
return td::Status::OK();
89
return node->update_value(std::move(newnode), adnl, self_id);
94
TRY_RESULT_PREFIX(N, DhtRemoteNode::create(std::move(newnode), max_missed_pings_, our_network_id),
95
"failed to add new node: ");
97
for (auto &node : active_nodes_) {
98
if (node == nullptr) {
100
node->receive_ping();
101
return td::Status::OK();
106
size_t idx = select_backup_node_to_drop();
107
if (idx < backup_nodes_.size()) {
108
backup_nodes_[idx] = std::move(N);
110
return td::Status::OK();
113
size_t DhtBucket::select_backup_node_to_drop() const {
114
size_t result = backup_nodes_.size();
115
for (size_t idx = 0; idx < backup_nodes_.size(); ++idx) {
116
const auto &node = backup_nodes_[idx];
117
if (node == nullptr) {
120
if (node->ready_from() == 0 && node->failed_from() + 60 < td::Time::now_cached()) {
121
if (result == backup_nodes_.size() || node->failed_from() < backup_nodes_[result]->failed_from()) {
129
void DhtBucket::receive_ping(DhtKeyId id, DhtNode result, td::actor::ActorId<adnl::Adnl> adnl,
130
adnl::AdnlNodeIdShort self_id) {
131
for (auto &node : active_nodes_) {
132
if (node && node->get_key() == id) {
133
node->receive_ping(std::move(result), adnl, self_id);
137
for (size_t i = 0; i < backup_nodes_.size(); i++) {
138
auto &node = backup_nodes_[i];
139
if (node && node->get_key() == id) {
140
node->receive_ping(std::move(result), adnl, self_id);
141
if (node->is_ready()) {
149
void DhtBucket::demote_node(size_t idx) {
150
size_t new_idx = select_backup_node_to_drop();
151
if (new_idx < backup_nodes_.size()) {
152
backup_nodes_[new_idx] = std::move(active_nodes_[idx]);
154
active_nodes_[idx] = nullptr;
157
void DhtBucket::promote_node(size_t idx) {
158
CHECK(backup_nodes_[idx]);
159
for (auto &node : active_nodes_) {
160
if (node == nullptr) {
161
node = std::move(backup_nodes_[idx]);
164
CHECK(node->is_ready());
168
void DhtBucket::check(bool client_only, td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<DhtMember> dht,
169
adnl::AdnlNodeIdShort src) {
170
size_t have_space = 0;
171
for (size_t i = 0; i < active_nodes_.size(); i++) {
172
auto &node = active_nodes_[i];
173
if (node && td::Time::now_cached() - node->last_ping_at() > node->ping_interval()) {
174
node->send_ping(client_only, adnl, dht, src);
175
if (node->ready_from() == 0) {
179
if (node == nullptr) {
183
for (size_t i = 0; i < backup_nodes_.size(); i++) {
184
auto &node = backup_nodes_[i];
185
if (node && td::Time::now_cached() - node->last_ping_at() > node->ping_interval()) {
186
node->send_ping(client_only, adnl, dht, src);
188
if (node && have_space > 0 && node->is_ready()) {
195
void DhtBucket::dump(td::StringBuilder &sb) const {
198
for (auto &node : active_nodes_) {
200
sb << " " << node->get_key() << "\n";
204
for (auto &node : backup_nodes_) {
206
sb << " " << node->get_key() << "\n";
211
DhtNodesList DhtBucket::export_nodes() const {
213
for (auto &node : active_nodes_) {
215
list.push_back(node->get_node());
218
for (auto &node : backup_nodes_) {
220
list.push_back(node->get_node());
223
if (list.size() > k_) {
224
list.list().resize(k_);