diff --git a/dht/dht-query.cpp b/dht/dht-query.cpp index e0e878d0..08579415 100644 --- a/dht/dht-query.cpp +++ b/dht/dht-query.cpp @@ -149,6 +149,23 @@ void DhtQueryFindValue::send_one_query(adnl::AdnlNodeIdShort id) { td::Timestamp::in(2.0 + td::Random::fast(0, 20) * 0.1), std::move(B)); } +void DhtQueryFindValue::send_one_query_nodes(adnl::AdnlNodeIdShort id) { + auto P = create_serialize_tl_object(get_key().tl(), get_k()); + td::BufferSlice B; + if (client_only_) { + B = std::move(P); + } else { + B = create_serialize_tl_object_suffix(P.as_slice(), self_.tl()); + } + + auto Pr = td::PromiseCreator::lambda([SelfId = actor_id(this), dst = id](td::Result R) { + td::actor::send_closure(SelfId, &DhtQueryFindValue::on_result_nodes, std::move(R), dst); + }); + + td::actor::send_closure(adnl_, &adnl::Adnl::send_query, get_src(), id, "dht findValue", std::move(Pr), + td::Timestamp::in(2.0 + td::Random::fast(0, 20) * 0.1), std::move(B)); +} + void DhtQueryFindValue::on_result(td::Result R, adnl::AdnlNodeIdShort dst) { if (R.is_error()) { VLOG(DHT_INFO) << this << ": failed find value query " << get_src() << "->" << dst << ": " << R.move_as_error(); @@ -164,6 +181,7 @@ void DhtQueryFindValue::on_result(td::Result R, adnl::AdnlNodeI } bool need_stop = false; + bool send_get_nodes = false; auto A = Res.move_as_ok(); ton_api::downcast_call( @@ -180,17 +198,41 @@ void DhtQueryFindValue::on_result(td::Result R, adnl::AdnlNodeI VLOG(DHT_WARNING) << this << ": received value for bad key on find value query from " << dst; return; } + if (!value.check_is_acceptable()) { + send_get_nodes = true; + return; + } promise_.set_value(std::move(value)); need_stop = true; }, [&](ton_api::dht_valueNotFound &v) { add_nodes(DhtNodesList{std::move(v.nodes_)}); })); if (need_stop) { stop(); + } else if (send_get_nodes) { + send_one_query_nodes(dst); } else { finish_query(); } } +void DhtQueryFindValue::on_result_nodes(td::Result R, adnl::AdnlNodeIdShort dst) { + if (R.is_error()) { + VLOG(DHT_INFO) << this << ": failed find nodes query " << get_src() << "->" << dst << ": " << R.move_as_error(); + finish_query(); + return; + } + auto Res = fetch_tl_object(R.move_as_ok(), true); + if (Res.is_error()) { + VLOG(DHT_WARNING) << this << ": dropping incorrect answer on dht.findNodes query from " << dst << ": " + << Res.move_as_error(); + finish_query(); + return; + } + auto r = Res.move_as_ok(); + add_nodes(DhtNodesList{create_tl_object(std::move(r->nodes_))}); + finish_query(); +} + void DhtQueryFindValue::finish(DhtNodesList list) { promise_.set_error(td::Status::Error(ErrorCode::notready, "dht key not found")); } diff --git a/dht/dht-query.hpp b/dht/dht-query.hpp index fe2f2d70..491bf61d 100644 --- a/dht/dht-query.hpp +++ b/dht/dht-query.hpp @@ -129,7 +129,9 @@ class DhtQueryFindValue : public DhtQuery { , promise_(std::move(promise)) { } void send_one_query(adnl::AdnlNodeIdShort id) override; + void send_one_query_nodes(adnl::AdnlNodeIdShort id); void on_result(td::Result R, adnl::AdnlNodeIdShort dst); + void on_result_nodes(td::Result R, adnl::AdnlNodeIdShort dst); void finish(DhtNodesList list) override; std::string get_name() const override { return "find value"; diff --git a/dht/dht-types.cpp b/dht/dht-types.cpp index 89949bc1..118df2a8 100644 --- a/dht/dht-types.cpp +++ b/dht/dht-types.cpp @@ -209,6 +209,10 @@ td::Status DhtValue::check() const { return key_.update_rule()->check_value(*this); } +bool DhtValue::check_is_acceptable() const { + return key_.update_rule()->check_is_acceptable(*this); +} + DhtKeyId DhtValue::key_id() const { return key_.key().compute_key_id(); } @@ -360,6 +364,21 @@ td::Status DhtUpdateRuleOverlayNodes::update_value(DhtValue &value, DhtValue &&n return td::Status::OK(); } +bool DhtUpdateRuleOverlayNodes::check_is_acceptable(const ton::dht::DhtValue &value) { + auto F = fetch_tl_object(value.value().clone_as_buffer_slice(), true); + if (F.is_error()) { + return false; + } + auto L = F.move_as_ok(); + auto now = td::Clocks::system(); + for (auto &node : L->nodes_) { + if (node->version_ + 600 > now) { + return true; + } + } + return false; +} + tl_object_ptr DhtUpdateRuleOverlayNodes::tl() const { return create_tl_object(); } diff --git a/dht/dht-types.h b/dht/dht-types.h index 75efee55..45657d45 100644 --- a/dht/dht-types.h +++ b/dht/dht-types.h @@ -119,6 +119,9 @@ class DhtUpdateRule { virtual td::Status check_value(const DhtValue &value) = 0; virtual td::Status update_value(DhtValue &value, DhtValue &&new_value) = 0; virtual bool need_republish() const = 0; + virtual bool check_is_acceptable(const DhtValue &value) { + return true; + } virtual tl_object_ptr tl() const = 0; static td::Result> create(tl_object_ptr obj); }; @@ -210,6 +213,7 @@ class DhtValue { void update_signature(td::BufferSlice signature); void update_signature(td::SharedSlice signature); td::Status check() const; + bool check_is_acceptable() const; DhtKeyId key_id() const; @@ -249,6 +253,7 @@ class DhtUpdateRuleOverlayNodes : public DhtUpdateRule { bool need_republish() const override { return false; } + bool check_is_acceptable(const DhtValue &value) override; tl_object_ptr tl() const override; static td::Result> create(); };