Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions adnl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ set(ADNL_SOURCE
set(ADNL_TEST_SOURCE
adnl-test-loopback-implementation.h
adnl-test-loopback-implementation.cpp
adnl-test-network.h
adnl-test-network.cpp
)

set(ADNL_PROXY_SOURCE
Expand Down
91 changes: 91 additions & 0 deletions adnl/adnl-test-network.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2026, TON CORE TECHNOLOGIES CO. L.L.C
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "adnl-test-network.h"

#include "adnl-test-loopback-implementation.h"
#include "td/utils/port/path.h"

namespace ton::adnl {

void TestNetworkNode::install_callback(std::unique_ptr<Callback> callback) {
CHECK(!callback_);
callback_ = std::move(callback);
}

void TestNetworkNode::add_self_addr(td::IPAddress, AdnlCategoryMask, td::uint32) {
}

void TestNetworkNode::add_proxy_addr(td::IPAddress, td::uint16, std::shared_ptr<AdnlProxy>, AdnlCategoryMask,
td::uint32) {
}

void TestNetworkNode::send_udp_packet(AdnlNodeIdShort, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, td::uint32,
td::BufferSlice data) {
router_->route_packet(dst_id, dst_addr, std::move(data));
}

void TestNetworkNode::set_local_id_category(AdnlNodeIdShort, td::uint8) {
}

void TestNetworkNode::deliver(td::IPAddress addr, td::BufferSlice data) {
CHECK(callback_);
AdnlCategoryMask m;
m[0] = true;
callback_->receive_packet(addr, std::move(m), std::move(data));
}

TestNetwork::TestNetwork(const std::string& db_root) : db_root_(db_root) {
td::rmrf(db_root_).ignore();
td::mkdir(db_root_).ensure();
}

TestNetwork::~TestNetwork() {
nodes_.clear();
td::rmrf(db_root_).ignore();
}

TestNetwork::Node& TestNetwork::add_node() {
PrivateKey pk{privkeys::Ed25519::random()};
auto node_db = db_root_ + "/node-" + std::to_string(nodes_.size());
td::mkdir(node_db).ensure();

auto node = std::make_unique<Node>(pk.compute_public_key(), node_db);

node->keyring = keyring::Keyring::create(node_db);
td::actor::send_closure(node->keyring, &keyring::Keyring::add_key, std::move(pk), true, [](td::Result<>) {});

node->network_manager = td::actor::create_actor<TestNetworkNode>("net", this);
node->adnl = Adnl::create(node_db, node->keyring.get());
td::actor::send_closure(node->adnl, &Adnl::register_network_manager, node->network_manager.get());

auto addr = generate_dummy_addr_list();
td::actor::send_closure(node->adnl, &Adnl::add_id, node->adnl_full, addr, static_cast<td::uint8>(0));

routing_table_[node->adnl_short] = node->network_manager.get();

auto& ref = *node;
nodes_.push_back(std::move(node));
return ref;
}

void TestNetwork::connect(Node& a, Node& b) {
auto addr = generate_dummy_addr_list();
td::actor::send_closure(a.adnl, &Adnl::add_peer, a.adnl_short, b.adnl_full, addr);
td::actor::send_closure(b.adnl, &Adnl::add_peer, b.adnl_short, a.adnl_full, addr);
}

void TestNetwork::route_packet(AdnlNodeIdShort dst_id, td::IPAddress dst_addr, td::BufferSlice data) {
auto it = routing_table_.find(dst_id);
if (it != routing_table_.end()) {
td::actor::send_closure(it->second, &TestNetworkNode::deliver, dst_addr, std::move(data));
}
}

AdnlAddressList TestNetwork::generate_dummy_addr_list() {
return TestLoopbackNetworkManager::generate_dummy_addr_list();
}

} // namespace ton::adnl
77 changes: 77 additions & 0 deletions adnl/adnl-test-network.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2026, TON CORE TECHNOLOGIES CO. L.L.C
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once

#include <map>

#include "adnl/adnl-network-manager.h"
#include "adnl/adnl.h"

namespace ton::adnl {

class TestNetworkNode : public AdnlNetworkManager {
public:
class Router {
public:
virtual ~Router() = default;
virtual void route_packet(AdnlNodeIdShort dst_id, td::IPAddress dst_addr, td::BufferSlice data) = 0;
};

explicit TestNetworkNode(Router* router) : router_(router) {
}

void install_callback(std::unique_ptr<Callback> callback) override;
void add_self_addr(td::IPAddress addr, AdnlCategoryMask cat_mask, td::uint32 priority) override;
void add_proxy_addr(td::IPAddress addr, td::uint16 local_port, std::shared_ptr<AdnlProxy> proxy,
AdnlCategoryMask cat_mask, td::uint32 priority) override;
void send_udp_packet(AdnlNodeIdShort src_id, AdnlNodeIdShort dst_id, td::IPAddress dst_addr, td::uint32 priority,
td::BufferSlice data) override;
void set_local_id_category(AdnlNodeIdShort id, td::uint8 cat) override;

void deliver(td::IPAddress addr, td::BufferSlice data);

private:
Router* router_;
std::unique_ptr<Callback> callback_;
};

// A test network that connects multiple independent ADNL nodes.
// Each call to add_node() creates a fresh AdnlNetworkManager + Adnl pair.
class TestNetwork : public TestNetworkNode::Router {
public:
struct Node {
td::actor::ActorOwn<keyring::Keyring> keyring;
td::actor::ActorOwn<TestNetworkNode> network_manager;
td::actor::ActorOwn<Adnl> adnl;
PublicKey pub;
AdnlNodeIdFull adnl_full;
AdnlNodeIdShort adnl_short;
std::string db_root;

explicit Node(PublicKey pub_key, std::string db)
: pub(std::move(pub_key)), adnl_full(pub), adnl_short(pub.compute_short_id()), db_root(std::move(db)) {
}
};

explicit TestNetwork(const std::string& db_root);
~TestNetwork();

Node& add_node();

// Introduce two nodes so they know each other's ADNL addresses.
void connect(Node& a, Node& b);

void route_packet(AdnlNodeIdShort dst_id, td::IPAddress dst_addr, td::BufferSlice data) override;

static AdnlAddressList generate_dummy_addr_list();

private:
std::string db_root_;
std::vector<std::unique_ptr<Node>> nodes_;
std::map<AdnlNodeIdShort, td::actor::ActorId<TestNetworkNode>> routing_table_;
};

} // namespace ton::adnl
41 changes: 31 additions & 10 deletions overlay/broadcast-twostep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,24 @@ struct BroadcastTwostepDataFec {
td::BufferSlice extra;
};

static void gc_oldest_incomplete_broadcast(
OverlayImpl *overlay, td::ListNode &lru,
std::map<Overlay::BroadcastHash, std::unique_ptr<BroadcastTwostep>> &broadcasts, td::Slice reason) {
auto bcast = static_cast<BroadcastTwostep *>(lru.prev);
CHECK(bcast);
auto broadcast_id = bcast->broadcast_id;

if (!bcast->delivered) {
FLOG(INFO) {
sb << "twostep " << reason << " receiver " << *bcast << " decoded=false elapsed=" << bcast->debug.elapsed()
<< " ";
bcast->debug.print_senders(sb);
};
}
CHECK(broadcasts.erase(broadcast_id));
overlay->register_delivered_broadcast(broadcast_id);
}

BroadcastsTwostep::BroadcastsTwostep() = default;

BroadcastsTwostep::~BroadcastsTwostep() = default;
Expand Down Expand Up @@ -406,6 +424,14 @@ td::actor::Task<> BroadcastsTwostep::process_broadcast(OverlayImpl *overlay, adn
}
}
if (it == broadcasts_.end()) {
auto max_fec_bcasts = static_cast<size_t>(overlay->max_fec_bcasts());
if (max_fec_bcasts == 0) {
co_return td::Status::Error(ErrorCode::error, "twostep cache disabled");
}
gc(overlay);
while (broadcasts_.size() >= max_fec_bcasts) {
gc_oldest_incomplete_broadcast(overlay, lru_, broadcasts_, "GC_MAX_FEC_BCASTS");
}
CO_TRY(overlay->get_broadcasts_limiter(src_keyhash, cert.get()).try_register_broadcast(data_size));
td::Result<std::unique_ptr<td::raptorq::Decoder>> R;
if (part_size == 0 ||
Expand Down Expand Up @@ -465,16 +491,11 @@ void BroadcastsTwostep::gc(OverlayImpl *overlay) {
if (bcast->date > td::Clocks::system() - 25) { // see OverlayImpl::check_date
break;
}
auto broadcast_id = bcast->broadcast_id;

if (!bcast->delivered) {
FLOG(INFO) {
sb << "twostep GC_INCOMPLETE receiver " << *bcast << " decoded=false elapsed=" << bcast->debug.elapsed() << " ";
bcast->debug.print_senders(sb);
};
}
CHECK(broadcasts_.erase(broadcast_id));
overlay->register_delivered_broadcast(broadcast_id);
gc_oldest_incomplete_broadcast(overlay, lru_, broadcasts_, "GC_INCOMPLETE");
}
auto max_fec_bcasts = static_cast<size_t>(overlay->max_fec_bcasts());
while (broadcasts_.size() > max_fec_bcasts) {
gc_oldest_incomplete_broadcast(overlay, lru_, broadcasts_, "GC_MAX_FEC_BCASTS");
}
}

Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
add_library(td-test-main test-td-main.cpp)
target_link_libraries(td-test-main PRIVATE tdutils)

add_subdirectory(overlay)
add_subdirectory(tdactor)
add_subdirectory(tdutils)
add_subdirectory(tonlib)
Expand Down
12 changes: 12 additions & 0 deletions test/overlay/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
add_executable(test-overlay-manager test-overlay-manager.cpp)
target_link_libraries(test-overlay-manager PRIVATE
overlay
tdutils
tdactor
adnl
adnltest
tl_api
dht
td-test-main
)
ton_test(test-overlay-manager)
Loading