1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

initial commit

This commit is contained in:
initial commit 2019-09-07 14:03:22 +04:00 committed by vvaltman
commit c2da007f40
1610 changed files with 398047 additions and 0 deletions

2053
test/ed25519_crypto.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,207 @@
#!/bin/python3.7
import subprocess
import json
import pprint
import base64
import hashlib
configname="server.list"
binary="../ton-build/generate-random-id"
ids=[]
catchains=[]
public_overlays=[]
def ip2str(ip):
b = ip.split(".")
v = (int(b[0]) << 24) + (int(b[1]) << 16) + (int(b[2]) << 8) + int(b[3])
if (v >= (1 << 31)):
return '-' + str((1 << 32) - v)
else:
return str(v)
def get_addr_list(node):
return '{"@type":"adnl.addressList","version":0,"addrs":[{"@type":"adnl.address.udp","ip":'+ \
ip2str(node['ip'])+',"port":'+node['port']+'}]}'
def generate_dht_node(node):
global binary
addr_list = get_addr_list(node)
r = subprocess.run([binary, '-k', node['spk'], '-a', addr_list, '-m', 'dht'], capture_output=True)
s = r.stdout.decode("utf-8").split("\n")
return json.loads(s[0])
def add_id(s):
global binary
if len(s) < 1 or s[0] == '#':
return
t = s.split(" ")
assert(len(t) >= 3)
ip = t[0]
port = t[1]
pk = t[2]
options = t[3:]
pub = '-'
short = '-'
rand = None
spk = pk
if (pk[0] != '-'):
r = subprocess.run([binary, '-k', pk, '-m', 'id'], capture_output=True)
s = r.stdout.decode("utf-8").split("\n")
pk = json.loads(pk)
pub = json.loads(s[1])
short = json.loads(s[2])
if '+dhtstatic' in options:
if not '+dht' in options:
options.append('+dht')
else:
if '+dhtstatic' in options:
print("cannot use dht static on random node")
sys.exit(2)
if any(opt.startswith('+catchain') for opt in options):
print("cannot use catchain on random node")
sys.exit(2)
rand=int(pk[1:])
global ids
if rand == None:
ids.append({'ip' : ip, 'port' : port, 'options' : options, 'pk' : pk, 'spk' : spk, 'pub' : pub, 'short' : short, 'rand' : rand})
else:
for x in range(0, rand):
r = subprocess.run([binary, '-m', 'id'], capture_output=True)
s = r.stdout.decode("utf-8").split("\n")
pk = json.loads(s[0])
pub = json.loads(s[1])
short = json.loads(s[2])
ids.append({'ip' : ip, 'port' : port, 'options' : options, 'pk' : pk, 'spk' : spk, 'pub' : pub, 'short' : short, 'rand' : None})
def readconfig(name):
with open(name) as f:
for s in f.readlines():
add_id(s.strip())
def generate_global_config():
global ids
config={'@type':'config.global'}
dht={'@type':'dht.config.global','k':6,'a':3}
dht_nodes=[]
for node in ids:
if '+dhtstatic' in node['options']:
dht_nodes.append(generate_dht_node(node))
dht['static_nodes'] = {'@type':'dht.nodes','nodes':dht_nodes}
config['dht'] = dht
catchains = []
for x in ids:
for y in x['options']:
if y.startswith('+catchain'):
assert(x['rand'] == None)
name=y[9:]
if not name in catchains:
catchains.append(name)
cc=[]
for name in catchains:
catchain={'@type':'catchain.config.global','tag':base64.b64encode(hashlib.sha256(name.encode("utf-8")).digest()).decode("utf-8")}
catchain_nodes=[]
for node in ids:
if ('+catchain'+name) in node['options']:
catchain_nodes.append(node['pub'])
catchain['nodes'] = catchain_nodes
cc.append(catchain)
config['catchains'] = cc
liteservers=[]
for node in ids:
for opt in node['options']:
if opt.startswith('+liteserver'):
assert(node['rand'] == None)
name=opt[9:]
liteservers.append({'@type':'liteservers.config.global','ip':int(ip2str(node['ip'])), 'port':4924,'id':node['pub']})
config['liteservers'] = liteservers
validators = {"@type": "validator.config.global", "zero_state": {
"workchain" : -1,
"shard" : -9223372036854775808,
"seqno" : 0,
"root_hash": "DXduYJkakj2d+rB7Qpj2SCkjTCG7AGXAA9G7EHQEyG0=",
"file_hash": "4xASfDALy6Hk5Tg01IyBoFUepur9YJg2pg3cm0zocJk="
}}
config['validator'] = validators
with open('ton-global.config.json', 'w') as outfile:
json.dump(config, outfile, indent=2)
def generate_local_config(ip,port):
global ids
config = {'@type' : 'config.local'}
ports=[]
for node in ids:
if node['ip'] == ip and node['port'] == port:
ports.append(int(node['port']))
ports = sorted(set(ports))
config['udp_ports'] = ports
ids_config=[]
for node in ids:
if node['rand'] == None and node['ip'] == ip and node['port'] == port:
ids_config.append({'@type':'id.config.local','id':node['pk']})
config['local_ids'] = ids_config
dht_config=[]
for node in ids:
if node['ip'] == ip and node['port'] == port and ('+dht' in node['options']):
if node['rand'] == None:
dht_config.append({'@type':'dht.config.local', 'id':node['short']})
else:
cnt=node['rand']
dht_config.append({'@type':'dht.config.random.local', 'cnt':cnt})
config['dht'] = dht_config
liteservers=[]
for node in ids:
for opt in node['options']:
if opt.startswith('+liteserver') and node['ip'] == ip and node['port'] == port:
assert(node['rand'] == None)
name=opt[9:]
liteservers.append({'@type':'liteserver.config.local','port':4924,'id':node['pk']})
config['liteservers'] = liteservers
validators=[]
for node in ids:
for opt in node['options']:
if opt == '+validator' and node['ip'] == ip and node['port'] == port:
assert(node['rand'] == None)
validators.append({'@type':'validator.config.local', 'id':node['short']})
config['validators'] = validators
controlserver = {'@type':'control.config.local', 'priv':{"@type":"pk.ed25519","key":"jRbqvPhSr3/xylof9zQyeqbplvWPSIGiHSft3ovKVc4="}, \
'pub':'Fv8DAtv6nqnrHIPpmv4LGIw0D9cMoF40JXQdM2WVMQM=', 'port':(int(port) + 1000)}
config['control'] = [controlserver]
with open('ton-local.' + ip + '.' + port + '.config.json', 'w') as outfile:
json.dump(config, outfile, indent=2)
readconfig(configname)
generate_global_config()
ips=["" + node['ip'] + ":" + node['port'] for node in ids]
ips=set(ips)
for ip in ips:
b = ip.split(":")
generate_local_config(b[0], b[1])

54
test/regression-tests.ans Normal file
View file

@ -0,0 +1,54 @@
abce
Test_Bigint_main_default 0327a04f1252c37f77b6706b902ab2c3235c47738bca3f183c837a2c5d22bb6f
Test_Bitstrings_main_default a8b08af3116923c4c2a14e138d168375abd0c059f2f780d3267b294929a1110e
Test_Cells_simple_default 832502642fe4fe5db70de82681aedb7d54d7f3530e0069861fff405fe6f6cf23
Test_Fift_bug_div_default 1ac42861ce96b2896001c587f65e9afe1617db48859f19c2f4e3063a20ea60b0
Test_Fift_bug_newlize_default e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Test_Fift_contfrac_default 09ebce5c91bcb70696c6fb6981d82dc3b9e3444dab608a7a1b044c0ddd778a96
Test_Fift_test_default 4e44b3382963ec89f7b5c8f2ebd85da3bc8aebad5b49f5b11b14075061477b4d
Test_Fift_testvm2_default 4dcb0f98fd689cbdd81a3a1f937a497dd64d27ecebdcd67cf28fd6888469d93d
Test_Fift_testvm3_default 3c1b77471c5fd914ed8b5f528b9faed618e278693f5030b953ff150e543864ae
Test_Fift_testvm4_default 4dcb0f98fd689cbdd81a3a1f937a497dd64d27ecebdcd67cf28fd6888469d93d
Test_Fift_testvm4a_default 523b561d6bf2f5ebb26a755e687bfbda8e33462c98e9978119755f79a086cf5e
Test_Fift_testvm4b_default daf8567bd58f05c10bb6596cea33b63e1061fa02dd5560db18ff22f96736f0d5
Test_Fift_testvm4c_default 2bbd67831d90bceaae29546ee3a58c4d376c2e8fb6a5b8ea2eae3ab8787e063e
Test_Fift_testvm4d_default 32eee098378e64c938dea09990287a349d0d8f6aabb7360535c782a958cd5fea
Test_Fift_testvm5_default bab109acfdf626a192171d74c69c3176d661a8dedf730aea616d4997b98830f1
Test_Fift_testvm6_default dd6353c8f3f21cf62a4769ee1f3daaec46f43fd633ffb84c5d6535b120af9027
Test_Fift_testvm7_default 77f54b6c8c9a728d262e912efcc347de7014a37d08793c3adeac8b96fe063342
Test_Fift_testvm8_default 17c9e2205ccecfd8549328b4a501d07dde0336899a7a496e747e1032ad5efff9
Test_Fift_testvm_default ee4cbfec76c050b6de7877cfc39817d594cd1e175b6265b76fb642e30b940437
Test_Fift_testvmprog_default 3aeebf868c0492f2bafe339505751449e9d258bf25ea5d956efe70c6fce408ed
Test_RefInt_main_default 768493e0aef8e09a401a6d369edd1ef503a9215fb09dc460f52b27a8bde767cb
Test_VM_assert_code_not_null_default 05bc07e129181c972b976442f200de9487dee8bfb5ac53dd36ff61c5d4d4291d
Test_VM_assert_extract_minmax_key_default c352309c61bdf62ba7a0ba7280d303c88b0696fe7efa550c05feb2c662275297
Test_VM_assert_lookup_prefix_default 18e4fd70d6fa718bd352a6edf5d550a51355d4fb6f2fac58860a646c27a29bc9
Test_VM_assert_pfx_dict_lookup_default fa6e3f96b31cf2ed9a9dac6b279ec05acfedf13b8ed7b815789f167d1ed7352f
Test_VM_bigint_default feeb473a4ac51133989e1c145d0f49defa77117d2ae8b66bd7d12e3579e91b9f
Test_VM_bug_div_short_any_default f69aca6873f75d53dd37b6952151a2d858407a04589330762827dbc96d8b7c04
Test_VM_bug_exec_dict_getnear_default db314c2e25b49c1f7f044d271e225f36da546c66242a8ab12f6afae37628a81e
Test_VM_bug_stack_overflow_default 7e0e3e96ca438ac96648d569c55213aa82154cf004e80265b1c481b1c4219719
Test_VM_memory_leak_default e10dc118f3538720a16bcbd39be9a68c3ea07f76b3d2ed5719a5e866d91f0ab3
Test_VM_memory_leak_new_default fd2eec0a1d5ae49fb5ff8ba4b938fd9d0fe330be4a07b2b8be12bab249b00d90
Test_VM_memory_leak_old_default f3076ae38d14000c021597b824d2f0e51de4f00601429ec3e23cca1b32dba844
Test_VM_report3_1_default 7bc6a8e66f9a0e40cd131e9829ff36fed16b464170d27c0b365a3f549df57282
Test_VM_report3_2_default 2231bc352cf431e72a84abad2261969bd5b0ee3d9051bb7a53b69fd8ea05f951
Test_VM_report3_3_default 9416187eb0600ed247795837ca820bccaffb39841bd9d2ff625816bfbba35d6d
Test_VM_report3_4_default 11661eb00ea37c68e3483a8e048f922f73070c6da8219247663e3d6471c5c0cc
Test_VM_report3_6_default 1d7be98a8b07f803e80168247459e620ce4b91df634ad896e878d21a3ed757c0
Test_VM_report3_int_overflow_1_default a0c2414ca2c9672d54409ee375a6aad6e2233306eaa3dfd33a82de3c90bba3ba
Test_VM_report3_int_overflow_2_default 01cd461802e532a6830705ad50eaa1760278737ff7beeb654e3c59ceb4aa8e2e
Test_VM_report3_loop_1_default b28b35d057a1b4fa2282d6f422ecd822b18cc4344733d923ef7b002f64bc4d72
Test_VM_report3_loop_2_default 9f8236535902b04e403d412fcf1f79e64d0f2eb25b3cc014b7d61b2d7a34b9ef
Test_VM_report3_loop_3_default 7ee05ea553c48a2476035817b9d860f614a355927c9e011b2f824dc6e5f7b0cf
Test_VM_report3_loop_4_default 4b6c2f65fda3c9e9c6660b6cbbcb1b2103c5b52870cb5daa8876bbed0ca9bbc9
Test_VM_report3_loop_5_default 0d5d504884172ef8513757d7f6b2a3870dbd28efd5960857441c032e1c67d836
Test_VM_report3_loop_6_default 5c35b92144debdb61b2020d690669bffbdd96f75ecde827fd0c75c05da22b5a0
Test_VM_report3_qnot_default dc280444c7e3886cc3412f96f44c803c45287a07fcb9c638643e21bcdfe3905d
Test_VM_simple_default f6733549069427c2beb1a85ee25635540e27aa68cb8ad101d8435e19afeae862
Test_VM_unhandled_exception_1_default 0abe2740dd3b6a6b91eb67fee573f638086fecc72653d2d81c956782186b5d78
Test_VM_unhandled_exception_4_default 412cbfe13745fde55cdcc5e41d7b15ba4d09f0e723f8e4421ae0b7066ca07b8f
Test_VM_unhandled_exception_5_default d760e540cd9c200c207f71c540cdaf06d11c96e32ec19860b9c1046cb1e38855
Test_base64_main_default e90d541bd810871c4a81e162f1fffb555024b72807cb895414d16bc11494b789
Test_bits256_scan_main_default 3ec7434e1cabc8e08eb2e79064e67747ffbfed177473c7873b88c144a7ed6f42
Test_crc16_main_default 84abc15310c7d8fe3344a73e97ad3c8d2e23645e1f8e67f8c8756bdf5012ebd6

322
test/test-adnl.cpp Normal file
View file

@ -0,0 +1,322 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl-network-manager.h"
#include "adnl/adnl.h"
#include "adnl/adnl-test-loopback-implementation.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include <memory>
#include <set>
#include <chrono>
#include <thread>
int main() {
SET_VERBOSITY_LEVEL(verbosity_INFO);
std::string db_root_ = "tmp-ee";
td::mkdir(db_root_).ensure();
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<ton::keyring::Keyring> keyring;
td::actor::ActorOwn<ton::adnl::TestLoopbackNetworkManager> network_manager;
td::actor::ActorOwn<ton::adnl::Adnl> adnl;
ton::adnl::AdnlNodeIdShort src;
ton::adnl::AdnlNodeIdShort dst;
td::actor::Scheduler scheduler({7});
scheduler.run_in_context([&] {
keyring = ton::keyring::Keyring::create(db_root_);
network_manager = td::actor::create_actor<ton::adnl::TestLoopbackNetworkManager>("test network manager");
adnl = ton::adnl::Adnl::create(db_root_, keyring.get());
td::actor::send_closure(adnl, &ton::adnl::Adnl::register_network_manager, network_manager.get());
auto pk1 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub1 = pk1.compute_public_key();
src = ton::adnl::AdnlNodeIdShort{pub1.compute_short_id()};
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {});
auto pk2 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub2 = pk2.compute_public_key();
dst = ton::adnl::AdnlNodeIdShort{pub2.compute_short_id()};
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk2), true, [](td::Unit) {});
auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list();
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr);
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub2}, addr);
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_peer, src, ton::adnl::AdnlNodeIdFull{pub2}, addr);
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, src, true, false);
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, dst, false, true);
});
{
auto a = ton::adnl::Adnl::adnl_start_time();
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
CHECK(a == ton::adnl::Adnl::adnl_start_time());
}
{
auto obj = ton::create_tl_object<ton::ton_api::adnl_proxy_fast>(td::BufferSlice{"1234"});
auto R = ton::adnl::AdnlProxy::create(*obj.get());
R.ensure();
auto P = R.move_as_ok();
td::BufferSlice z{64};
td::Random::secure_bytes(z.as_slice());
auto packet = P->encrypt(ton::adnl::AdnlProxy::Packet{2, 3, z.clone()});
td::Bits256 x;
x.as_slice().copy_from(packet.as_slice().truncate(32));
CHECK(x.is_zero());
auto packet2R = P->decrypt(std::move(packet));
packet2R.ensure();
auto packet2 = packet2R.move_as_ok();
CHECK(packet2.ip == 2);
CHECK(packet2.port == 3);
CHECK(packet2.data.as_slice() == z.as_slice());
}
auto send_packet = [&](td::uint32 i) {
td::BufferSlice d{i};
d.as_slice()[0] = '1';
if (i >= 5) {
td::Random::secure_bytes(d.as_slice().remove_prefix(1).truncate(d.size() - 5));
auto x = td::crc32c(d.as_slice().truncate(d.size() - 4));
d.as_slice().remove_prefix(d.size() - 4).copy_from(td::Slice{reinterpret_cast<td::uint8 *>(&x), 4});
} else {
td::Random::secure_bytes(d.as_slice().remove_prefix(1));
}
return d;
};
std::atomic<td::uint32> remaining{0};
scheduler.run_in_context([&] {
class Callback : public ton::adnl::Adnl::Callback {
public:
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data) override {
CHECK(data.size() <= ton::adnl::Adnl::huge_packet_max_size());
CHECK(src == src);
CHECK(dst == dst);
if (data.size() >= 5) {
CHECK(td::crc32c(data.as_slice().truncate(data.size() - 4)) ==
*reinterpret_cast<const td::uint32 *>(data.as_slice().remove_prefix(data.size() - 4).begin()));
}
CHECK(remaining_ > 0);
remaining_--;
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
UNREACHABLE();
}
Callback(std::atomic<td::uint32> &remaining) : remaining_(remaining) {
}
private:
std::atomic<td::uint32> &remaining_;
};
td::actor::send_closure(adnl, &ton::adnl::Adnl::subscribe, dst, "1", std::make_unique<Callback>(remaining));
});
LOG(ERROR) << "testing delivering of all packets";
auto f = td::Clocks::system();
scheduler.run_in_context([&] {
for (td::uint32 i = 1; i <= ton::adnl::Adnl::huge_packet_max_size(); i++) {
remaining++;
td::actor::send_closure(adnl, &ton::adnl::Adnl::send_message, src, dst, send_packet(i));
}
});
auto t = td::Timestamp::in(320.0);
while (scheduler.run(1)) {
if (!remaining) {
break;
}
if (t.is_in_past()) {
LOG(FATAL) << "failed to receive packets: remaining=" << remaining;
}
}
LOG(ERROR) << "successfully tested delivering of packets of all sizes. Time=" << (td::Clocks::system() - f);
scheduler.run_in_context([&] {
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, src, true, true);
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, dst, true, true);
});
scheduler.run_in_context(
[&] { td::actor::send_closure(adnl, &ton::adnl::Adnl::send_message, dst, src, send_packet(1)); });
t = td::Timestamp::in(1.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
}
LOG(ERROR) << "testing with channels enabled";
f = td::Clocks::system();
scheduler.run_in_context([&] {
for (td::uint32 i = 1; i <= ton::adnl::Adnl::huge_packet_max_size(); i++) {
remaining++;
td::actor::send_closure(adnl, &ton::adnl::Adnl::send_message, src, dst, send_packet(i));
}
});
t = td::Timestamp::in(320.0);
while (scheduler.run(1)) {
if (!remaining) {
break;
}
if (t.is_in_past()) {
LOG(FATAL) << "failed to receive packets: remaining=" << remaining;
}
}
LOG(ERROR) << "successfully tested delivering of packets of all sizes with channels enabled. Time="
<< (td::Clocks::system() - f);
scheduler.run_in_context([&] {
class Callback : public ton::adnl::Adnl::Callback {
public:
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data) override {
UNREACHABLE();
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
CHECK(data.size() == 5);
td::uint32 s = *reinterpret_cast<const td::uint32 *>(data.as_slice().remove_prefix(1).begin());
td::BufferSlice d{s};
if (s >= 4) {
td::Random::secure_bytes(d.as_slice().truncate(s - 4));
auto x = td::crc32c(d.as_slice().truncate(d.size() - 4));
d.as_slice().remove_prefix(d.size() - 4).copy_from(td::Slice{reinterpret_cast<td::uint8 *>(&x), 4});
} else {
td::Random::secure_bytes(d.as_slice());
}
promise.set_value(std::move(d));
}
Callback() {
}
};
td::actor::send_closure(adnl, &ton::adnl::Adnl::subscribe, dst, "2", std::make_unique<Callback>());
});
LOG(ERROR) << "testing queries";
for (td::uint32 i = 1; i <= ton::adnl::Adnl::huge_packet_max_size(); i++) {
remaining++;
td::BufferSlice d{5};
d.as_slice()[0] = '2';
d.as_slice().remove_prefix(1).copy_from(td::Slice{reinterpret_cast<td::uint8 *>(&i), 4});
auto P = td::PromiseCreator::lambda([&, i](td::Result<td::BufferSlice> R) {
R.ensure();
auto data = R.move_as_ok();
CHECK(data.size() == i);
if (i >= 4) {
CHECK(td::crc32c(data.as_slice().truncate(data.size() - 4)) ==
*reinterpret_cast<const td::uint32 *>(data.as_slice().remove_prefix(data.size() - 4).begin()));
}
CHECK(remaining > 0);
remaining--;
});
scheduler.run_in_context([&] {
td::actor::send_closure(adnl, &ton::adnl::Adnl::send_query, src, dst, PSTRING() << "query" << i, std::move(P),
td::Timestamp::in(320.0), std::move(d));
});
}
t = td::Timestamp::in(320.0);
while (scheduler.run(1)) {
if (!remaining) {
break;
}
if (t.is_in_past()) {
LOG(FATAL) << "failed to receive answers: remaining=" << remaining;
}
}
LOG(ERROR) << "successfully tested delivering of quries/answers. Time=" << (td::Clocks::system() - f);
LOG(ERROR) << "testing packets, that should be ignored";
// too big answer
scheduler.run_in_context([&] {
auto x = ton::adnl::Adnl::huge_packet_max_size() + 1;
td::BufferSlice d{5};
d.as_slice()[0] = '2';
d.as_slice().remove_prefix(1).copy_from(td::Slice{reinterpret_cast<td::uint8 *>(&x), 4});
auto P = td::PromiseCreator::lambda([](td::Result<td::BufferSlice> R) { CHECK(R.is_error()); });
td::actor::send_closure(adnl, &ton::adnl::Adnl::send_query, src, dst, PSTRING() << "query" << x, std::move(P),
td::Timestamp::in(320.0), std::move(d));
});
// too big packet
scheduler.run_in_context([&] {
auto x = ton::adnl::Adnl::huge_packet_max_size() + 1;
td::actor::send_closure(adnl, &ton::adnl::Adnl::send_message, src, dst, send_packet(x));
});
// no callbacks
scheduler.run_in_context([&] {
td::BufferSlice d{1};
d.as_slice()[0] = '3';
td::actor::send_closure(adnl, &ton::adnl::Adnl::send_message, src, dst, std::move(d));
});
// no callbacks 2
scheduler.run_in_context([&] {
td::BufferSlice d{};
td::actor::send_closure(adnl, &ton::adnl::Adnl::send_message, src, dst, std::move(d));
});
t = td::Timestamp::in(2.0);
while (scheduler.run(1)) {
if (!remaining) {
break;
}
if (t.is_in_past()) {
break;
}
}
LOG(ERROR) << "successfully tested ignoring";
td::rmrf(db_root_).ensure();
std::_Exit(0);
return 0;
}

318
test/test-catchain.cpp Normal file
View file

@ -0,0 +1,318 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "adnl/utils.hpp"
#include "adnl/adnl-test-loopback-implementation.h"
#include "dht/dht.h"
#include "overlay/overlays.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "td/utils/overloaded.h"
#include "catchain/catchain.h"
#include "common/errorlog.h"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
#include <set>
struct Node {
ton::PublicKeyHash id;
ton::PublicKey id_full;
ton::adnl::AdnlNodeIdShort adnl_id;
ton::adnl::AdnlNodeIdFull adnl_id_full;
};
std::vector<Node> nodes;
td::uint32 total_nodes = 11;
class CatChainInst : public td::actor::Actor {
public:
class PayloadExtra : public ton::catchain::CatChainBlock::Extra {
public:
PayloadExtra(td::uint64 sum) : sum(sum) {
}
td::uint64 sum;
};
void process_blocks(std::vector<ton::catchain::CatChainBlock *> blocks) {
td::uint64 sum = sum_;
for (auto &B : blocks) {
auto E = dynamic_cast<const PayloadExtra *>(B->extra());
CHECK(E);
sum = std::max(sum, E->sum);
}
td::uint64 value = td::Random::fast_uint64();
sum = std::max(sum, value);
td::uint64 x[2];
x[0] = value;
x[1] = sum;
sum_ = sum;
td::actor::send_closure(catchain_, &ton::catchain::CatChain::processed_block,
td::BufferSlice{td::Slice{reinterpret_cast<char *>(x), 16}});
alarm_timestamp() = td::Timestamp::in(0.1);
height_++;
prev_values_.push_back(sum_);
}
void finished_processing() {
}
void preprocess_block(ton::catchain::CatChainBlock *block) {
td::uint64 sum = 0;
auto prev = block->prev();
if (prev) {
auto E = dynamic_cast<const PayloadExtra *>(prev->extra());
CHECK(E);
sum = std::max(E->sum, sum);
}
for (auto &B : block->deps()) {
auto E = dynamic_cast<const PayloadExtra *>(B->extra());
CHECK(E);
sum = std::max(E->sum, sum);
}
auto &payload = block->payload();
if (!payload.empty()) {
CHECK(payload.size() == 16);
td::uint64 x[2];
td::MutableSlice{reinterpret_cast<td::uint8 *>(x), 16}.copy_from(payload.as_slice());
sum = std::max(sum, x[0]);
LOG_CHECK(sum == x[1]) << sum << " " << x[0];
} else {
CHECK(!block->deps().size());
}
block->set_extra(std::make_unique<PayloadExtra>(sum));
}
void alarm() override {
td::actor::send_closure(catchain_, &ton::catchain::CatChain::need_new_block, td::Timestamp::in(0.1));
}
void start_up() override {
alarm_timestamp() = td::Timestamp::in(0.1);
ton::catchain::CatChainOptions opts;
opts.debug_disable_db = true;
std::vector<ton::catchain::CatChainNode> nodes;
for (auto &n : nodes_) {
nodes.push_back(ton::catchain::CatChainNode{n.adnl_id, n.id_full});
}
catchain_ = ton::catchain::CatChain::create(make_callback(), opts, keyring_, adnl_, overlay_manager_,
std::move(nodes), nodes_[idx_].id, unique_hash_, std::string(""));
}
CatChainInst(td::actor::ActorId<ton::keyring::Keyring> keyring, td::actor::ActorId<ton::adnl::Adnl> adnl,
td::actor::ActorId<ton::overlay::Overlays> overlay_manager, std::vector<Node> nodes, td::uint32 idx,
ton::catchain::CatChainSessionId unique_hash)
: keyring_(keyring)
, adnl_(adnl)
, overlay_manager_(overlay_manager)
, nodes_(std::move(nodes))
, idx_(idx)
, unique_hash_(unique_hash) {
}
std::unique_ptr<ton::catchain::CatChain::Callback> make_callback() {
class Callback : public ton::catchain::CatChain::Callback {
public:
void process_blocks(std::vector<ton::catchain::CatChainBlock *> blocks) override {
td::actor::send_closure(id_, &CatChainInst::process_blocks, std::move(blocks));
}
void finished_processing() override {
td::actor::send_closure(id_, &CatChainInst::finished_processing);
}
void preprocess_block(ton::catchain::CatChainBlock *block) override {
td::actor::send_closure(id_, &CatChainInst::preprocess_block, std::move(block));
}
void process_broadcast(ton::PublicKeyHash src, td::BufferSlice data) override {
UNREACHABLE();
}
void process_message(ton::PublicKeyHash src, td::BufferSlice data) override {
UNREACHABLE();
}
void process_query(ton::PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override {
UNREACHABLE();
}
void started() override {
}
Callback(td::actor::ActorId<CatChainInst> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<CatChainInst> id_;
};
return std::make_unique<Callback>(actor_id(this));
}
td::uint64 value() {
return sum_;
}
void create_fork() {
auto height = height_ - 1; //td::Random::fast(0, height_ - 1);
auto sum = prev_values_[height] + 1;
td::uint64 x[2];
x[0] = sum + 1;
x[1] = sum + 1;
td::actor::send_closure(catchain_, &ton::catchain::CatChain::debug_add_fork,
td::BufferSlice{td::Slice{reinterpret_cast<char *>(x), 16}}, height + 1);
}
private:
td::actor::ActorId<ton::keyring::Keyring> keyring_;
td::actor::ActorId<ton::adnl::Adnl> adnl_;
td::actor::ActorId<ton::overlay::Overlays> overlay_manager_;
std::vector<Node> nodes_;
td::uint32 idx_;
ton::catchain::CatChainSessionId unique_hash_;
td::actor::ActorOwn<ton::catchain::CatChain> catchain_;
td::uint64 sum_ = 0;
td::uint32 height_ = 0;
std::vector<td::uint64> prev_values_;
};
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_default_failure_signal_handler().ensure();
std::string db_root_ = "tmp-ee";
td::mkdir(db_root_).ensure();
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<ton::keyring::Keyring> keyring;
td::actor::ActorOwn<ton::adnl::TestLoopbackNetworkManager> network_manager;
td::actor::ActorOwn<ton::adnl::Adnl> adnl;
td::actor::ActorOwn<ton::overlay::Overlays> overlay_manager;
td::actor::Scheduler scheduler({7});
scheduler.run_in_context([&] {
ton::errorlog::ErrorLog::create(db_root_);
keyring = ton::keyring::Keyring::create(db_root_);
network_manager = td::actor::create_actor<ton::adnl::TestLoopbackNetworkManager>("test net");
adnl = ton::adnl::Adnl::create(db_root_, keyring.get());
overlay_manager =
ton::overlay::Overlays::create(db_root_, keyring.get(), adnl.get(), td::actor::ActorId<ton::dht::Dht>{});
td::actor::send_closure(adnl, &ton::adnl::Adnl::register_network_manager, network_manager.get());
});
for (td::uint32 att = 0; att < 10; att++) {
nodes.resize(total_nodes);
scheduler.run_in_context([&] {
auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list();
for (auto &n : nodes) {
auto pk1 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub1 = pk1.compute_public_key();
n.adnl_id_full = ton::adnl::AdnlNodeIdFull{pub1};
n.adnl_id = ton::adnl::AdnlNodeIdShort{pub1.compute_short_id()};
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {});
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr);
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, n.adnl_id, true,
true);
auto pk2 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub2 = pk2.compute_public_key();
n.id_full = pub2;
n.id = pub2.compute_short_id();
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk2), true, [](td::Unit) {});
LOG(DEBUG) << "created node " << n.adnl_id << " " << n.id;
}
for (auto &n1 : nodes) {
for (auto &n2 : nodes) {
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_peer, n1.adnl_id, n2.adnl_id_full, addr);
}
}
});
auto t = td::Timestamp::in(1.0);
ton::catchain::CatChainSessionId unique_id;
td::Random::secure_bytes(unique_id.as_slice());
std::vector<td::actor::ActorOwn<CatChainInst>> inst;
scheduler.run_in_context([&] {
for (td::uint32 idx = 0; idx < total_nodes; idx++) {
inst.push_back(td::actor::create_actor<CatChainInst>("inst", keyring.get(), adnl.get(), overlay_manager.get(),
nodes, idx, unique_id));
}
});
t = td::Timestamp::in(10.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
}
for (auto &n : inst) {
std::cout << "value=" << n.get_actor_unsafe().value() << std::endl;
}
scheduler.run_in_context([&] { td::actor::send_closure(inst[0], &CatChainInst::create_fork); });
t = td::Timestamp::in(10.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
}
for (auto &n : inst) {
std::cout << "value=" << n.get_actor_unsafe().value() << std::endl;
}
scheduler.run_in_context([&] {
nodes.clear();
inst.clear();
});
}
td::rmrf(db_root_).ensure();
std::_Exit(0);
return 0;
}

407
test/test-dht.cpp Normal file
View file

@ -0,0 +1,407 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl-network-manager.h"
#include "adnl/adnl-test-loopback-implementation.h"
#include "adnl/adnl.h"
#include "dht/dht.h"
#include "dht/dht.hpp"
#include "td/utils/port/signals.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include <memory>
#include <set>
int main() {
SET_VERBOSITY_LEVEL(verbosity_INFO);
std::string db_root_ = "tmp-ee";
td::mkdir(db_root_).ensure();
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<ton::keyring::Keyring> keyring;
td::actor::ActorOwn<ton::adnl::TestLoopbackNetworkManager> network_manager;
td::actor::ActorOwn<ton::adnl::Adnl> adnl;
std::vector<td::actor::ActorOwn<ton::dht::Dht>> dht;
std::shared_ptr<ton::dht::DhtGlobalConfig> dht_config;
td::actor::Scheduler scheduler({7});
std::vector<ton::adnl::AdnlNodeIdFull> dht_ids;
td::uint32 total_nodes = 11;
std::atomic<td::uint32> remaining{0};
scheduler.run_in_context([&] {
keyring = ton::keyring::Keyring::create(db_root_);
network_manager = td::actor::create_actor<ton::adnl::TestLoopbackNetworkManager>("test net");
adnl = ton::adnl::Adnl::create(db_root_, keyring.get());
td::actor::send_closure(adnl, &ton::adnl::Adnl::register_network_manager, network_manager.get());
auto addr0 = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list(true);
auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list();
for (td::uint32 i = 0; i < total_nodes; i++) {
auto pk1 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub1 = pk1.compute_public_key();
auto src = ton::adnl::AdnlNodeIdShort{pub1.compute_short_id()};
if (i == 0) {
auto obj = ton::create_tl_object<ton::ton_api::dht_node>(pub1.tl(), addr0.tl(), -1, td::BufferSlice());
auto d = pk1.create_decryptor().move_as_ok();
obj->signature_ = d->sign(serialize_tl_object(obj, true)).move_as_ok();
std::vector<ton::tl_object_ptr<ton::ton_api::dht_node>> vec;
vec.push_back(std::move(obj));
auto nodes = ton::create_tl_object<ton::ton_api::dht_nodes>(std::move(vec));
auto conf = ton::create_tl_object<ton::ton_api::dht_config_global>(std::move(nodes), 6, 3);
auto dht_configR = ton::dht::Dht::create_global_config(std::move(conf));
dht_configR.ensure();
dht_config = dht_configR.move_as_ok();
}
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {});
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr);
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, src, true, true);
dht.push_back(ton::dht::Dht::create(src, db_root_, dht_config, keyring.get(), adnl.get()).move_as_ok());
dht_ids.push_back(ton::adnl::AdnlNodeIdFull{pub1});
}
for (auto &n1 : dht_ids) {
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_peer, n1.compute_short_id(), dht_ids[0], addr);
}
});
LOG(ERROR) << "testing different values";
auto key_pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto key_pub = key_pk.compute_public_key();
auto key_short_id = key_pub.compute_short_id();
auto key_dec = key_pk.create_decryptor().move_as_ok();
{
for (td::uint32 idx = 0; idx <= ton::dht::DhtKey::max_index() + 1; idx++) {
ton::dht::DhtKey dht_key{key_short_id, "test", idx};
if (idx <= ton::dht::DhtKey::max_index()) {
dht_key.check().ensure();
} else {
dht_key.check().ensure_error();
}
}
{
ton::dht::DhtKey dht_key{key_short_id, "test", 0};
dht_key.check().ensure();
dht_key = ton::dht::DhtKey{key_short_id, "", 0};
dht_key.check().ensure_error();
dht_key =
ton::dht::DhtKey{key_short_id, td::BufferSlice{ton::dht::DhtKey::max_name_length()}.as_slice().str(), 0};
dht_key.check().ensure();
dht_key =
ton::dht::DhtKey{key_short_id, td::BufferSlice{ton::dht::DhtKey::max_name_length() + 1}.as_slice().str(), 0};
dht_key.check().ensure_error();
}
{
ton::dht::DhtKey dht_key{key_short_id, "test", 0};
auto dht_update_rule = ton::dht::DhtUpdateRuleSignature::create().move_as_ok();
ton::dht::DhtKeyDescription dht_key_description{dht_key.clone(), key_pub, dht_update_rule, td::BufferSlice()};
dht_key_description.update_signature(key_dec->sign(dht_key_description.to_sign()).move_as_ok());
dht_key_description.check().ensure();
dht_key_description = ton::dht::DhtKeyDescription{dht_key.clone(), key_pub, dht_update_rule, td::BufferSlice(64)};
dht_key_description.check().ensure_error();
dht_key_description.update_signature(key_dec->sign(dht_key_description.to_sign()).move_as_ok());
dht_key_description.check().ensure();
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub = pk.compute_public_key();
dht_key_description = ton::dht::DhtKeyDescription{dht_key.clone(), pub, dht_update_rule, td::BufferSlice(64)};
dht_key_description.update_signature(
pk.create_decryptor().move_as_ok()->sign(dht_key_description.to_sign()).move_as_ok());
dht_key_description.check().ensure_error();
}
}
{
ton::dht::DhtKey dht_key{key_short_id, "test", 0};
auto dht_update_rule = ton::dht::DhtUpdateRuleSignature::create().move_as_ok();
ton::dht::DhtKeyDescription dht_key_description{std::move(dht_key), key_pub, std::move(dht_update_rule),
td::BufferSlice()};
dht_key_description.update_signature(key_dec->sign(dht_key_description.to_sign()).move_as_ok());
auto ttl = static_cast<td::uint32>(td::Clocks::system() + 3600);
ton::dht::DhtValue dht_value{dht_key_description.clone(), td::BufferSlice("value"), ttl, td::BufferSlice("")};
dht_value.check().ensure_error();
dht_value.update_signature(key_dec->sign(dht_value.to_sign()).move_as_ok());
dht_value.check().ensure();
CHECK(!dht_value.expired());
dht_value = ton::dht::DhtValue{dht_key_description.clone(), td::BufferSlice(""), ttl, td::BufferSlice("")};
dht_value.update_signature(key_dec->sign(dht_value.to_sign()).move_as_ok());
dht_value.check().ensure();
dht_value = ton::dht::DhtValue{dht_key_description.clone(), td::BufferSlice(""),
static_cast<td::uint32>(td::Clocks::system() - 1), td::BufferSlice("")};
dht_value.update_signature(key_dec->sign(dht_value.to_sign()).move_as_ok());
dht_value.check().ensure();
CHECK(dht_value.expired());
dht_value = ton::dht::DhtValue{dht_key_description.clone(), td::BufferSlice("value"), ttl, td::BufferSlice("")};
dht_value.update_signature(td::BufferSlice{64});
dht_value.check().ensure_error();
dht_value = ton::dht::DhtValue{dht_key_description.clone(), td::BufferSlice(ton::dht::DhtValue::max_value_size()),
ttl, td::BufferSlice("")};
dht_value.update_signature(key_dec->sign(dht_value.to_sign()).move_as_ok());
dht_value.check().ensure();
dht_value = ton::dht::DhtValue{dht_key_description.clone(),
td::BufferSlice(ton::dht::DhtValue::max_value_size() + 1), ttl, td::BufferSlice("")};
dht_value.update_signature(key_dec->sign(dht_value.to_sign()).move_as_ok());
dht_value.check().ensure_error();
}
{
ton::dht::DhtKey dht_key{key_short_id, "test", 0};
auto dht_update_rule = ton::dht::DhtUpdateRuleAnybody::create().move_as_ok();
ton::dht::DhtKeyDescription dht_key_description{std::move(dht_key), key_pub, std::move(dht_update_rule),
td::BufferSlice()};
dht_key_description.update_signature(key_dec->sign(dht_key_description.to_sign()).move_as_ok());
auto ttl = static_cast<td::uint32>(td::Clocks::system() + 3600);
ton::dht::DhtValue dht_value{dht_key_description.clone(), td::BufferSlice("value"), ttl, td::BufferSlice()};
dht_value.check().ensure();
CHECK(!dht_value.expired());
dht_value.update_signature(key_dec->sign(dht_value.to_sign()).move_as_ok());
dht_value.check().ensure_error();
dht_value = ton::dht::DhtValue{dht_key_description.clone(), td::BufferSlice(), ttl, td::BufferSlice()};
dht_value.check().ensure();
dht_value = ton::dht::DhtValue{dht_key_description.clone(), td::BufferSlice(ton::dht::DhtValue::max_value_size()),
ttl, td::BufferSlice()};
dht_value.check().ensure();
dht_value = ton::dht::DhtValue{dht_key_description.clone(),
td::BufferSlice(ton::dht::DhtValue::max_value_size() + 1), ttl, td::BufferSlice()};
dht_value.check().ensure_error();
}
{
ton::dht::DhtKey dht_key{key_short_id, "test", 0};
auto dht_update_rule = ton::dht::DhtUpdateRuleOverlayNodes::create().move_as_ok();
ton::dht::DhtKeyDescription dht_key_description{std::move(dht_key), key_pub, std::move(dht_update_rule),
td::BufferSlice()};
dht_key_description.update_signature(key_dec->sign(dht_key_description.to_sign()).move_as_ok());
auto ttl = static_cast<td::uint32>(td::Clocks::system() + 3600);
ton::dht::DhtValue dht_value{dht_key_description.clone(), td::BufferSlice(""), ttl, td::BufferSlice()};
dht_value.check().ensure_error();
auto obj = ton::create_tl_object<ton::ton_api::overlay_nodes>();
dht_value =
ton::dht::DhtValue{dht_key_description.clone(), ton::serialize_tl_object(obj, true), ttl, td::BufferSlice()};
dht_value.check().ensure();
for (td::uint32 i = 0; i < 100; i++) {
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub = pk.compute_public_key();
auto date = static_cast<td::int32>(td::Clocks::system() - 10);
//overlay.node.toSign id:adnl.id.short overlay:int256 version:int = overlay.node.ToSign;
//overlay.node id:PublicKey overlay:int256 version:int signature:bytes = overlay.Node;
auto to_sign = ton::create_serialize_tl_object<ton::ton_api::overlay_node_toSign>(
ton::adnl::AdnlNodeIdShort{pub.compute_short_id()}.tl(), key_short_id.tl(), date);
auto n = ton::create_tl_object<ton::ton_api::overlay_node>(
pub.tl(), key_short_id.tl(), date, pk.create_decryptor().move_as_ok()->sign(to_sign.as_slice()).move_as_ok());
obj->nodes_.push_back(std::move(n));
dht_value =
ton::dht::DhtValue{dht_key_description.clone(), ton::serialize_tl_object(obj, true), ttl, td::BufferSlice()};
auto size = ton::serialize_tl_object(obj, true).size();
if (size <= ton::dht::DhtValue::max_value_size()) {
dht_value.check().ensure();
} else {
dht_value.check().ensure_error();
}
}
obj->nodes_.clear();
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub = pk.compute_public_key();
auto date = static_cast<td::int32>(td::Clocks::system() - 10);
//overlay.node.toSign id:adnl.id.short overlay:int256 version:int = overlay.node.ToSign;
//overlay.node id:PublicKey overlay:int256 version:int signature:bytes = overlay.Node;
auto to_sign = ton::create_serialize_tl_object<ton::ton_api::overlay_node_toSign>(
ton::adnl::AdnlNodeIdShort{pub.compute_short_id()}.tl(), key_short_id.tl() ^ td::Bits256::ones(), date);
auto n = ton::create_tl_object<ton::ton_api::overlay_node>(
pub.tl(), key_short_id.tl() ^ td::Bits256::ones(), date,
pk.create_decryptor().move_as_ok()->sign(to_sign.as_slice()).move_as_ok());
obj->nodes_.push_back(std::move(n));
dht_value =
ton::dht::DhtValue{dht_key_description.clone(), ton::serialize_tl_object(obj, true), ttl, td::BufferSlice()};
dht_value.check().ensure_error();
obj->nodes_.clear();
to_sign = ton::create_serialize_tl_object<ton::ton_api::overlay_node_toSign>(
ton::adnl::AdnlNodeIdShort{pub.compute_short_id()}.tl(), key_short_id.tl(), date);
n = ton::create_tl_object<ton::ton_api::overlay_node>(
pub.tl(), key_short_id.tl(), date, pk.create_decryptor().move_as_ok()->sign(to_sign.as_slice()).move_as_ok());
obj->nodes_.push_back(std::move(n));
dht_value =
ton::dht::DhtValue{dht_key_description.clone(), ton::serialize_tl_object(obj, true), ttl, td::BufferSlice()};
dht_value.check().ensure();
obj->nodes_.clear();
//to_sign = ton::create_serialize_tl_object<ton::ton_api::overlay_node_toSign>(
// ton::adnl::AdnlNodeIdShort{pub.compute_short_id()}.tl(), key_short_id.tl(), date);
n = ton::create_tl_object<ton::ton_api::overlay_node>(pub.tl(), key_short_id.tl(), date, td::BufferSlice{64});
obj->nodes_.push_back(std::move(n));
dht_value =
ton::dht::DhtValue{dht_key_description.clone(), ton::serialize_tl_object(obj, true), ttl, td::BufferSlice()};
dht_value.check().ensure_error();
obj->nodes_.clear();
to_sign = ton::create_serialize_tl_object<ton::ton_api::overlay_node_toSign>(
ton::adnl::AdnlNodeIdShort{pub.compute_short_id()}.tl(), key_short_id.tl(), date);
n = ton::create_tl_object<ton::ton_api::overlay_node>(
pub.tl(), key_short_id.tl(), date, pk.create_decryptor().move_as_ok()->sign(to_sign.as_slice()).move_as_ok());
obj->nodes_.push_back(std::move(n));
dht_value =
ton::dht::DhtValue{dht_key_description.clone(), ton::serialize_tl_object(obj, true), ttl, td::BufferSlice()};
dht_value.check().ensure();
auto dht_value2 =
ton::dht::DhtValue{dht_key_description.clone(), ton::serialize_tl_object(obj, true), ttl, td::BufferSlice()};
dht_value2.check().ensure();
dht_value.update(std::move(dht_value2)).ensure();
CHECK(ton::fetch_tl_object<ton::ton_api::overlay_nodes>(dht_value.value().as_slice(), true)
.move_as_ok()
->nodes_.size() == 1);
obj->nodes_.clear();
{
td::BufferSlice x{64};
td::Random::secure_bytes(x.as_slice());
auto pk2 = ton::PrivateKey{ton::privkeys::Unenc{x.clone()}};
n = ton::create_tl_object<ton::ton_api::overlay_node>(
pk2.compute_public_key().tl(), key_short_id.tl(), date,
pk2.create_decryptor().move_as_ok()->sign(to_sign.as_slice()).move_as_ok());
obj->nodes_.push_back(std::move(n));
}
dht_value2 =
ton::dht::DhtValue{dht_key_description.clone(), ton::serialize_tl_object(obj, true), ttl, td::BufferSlice()};
dht_value2.check().ensure();
dht_value.update(std::move(dht_value2)).ensure();
CHECK(ton::fetch_tl_object<ton::ton_api::overlay_nodes>(dht_value.value().as_slice(), true)
.move_as_ok()
->nodes_.size() == 2);
}
LOG(ERROR) << "success";
LOG(ERROR) << "empty run";
auto t = td::Timestamp::in(10.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
}
LOG(ERROR) << "success";
for (td::uint32 x = 0; x < 100; x++) {
ton::dht::DhtKey dht_key{key_short_id, PSTRING() << "test-" << x, x % 8};
auto dht_update_rule = ton::dht::DhtUpdateRuleSignature::create().move_as_ok();
ton::dht::DhtKeyDescription dht_key_description{std::move(dht_key), key_pub, std::move(dht_update_rule),
td::BufferSlice()};
dht_key_description.update_signature(key_dec->sign(dht_key_description.to_sign()).move_as_ok());
auto ttl = static_cast<td::uint32>(td::Clocks::system() + 3600);
td::uint8 v[1];
v[0] = static_cast<td::uint8>(x);
ton::dht::DhtValue dht_value{std::move(dht_key_description), td::BufferSlice(td::Slice(v, 1)), ttl,
td::BufferSlice("")};
dht_value.update_signature(key_dec->sign(dht_value.to_sign()).move_as_ok());
remaining++;
auto P = td::PromiseCreator::lambda([&](td::Result<td::Unit> R) {
R.ensure();
remaining--;
});
scheduler.run_in_context([&] {
td::actor::send_closure(dht[td::Random::fast(0, total_nodes - 1)], &ton::dht::Dht::set_value,
std::move(dht_value), std::move(P));
});
}
LOG(ERROR) << "stores";
t = td::Timestamp::in(60.0);
while (scheduler.run(1)) {
if (!remaining) {
break;
}
if (t.is_in_past()) {
LOG(FATAL) << "failed: remaining = " << remaining;
}
}
LOG(ERROR) << "success";
for (td::uint32 x = 0; x < 100; x++) {
ton::dht::DhtKey dht_key{key_short_id, PSTRING() << "test-" << x, x % 8};
remaining++;
auto P = td::PromiseCreator::lambda([&, idx = x](td::Result<ton::dht::DhtValue> R) {
R.ensure();
auto v = R.move_as_ok();
CHECK(v.key().key().public_key_hash() == key_short_id);
CHECK(v.key().key().name() == (PSTRING() << "test-" << idx));
CHECK(v.key().key().idx() == idx % 8);
td::uint8 buf[1];
buf[0] = static_cast<td::uint8>(idx);
CHECK(v.value().as_slice() == td::Slice(buf, 1));
remaining--;
});
scheduler.run_in_context([&] {
td::actor::send_closure(dht[td::Random::fast(0, total_nodes - 1)], &ton::dht::Dht::get_value, dht_key,
std::move(P));
});
}
LOG(ERROR) << "gets";
t = td::Timestamp::in(60.0);
while (scheduler.run(1)) {
if (!remaining) {
break;
}
if (t.is_in_past()) {
LOG(FATAL) << "failed: remaining = " << remaining;
}
}
LOG(ERROR) << "success";
td::rmrf(db_root_).ensure();
std::_Exit(0);
return 0;
}

View file

@ -0,0 +1,236 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "adnl/adnl-ext-client.h"
#include "adnl/utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "terminal/terminal.h"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
template <std::size_t size>
std::ostream &operator<<(std::ostream &stream, const td::UInt<size> &x) {
for (size_t i = 0; i < size / 8; i++) {
stream << td::format::hex_digit((x.raw[i] >> 4) & 15) << td::format::hex_digit(x.raw[i] & 15);
}
return stream;
}
class TestNode : public td::actor::Actor {
private:
td::actor::ActorOwn<ton::adnl::Adnl> adnl_;
std::string local_config_ = "ton-local.config";
std::string global_config_ = "ton-global.config";
td::actor::ActorOwn<ton::adnl::AdnlExtClient> client_;
td::actor::ActorOwn<td::TerminalIO> io_;
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> make_callback() {
class Callback : public ton::adnl::AdnlExtClient::Callback {
public:
void on_ready() override {
td::actor::send_closure(id_, &TestNode::conn_ready);
}
void on_stop_ready() override {
td::actor::send_closure(id_, &TestNode::conn_closed);
}
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<TestNode> id_;
};
return std::make_unique<Callback>(actor_id(this));
}
bool ready_ = false;
std::string db_root_;
public:
void conn_ready() {
LOG(ERROR) << "conn ready";
ready_ = true;
}
void conn_closed() {
ready_ = false;
}
void set_local_config(std::string str) {
local_config_ = str;
}
void set_global_config(std::string str) {
global_config_ = str;
}
void set_db_root(std::string db_root) {
db_root_ = db_root;
}
void start_up() override {
class Cb : public td::TerminalIO::Callback {
public:
void line_cb(td::BufferSlice line) override {
LOG(ERROR) << "read line";
td::actor::send_closure(id_, &TestNode::send_query, std::move(line));
}
Cb(td::actor::ActorId<TestNode> id) : id_(id) {
}
private:
td::actor::ActorId<TestNode> id_;
};
io_ = td::TerminalIO::create("", false, std::make_unique<Cb>(actor_id(this)));
td::actor::send_closure(io_, &td::TerminalIO::set_log_interface);
}
void send_query(td::BufferSlice data) {
if (ready_ && !client_.empty()) {
LOG(ERROR) << "sending query";
auto P = td::PromiseCreator::lambda([](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
LOG(ERROR) << "failed query: " << R.move_as_error();
return;
}
auto F = ton::fetch_tl_object<ton::ton_api::Object>(R.move_as_ok(), true);
if (F.is_error()) {
LOG(ERROR) << "failed to parse answer: " << F.move_as_error();
return;
}
auto obj = F.move_as_ok();
LOG(ERROR) << "got answer: " << ton::ton_api::to_string(obj);
});
td::BufferSlice b =
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::liteServer_query>(std::move(data)), true);
td::actor::send_closure(client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b),
td::Timestamp::in(10.0), std::move(P));
}
}
TestNode() {
}
void run() {
adnl_ = ton::adnl::Adnl::create(db_root_);
auto G = td::read_file(global_config_).move_as_ok();
auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
ton::ton_api::config_global gc;
ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
//td::actor::send_closure(network_manager_, &ton::adnl::AdnlNetworkManager::load_local_config, std::move(lc.net_));
if (gc.adnl_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_static_nodes_from_config,
std::move(gc.adnl_->static_nodes_));
}
CHECK(gc.liteclients_.size() > 0);
auto &cli = gc.liteclients_[0];
td::IPAddress addr;
addr.init_host_port(td::IPAddress::ipv4_to_str(cli->ip_), cli->port_).ensure();
client_ = ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{cli->id_}, addr, make_callback());
}
};
td::Result<td::UInt256> get_uint256(std::string str) {
if (str.size() != 64) {
return td::Status::Error("uint256 must have 64 bytes");
}
td::UInt256 res;
for (size_t i = 0; i < 32; i++) {
res.raw[i] = static_cast<td::uint8>(td::hex_to_int(str[2 * i]) * 16 + td::hex_to_int(str[2 * i + 1]));
}
return res;
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_DEBUG);
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<TestNode> x;
td::OptionsParser p;
p.set_description("test basic adnl functionality");
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_global_config, fname.str());
return td::Status::OK();
});
p.add_option('c', "local-config", "file to read local config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_local_config, fname.str());
return td::Status::OK();
});
p.add_option('D', "db", "root for dbs", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_db_root, fname.str());
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
td::FileFd::Flags::Create | td::FileFd::Flags::Append | td::FileFd::Flags::Write)
.move_as_ok();
dup2(FileLog.get_native_fd().fd(), 1);
dup2(FileLog.get_native_fd().fd(), 2);
return td::Status::OK();
});
#endif
td::actor::Scheduler scheduler({2});
scheduler.run_in_context([&] { x = td::actor::create_actor<TestNode>("testnode"); });
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
scheduler.run_in_context([&] { td::actor::send_closure(x, &TestNode::run); });
scheduler.run();
return 0;
}

220
test/test-ext-client.cpp Normal file
View file

@ -0,0 +1,220 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "adnl/utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "dht/dht.h"
#include "overlay/overlays.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "adnl/adnl-ext-client.h"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
template <std::size_t size>
std::ostream &operator<<(std::ostream &stream, const td::UInt<size> &x) {
for (size_t i = 0; i < size / 8; i++) {
stream << td::format::hex_digit((x.raw[i] >> 4) & 15) << td::format::hex_digit(x.raw[i] & 15);
}
return stream;
}
class TestNode : public td::actor::Actor {
private:
std::string local_config_ = "ton-local.config";
std::string global_config_ = "ton-global.config";
td::actor::ActorOwn<ton::adnl::AdnlExtClient> client_;
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> make_callback() {
class Callback : public ton::adnl::AdnlExtClient::Callback {
public:
void on_ready() override {
td::actor::send_closure(id_, &TestNode::conn_ready);
}
void on_stop_ready() override {
td::actor::send_closure(id_, &TestNode::conn_closed);
}
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<TestNode> id_;
};
return std::make_unique<Callback>(actor_id(this));
}
bool ready_ = false;
std::string db_root_;
public:
void conn_ready() {
LOG(ERROR) << "conn ready";
ready_ = true;
}
void conn_closed() {
ready_ = false;
}
void set_local_config(std::string str) {
local_config_ = str;
}
void set_global_config(std::string str) {
global_config_ = str;
}
void set_db_root(std::string db_root) {
db_root_ = db_root;
}
void start_up() override {
}
void alarm() override {
if (ready_ && !client_.empty()) {
LOG(ERROR) << "sending query";
auto P = td::PromiseCreator::lambda([](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
LOG(ERROR) << "failed query: " << R.move_as_error();
return;
}
auto F = ton::fetch_tl_object<ton::ton_api::Object>(R.move_as_ok(), true);
if (F.is_error()) {
LOG(ERROR) << "failed to pasrse answer: " << F.move_as_error();
return;
}
auto obj = F.move_as_ok();
LOG(ERROR) << "got answer: " << ton::ton_api::to_string(obj);
});
td::BufferSlice b = ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::getTestObject>(), true);
td::actor::send_closure(client_, &ton::adnl::AdnlExtClient::send_query, "query", std::move(b),
td::Timestamp::in(10.0), std::move(P));
}
alarm_timestamp() = td::Timestamp::in(2.0);
}
TestNode() {
}
void run() {
auto L = td::read_file(local_config_).move_as_ok();
auto lc_j = td::json_decode(L.as_slice()).move_as_ok();
ton::ton_api::config_local lc;
ton::ton_api::from_json(lc, lc_j.get_object()).ensure();
auto G = td::read_file(global_config_).move_as_ok();
auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
ton::ton_api::config_global gc;
ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
CHECK(gc.liteclients_.size() > 0);
auto &cli = gc.liteclients_[0];
td::IPAddress addr;
addr.init_host_port(td::IPAddress::ipv4_to_str(cli->ip_), cli->port_).ensure();
client_ = ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull::create(cli->id_).move_as_ok(), addr,
make_callback());
alarm_timestamp() = td::Timestamp::in(2.0);
}
};
td::Result<td::UInt256> get_uint256(std::string str) {
if (str.size() != 64) {
return td::Status::Error("uint256 must have 64 bytes");
}
td::UInt256 res;
for (size_t i = 0; i < 32; i++) {
res.raw[i] = static_cast<td::uint8>(td::hex_to_int(str[2 * i]) * 16 + td::hex_to_int(str[2 * i + 1]));
}
return res;
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_DEBUG);
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<TestNode> x;
td::OptionsParser p;
p.set_description("test basic adnl functionality");
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_global_config, fname.str());
return td::Status::OK();
});
p.add_option('c', "local-config", "file to read local config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_local_config, fname.str());
return td::Status::OK();
});
p.add_option('D', "db", "root for dbs", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_db_root, fname.str());
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
td::FileFd::Flags::Create | td::FileFd::Flags::Append | td::FileFd::Flags::Write)
.move_as_ok();
dup2(FileLog.get_native_fd().fd(), 1);
dup2(FileLog.get_native_fd().fd(), 2);
return td::Status::OK();
});
#endif
td::actor::Scheduler scheduler({2});
scheduler.run_in_context([&] { x = td::actor::create_actor<TestNode>("testnode"); });
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
scheduler.run_in_context([&] { td::actor::send_closure(x, &TestNode::run); });
scheduler.run();
return 0;
}

221
test/test-ext-server.cpp Normal file
View file

@ -0,0 +1,221 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "adnl/utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "dht/dht.h"
#include "overlay/overlays.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
template <std::size_t size>
std::ostream &operator<<(std::ostream &stream, const td::UInt<size> &x) {
for (size_t i = 0; i < size / 8; i++) {
stream << td::format::hex_digit((x.raw[i] >> 4) & 15) << td::format::hex_digit(x.raw[i] & 15);
}
return stream;
}
class TestNode : public td::actor::Actor {
private:
td::actor::ActorOwn<ton::keyring::Keyring> keyring_;
td::actor::ActorOwn<ton::adnl::Adnl> adnl_;
std::string local_config_ = "ton-local.config";
std::string global_config_ = "ton-global.config";
std::unique_ptr<ton::adnl::Adnl::Callback> make_callback() {
class Callback : public ton::adnl::Adnl::Callback {
public:
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data) override {
td::actor::send_closure(id_, &TestNode::adnl_receive_message, src, dst, std::move(data));
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &TestNode::adnl_receive_query, src, dst, std::move(data), std::move(promise));
}
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<TestNode> id_;
};
return std::make_unique<Callback>(actor_id(this));
}
std::string db_root_;
public:
void adnl_receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data) {
LOG(ERROR) << "ADNL MESSAGE FROM " << src << ": size=" << data.size() << "\n";
}
void adnl_receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {
LOG(ERROR) << "ADNL QUERY FROM " << src << ": size=" << data.size() << "\n";
promise.set_value(ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::testString>("xxx"), true));
}
void set_local_config(std::string str) {
local_config_ = str;
}
void set_global_config(std::string str) {
global_config_ = str;
}
void set_db_root(std::string db_root) {
db_root_ = db_root;
}
void start_up() override {
}
void alarm() override {
}
TestNode() {
}
void run() {
keyring_ = ton::keyring::Keyring::create(db_root_ + "/keyring/");
adnl_ = ton::adnl::Adnl::create(db_root_, keyring_.get());
auto L = td::read_file(local_config_).move_as_ok();
auto lc_j = td::json_decode(L.as_slice()).move_as_ok();
ton::ton_api::config_local lc;
ton::ton_api::from_json(lc, lc_j.get_object()).ensure();
auto G = td::read_file(global_config_).move_as_ok();
auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
ton::ton_api::config_global gc;
ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
for (auto &port : lc.udp_ports_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_listening_udp_port, "0.0.0.0",
static_cast<td::uint16>(port));
}
//td::actor::send_closure(network_manager_, &ton::adnl::AdnlNetworkManager::load_local_config, std::move(lc.net_));
//td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_ids_from_config, std::move(lc.local_ids_));
if (gc.adnl_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_static_nodes_from_config,
std::move(gc.adnl_->static_nodes_));
}
for (auto &x : lc.liteservers_) {
auto pk = ton::PrivateKey{x->id_};
auto pub_k = ton::adnl::AdnlNodeIdFull{pk.compute_public_key()};
auto id = pub_k.compute_short_id();
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, pub_k, ton::adnl::AdnlAddressList{});
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, id,
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::getTestObject::ID), make_callback());
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_ext_local_id, id);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_ext_tcp_port, static_cast<td::uint16>(x->port_));
}
}
};
td::Result<td::UInt256> get_uint256(std::string str) {
if (str.size() != 64) {
return td::Status::Error("uint256 must have 64 bytes");
}
td::UInt256 res;
for (size_t i = 0; i < 32; i++) {
res.raw[i] = static_cast<td::uint8>(td::hex_to_int(str[2 * i]) * 16 + td::hex_to_int(str[2 * i + 1]));
}
return res;
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_DEBUG);
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<TestNode> x;
td::OptionsParser p;
p.set_description("test basic adnl functionality");
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_global_config, fname.str());
return td::Status::OK();
});
p.add_option('c', "local-config", "file to read local config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_local_config, fname.str());
return td::Status::OK();
});
p.add_option('D', "db", "root for dbs", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_db_root, fname.str());
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
td::FileFd::Flags::Create | td::FileFd::Flags::Append | td::FileFd::Flags::Write)
.move_as_ok();
dup2(FileLog.get_native_fd().fd(), 1);
dup2(FileLog.get_native_fd().fd(), 2);
return td::Status::OK();
});
#endif
td::actor::Scheduler scheduler({2});
scheduler.run_in_context([&] { x = td::actor::create_actor<TestNode>("testnode"); });
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
scheduler.run_in_context([&] { td::actor::send_closure(x, &TestNode::run); });
scheduler.run();
return 0;
}

138
test/test-hello-world.cpp Normal file
View file

@ -0,0 +1,138 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include <iostream>
#include "auto/tl/ton_api.h"
#include "auto/tl/ton_api_json.h"
#include "tl/tl_json.h"
namespace {
std::string config = R"json(
{
"@type" : "config.local",
"dht": [
{
"@type" : "dht.config.local",
"id" : {
"@type" : "adnl.id.pk.ed25519",
"key" : "VdeZz3BEIE8+tuPSBUNKN0jQXL/0T/SoK4ZpJ9vTCNQ="
},
"addr_list" : {
"@type" : "adnl.addressList",
"version" : 0,
"addrs" : [
{
"@type" : "adnl.address.udp",
"ip" : 2130706433,
"port" : 16000
}
]
}
}
]
}
)json";
std::string config2 = R"json(
{
"@type" : "config.local",
"dht": [
{
"@type" : "dht.config.local",
"id" : {
"@type" : "adnl.id.pk.ed25519",
"key" : "VdeZz3BEIE8+tuPSBUNKN0jQXL/0T/SoK4ZpJ9vTCNQ="
},
"addr_list" : {
"@type" : "adnl.addressList",
"version" : 0,
"addrs" : [
{
"@type" : "adnl.address.udp",
"ip" : 2130706433,
"port" : 16000
}
]
}
}
],
"adnl" : {
"@type" : "adnl.config.local"
}
}
)json";
} // namespace
int main() {
std::cout << "hello world!\n";
auto decode_encode = [](auto obj_json) {
auto as_json_value = td::json_decode(obj_json).move_as_ok();
ton::ton_api::object_ptr<ton::ton_api::Object> obj2;
from_json(obj2, as_json_value).ensure();
CHECK(obj2 != nullptr);
return td::json_encode<std::string>(td::ToJson(obj2));
};
auto test_tl_json = [&decode_encode](auto obj) {
auto obj_json = td::json_encode<std::string>(td::ToJson(obj));
std::cout << obj_json << "\n";
auto obj2_json = decode_encode(obj_json);
CHECK(obj_json == obj2_json);
};
td::Bits256 uint256;
uint256.set_ones();
test_tl_json(ton::ton_api::make_object<ton::ton_api::adnl_id_short>(uint256));
test_tl_json(ton::ton_api::make_object<ton::ton_api::testObject>(
1, ton::ton_api::make_object<ton::ton_api::adnl_id_short>(uint256),
ton::ton_api::make_object<ton::ton_api::getTestObject>()));
std::cout << decode_encode(config) << std::endl;
std::cout << decode_encode(config2) << std::endl;
auto decode_encode_local = [](auto obj_json) {
auto as_json_value = td::json_decode(obj_json).move_as_ok();
ton::ton_api::config_local config_local;
from_json(config_local, as_json_value.get_object()).ensure();
return td::json_encode<std::string>(td::ToJson(config_local));
};
std::cout << decode_encode_local(config) << std::endl;
std::cout << decode_encode_local(config2) << std::endl;
auto create_vector_bytes = [] {
std::vector<td::BufferSlice> res;
res.emplace_back("fdjskld");
res.emplace_back("fdj\0kld");
res.emplace_back("fdj\0\x01\xff\x7fkld");
return res;
};
test_tl_json(ton::ton_api::make_object<ton::ton_api::testVectorBytes>(create_vector_bytes()));
}

376
test/test-node.cpp Normal file
View file

@ -0,0 +1,376 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "adnl/utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "dht/dht.h"
#include "overlay/overlays.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "catchain/catchain.h"
#include "crypto/common/refvector.hpp"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
template <std::size_t size>
std::ostream &operator<<(std::ostream &stream, const td::UInt<size> &x) {
for (size_t i = 0; i < size / 8; i++) {
stream << td::format::hex_digit((x.raw[i] >> 4) & 15) << td::format::hex_digit(x.raw[i] & 15);
}
return stream;
}
class TestNode : public td::actor::Actor {
private:
std::vector<td::UInt256> ping_ids_;
td::Timestamp next_dht_dump_;
td::actor::ActorOwn<ton::adnl::Adnl> adnl_;
std::vector<td::actor::ActorOwn<ton::dht::Dht>> dht_nodes_;
td::actor::ActorOwn<ton::overlay::Overlays> overlay_manager_;
std::vector<std::pair<td::UInt256, td::UInt256>> overlays_;
std::vector<td::actor::ActorOwn<ton::CatChain>> catchains_;
std::string local_config_ = "ton-local.config";
std::string global_config_ = "ton-global.config";
td::int32 broadcast_size_ = 100;
void receive_message(td::UInt256 src, td::UInt256 dst, td::BufferSlice data) {
LOG(ERROR) << "MESSAGE FROM " << src << " to " << dst << " of size " << std::to_string(data.size()) << "\n";
}
void receive_broadcast(td::UInt256 overlay_id, td::BufferSlice data) {
LOG(ERROR) << "BROADCAST IN " << overlay_id << " hash=" << td::sha256(data.as_slice()) << "\n";
}
void receive_query(td::UInt256 src, td::UInt256 dst, td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
auto Q = ton::fetch_tl_object<ton::ton_api::getTestObject>(std::move(data), true);
CHECK(Q.is_ok());
auto R = Q.move_as_ok();
LOG(ERROR) << "QUERY "
<< " FROM " << src << " to " << dst << ": " << ton::ton_api::to_string(R) << "\n";
promise.set_value(serialize_tl_object(ton::create_tl_object<ton::ton_api::testObject>(), true));
}
void catchain_new_block(td::UInt256 src, td::uint64 height, td::BufferSlice data) {
LOG(ERROR) << "CATCHAIN BLOCK: " << src << "@" << height << ": " << td::sha256_uint256(data.as_slice()) << "\n";
}
void catchain_bad_block(td::UInt256 src) {
LOG(ERROR) << "CATCHAIN BAD BLOCK\n";
}
void catchain_broadcast(td::BufferSlice data) {
LOG(ERROR) << "CATCHAIN BROADCAST " << td::sha256_uint256(data.as_slice()) << "\n";
}
std::unique_ptr<ton::adnl::Adnl::Callback> make_callback() {
class Callback : public ton::adnl::Adnl::Callback {
public:
void receive_message(td::UInt256 src, td::UInt256 dst, td::BufferSlice data) override {
td::actor::send_closure(id_, &TestNode::receive_message, src, dst, std::move(data));
}
void receive_query(td::UInt256 src, td::UInt256 dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &TestNode::receive_query, src, dst, std::move(data), std::move(promise));
}
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<TestNode> id_;
};
return std::make_unique<Callback>(actor_id(this));
}
std::unique_ptr<ton::CatChainActor::Callback> make_catchain_callback() {
class Callback : public ton::CatChainActor::Callback {
public:
void new_block(td::UInt256 src, td::uint64 height, td::BufferSlice data) override {
td::actor::send_closure(id_, &TestNode::catchain_new_block, src, height, std::move(data));
}
void bad_block(td::UInt256 src) override {
td::actor::send_closure(id_, &TestNode::catchain_bad_block, src);
}
void broadcast(td::BufferSlice data) override {
td::actor::send_closure(id_, &TestNode::catchain_broadcast, std::move(data));
}
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<TestNode> id_;
};
return std::make_unique<Callback>(actor_id(this));
}
std::unique_ptr<ton::overlay::Overlays::Callback> make_overlay_callback() {
class Callback : public ton::overlay::Overlays::Callback {
public:
void receive_message(td::UInt256 src, td::UInt256 overlay_id, td::BufferSlice data) override {
}
void receive_query(td::UInt256 src, td::uint64 query_id, td::UInt256 overlay_id, td::BufferSlice data) override {
}
void receive_broadcast(td::UInt256 overlay_id, td::BufferSlice data) override {
td::actor::send_closure(id_, &TestNode::receive_broadcast, overlay_id, std::move(data));
}
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<TestNode> id_;
};
return std::make_unique<Callback>(actor_id(this));
}
public:
void set_broadcast_size(td::int32 size) {
broadcast_size_ = size;
}
void set_local_config(std::string str) {
local_config_ = str;
}
void set_global_config(std::string str) {
global_config_ = str;
}
void start_up() override {
alarm_timestamp() = td::Timestamp::in(1);
}
void alarm() override {
/*if (overlays_.size() > 0 && broadcast_size_ > 0) {
td::BufferSlice s(broadcast_size_);
td::Random::secure_bytes(s.as_slice());
td::actor::send_closure(overlay_manager_, &ton::overlay::OverlayManager::send_broadcast_fer, overlays_[0].first,
overlays_[0].second, ton::create_tl_object<ton::ton_api::testString>(s.as_slice().str()));
}*/
for (auto &chain : catchains_) {
td::BufferSlice s(broadcast_size_);
td::Random::secure_bytes(s.as_slice());
td::actor::send_closure(chain, &ton::CatChainActor::add_event, std::move(s));
}
alarm_timestamp() = td::Timestamp::in(1.0);
if (next_dht_dump_.is_in_past()) {
/*for (auto &node : dht_nodes_) {
char b[10240];
td::StringBuilder sb({b, 10000});
node->get_actor_unsafe().dump(sb);
LOG(DEBUG) << sb.as_cslice().c_str();
}*/
next_dht_dump_ = td::Timestamp::in(60.0);
}
}
TestNode() {
adnl_ = ton::adnl::Adnl::create("/var/ton-work/db.adnl");
}
void run() {
auto L = td::read_file(local_config_).move_as_ok();
auto lc_j = td::json_decode(L.as_slice()).move_as_ok();
ton::ton_api::config_local lc;
ton::ton_api::from_json(lc, lc_j.get_object()).ensure();
auto G = td::read_file(global_config_).move_as_ok();
auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
ton::ton_api::config_global gc;
ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
for (auto &port : lc.udp_ports_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_listening_udp_port, "0.0.0.0",
static_cast<td::uint16>(port));
}
/*if (!lc.net_) {
LOG(FATAL) << "local config does not contain NET section";
}*/
//td::actor::send_closure(network_manager_, &ton::adnl::AdnlNetworkManager::load_local_config, std::move(lc.net_));
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_ids_from_config, std::move(lc.local_ids_));
if (gc.adnl_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_static_nodes_from_config,
std::move(gc.adnl_->static_nodes_));
}
if (!gc.dht_) {
LOG(FATAL) << "global config does not contain dht section";
}
for (auto &it : lc.dht_) {
if (it->get_id() == ton::ton_api::dht_config_local::ID) {
auto R = ton::dht::Dht::create_from_json(
ton::clone_tl_object(gc.dht_), ton::move_tl_object_as<ton::ton_api::dht_config_local>(it), adnl_.get());
if (R.is_error()) {
LOG(FATAL) << "fail creating dht node: " << R.move_as_error();
}
dht_nodes_.push_back(R.move_as_ok());
} else {
auto I = ton::move_tl_object_as<ton::ton_api::dht_config_random_local>(it);
for (int i = 0; i < I->cnt_; i++) {
auto R = ton::dht::Dht::create_random(ton::clone_tl_object(gc.dht_), ton::clone_tl_object(I->addr_list_),
adnl_.get());
if (R.is_error()) {
LOG(FATAL) << "fail creating dht node: " << R.move_as_error();
}
dht_nodes_.push_back(R.move_as_ok());
}
}
}
CHECK(dht_nodes_.size() > 0);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_dht_node, dht_nodes_[0].get());
//td::actor::send_closure(overlay_manager_, &ton::overlay::Overlays::register_dht_node, dht_nodes_[0].get());
overlay_manager_ = ton::overlay::Overlays::create(adnl_.get(), dht_nodes_[0].get());
for (auto &it : lc.public_overlays_) {
if (it->get_id() == ton::ton_api::overlay_config_local::ID) {
auto X = ton::move_tl_object_as<ton::ton_api::overlay_config_local>(it);
auto id = ton::create_tl_object<ton::ton_api::adnl_id_overlay>(X->name_.clone());
auto Id = ton::move_tl_object_as<ton::ton_api::adnl_id_Full>(id);
auto sid = ton::adnl_short_id(Id);
overlays_.emplace_back(X->id_->id_, sid);
td::actor::send_closure(overlay_manager_, &ton::overlay::Overlays::create_public_overlay, X->id_->id_,
std::move(Id), make_overlay_callback());
} else {
auto X = ton::move_tl_object_as<ton::ton_api::overlay_config_random_local>(it);
for (int i = 0; i < X->cnt_; i++) {
auto pk = ton::adnl_generate_random_pk();
auto local_id = ton::adnl_short_id(ton::get_public_key(pk));
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, std::move(pk), ton::clone_tl_object(X->addr_list_));
auto id = ton::create_tl_object<ton::ton_api::adnl_id_overlay>(X->name_.clone());
auto Id = ton::move_tl_object_as<ton::ton_api::adnl_id_Full>(id);
auto sid = ton::adnl_short_id(Id);
overlays_.emplace_back(local_id, sid);
td::actor::send_closure(overlay_manager_, &ton::overlay::Overlays::create_public_overlay, local_id,
std::move(Id), make_overlay_callback());
}
}
}
//auto C = ton::CatChainActor::create(nullptr, adnl_.get(), overlay_manager_.get(),
// std::vector<ton::tl_object_ptr<ton::ton_api::adnl_id_Full>>());
for (auto &it : lc.catchains_) {
auto tag = it->tag_;
for (auto &V : gc.catchains_) {
if (V->tag_ == tag) {
auto v = std::move(clone_tl_object(V)->nodes_);
auto C = ton::CatChainActor::create(make_catchain_callback(), adnl_.get(), overlay_manager_.get(),
std::move(v), it->id_->id_, tag);
catchains_.push_back(std::move(C));
}
}
}
}
};
td::Result<td::UInt256> get_uint256(std::string str) {
if (str.size() != 64) {
return td::Status::Error("uint256 must have 64 bytes");
}
td::UInt256 res;
for (size_t i = 0; i < 32; i++) {
res.raw[i] = static_cast<td::uint8>(td::hex_to_int(str[2 * i]) * 16 + td::hex_to_int(str[2 * i + 1]));
}
return res;
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_DEBUG);
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<TestNode> x;
td::OptionsParser p;
p.set_description("test basic adnl functionality");
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb({b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_global_config, fname.str());
return td::Status::OK();
});
p.add_option('c', "local-config", "file to read local config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_local_config, fname.str());
return td::Status::OK();
});
p.add_option('s', "broadcast-size", "size of broadcast", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_broadcast_size, std::atoi(fname.str().c_str()));
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
td::FileFd::Flags::Create | td::FileFd::Flags::Append | td::FileFd::Flags::Write)
.move_as_ok();
dup2(FileLog.get_native_fd().fd(), 1);
dup2(FileLog.get_native_fd().fd(), 2);
return td::Status::OK();
});
#endif
td::actor::Scheduler scheduler({2});
scheduler.run_in_context([&] { x = td::actor::create_actor<TestNode>("testnode"); });
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
scheduler.run_in_context([&] { td::actor::send_closure(x, &TestNode::run); });
scheduler.run();
return 0;
}

202
test/test-rldp.cpp Normal file
View file

@ -0,0 +1,202 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl-network-manager.h"
#include "adnl/adnl-test-loopback-implementation.h"
#include "adnl/adnl.h"
#include "rldp/rldp.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include <memory>
#include <set>
int main() {
SET_VERBOSITY_LEVEL(verbosity_INFO);
std::string db_root_ = "tmp-ee";
td::mkdir(db_root_).ensure();
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<ton::keyring::Keyring> keyring;
td::actor::ActorOwn<ton::adnl::TestLoopbackNetworkManager> network_manager;
td::actor::ActorOwn<ton::adnl::Adnl> adnl;
td::actor::ActorOwn<ton::rldp::Rldp> rldp;
ton::adnl::AdnlNodeIdShort src;
ton::adnl::AdnlNodeIdShort dst;
td::actor::Scheduler scheduler({7});
scheduler.run_in_context([&] {
keyring = ton::keyring::Keyring::create(db_root_);
network_manager = td::actor::create_actor<ton::adnl::TestLoopbackNetworkManager>("test net");
adnl = ton::adnl::Adnl::create(db_root_, keyring.get());
rldp = ton::rldp::Rldp::create(adnl.get());
td::actor::send_closure(adnl, &ton::adnl::Adnl::register_network_manager, network_manager.get());
auto pk1 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub1 = pk1.compute_public_key();
src = ton::adnl::AdnlNodeIdShort{pub1.compute_short_id()};
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {});
auto pk2 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub2 = pk2.compute_public_key();
dst = ton::adnl::AdnlNodeIdShort{pub2.compute_short_id()};
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk2), true, [](td::Unit) {});
auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list();
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr);
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub2}, addr);
td::actor::send_closure(rldp, &ton::rldp::Rldp::add_id, src);
td::actor::send_closure(rldp, &ton::rldp::Rldp::add_id, dst);
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_peer, src, ton::adnl::AdnlNodeIdFull{pub2}, addr);
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, src, true, true);
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, dst, true, true);
});
auto send_packet = [&](td::uint32 i) {
td::BufferSlice d{5};
d.as_slice()[0] = '1';
d.as_slice().remove_prefix(1).copy_from(td::Slice{reinterpret_cast<td::uint8 *>(&i), 4});
return d;
};
std::atomic<td::uint32> remaining{0};
scheduler.run_in_context([&] {
class Callback : public ton::adnl::Adnl::Callback {
public:
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data) override {
CHECK(src == src);
CHECK(dst == dst);
if (data.size() >= 5) {
CHECK(td::crc32c(data.as_slice().truncate(data.size() - 4)) ==
*reinterpret_cast<const td::uint32 *>(data.as_slice().remove_prefix(data.size() - 4).begin()));
}
CHECK(remaining_ > 0);
remaining_--;
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
CHECK(data.size() == 5);
td::uint32 s = *reinterpret_cast<const td::uint32 *>(data.as_slice().remove_prefix(1).begin());
td::BufferSlice d{s};
if (s >= 4) {
td::Random::secure_bytes(d.as_slice().truncate(s - 4));
auto x = td::crc32c(d.as_slice().truncate(d.size() - 4));
d.as_slice().remove_prefix(d.size() - 4).copy_from(td::Slice{reinterpret_cast<td::uint8 *>(&x), 4});
} else {
td::Random::secure_bytes(d.as_slice());
}
promise.set_value(std::move(d));
}
Callback(std::atomic<td::uint32> &remaining) : remaining_(remaining) {
}
private:
std::atomic<td::uint32> &remaining_;
};
td::actor::send_closure(adnl, &ton::adnl::Adnl::subscribe, dst, "1", std::make_unique<Callback>(remaining));
});
std::vector<td::uint32> sizes{1, 1024, 1 << 20, 2 << 20, 3 << 20, 10 << 20, 16 << 20};
for (auto &size : sizes) {
LOG(ERROR) << "testing delivering of packet of size " << size;
auto f = td::Clocks::system();
scheduler.run_in_context([&] {
remaining++;
td::actor::send_closure(rldp, &ton::rldp::Rldp::send_query_ex, src, dst, std::string("t"),
td::PromiseCreator::lambda([&](td::Result<td::BufferSlice> R) {
R.ensure();
remaining--;
}),
td::Timestamp::in(1024.0), send_packet(size), size + 1024);
});
auto t = td::Timestamp::in(1024.0);
while (scheduler.run(16)) {
if (!remaining) {
break;
}
if (t.is_in_past()) {
LOG(FATAL) << "failed to receive packets: remaining=" << remaining;
}
}
LOG(ERROR) << "success. Time=" << (td::Clocks::system() - f);
}
scheduler.run_in_context([&] {
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::set_loss_probability, 0.1);
});
LOG(ERROR) << "set loss to 10%";
for (auto &size : sizes) {
LOG(ERROR) << "testing delivering of packet of size " << size;
auto f = td::Clocks::system();
scheduler.run_in_context([&] {
remaining++;
td::actor::send_closure(rldp, &ton::rldp::Rldp::send_query_ex, src, dst, std::string("t"),
td::PromiseCreator::lambda([&](td::Result<td::BufferSlice> R) {
R.ensure();
remaining--;
}),
td::Timestamp::in(1024.0), send_packet(size), size + 1024);
});
auto t = td::Timestamp::in(1024.0);
while (scheduler.run(16)) {
if (!remaining) {
break;
}
if (t.is_in_past()) {
LOG(FATAL) << "failed to receive packets: remaining=" << remaining;
}
}
LOG(ERROR) << "success. Time=" << (td::Clocks::system() - f);
}
td::rmrf(db_root_).ensure();
std::_Exit(0);
return 0;
}

55
test/test-td-main.cpp Normal file
View file

@ -0,0 +1,55 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "td/utils/tests.h"
#include "td/utils/misc.h"
#include <cstring>
#include "td/utils/port/signals.h"
int main(int argc, char **argv) {
td::set_default_failure_signal_handler().ensure();
// TODO port OptionsParser to Windows
auto &runner = td::TestsRunner::get_default();
for (int i = 1; i < argc; i++) {
if (!std::strcmp(argv[i], "--filter")) {
CHECK(i + 1 < argc);
runner.add_substr_filter(argv[++i]);
} else if (!std::strcmp(argv[i], "--stress")) {
runner.set_stress_flag(true);
} else if (!std::strcmp(argv[i], "--regression")) {
CHECK(i + 1 < argc);
runner.set_regression_tester(td::RegressionTester::create(argv[++i]));
} else if (!std::strcmp(argv[i], "--verbosity")) {
CHECK(i + 1 < argc);
SET_VERBOSITY_LEVEL(td::to_integer<td::int32>(td::Slice(argv[++i])));
}
}
runner.run_all();
return 0;
}

446
test/test-ton-collator.cpp Normal file
View file

@ -0,0 +1,446 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "adnl/utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "dht/dht.h"
#include "overlay/overlays.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "catchain/catchain.h"
#include "validator-session/validator-session.h"
#include "validator/manager-disk.h"
#include "td/utils/filesystem.h"
#include "td/utils/port/path.h"
#include "validator/fabric.h"
#include "validator/impl/collator.h"
#include "crypto/vm/cp0.h"
#include "crypto/block/block-db.h"
#include "common/errorlog.h"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
int verbosity;
struct IntError {
std::string err_msg;
IntError(std::string _msg) : err_msg(_msg) {
}
IntError(const char *_msg) : err_msg(_msg) {
}
IntError(td::Status _err) : err_msg(_err.to_string()) {
}
void show() const {
std::cerr << "fatal: " << err_msg << std::endl;
}
};
class TestNode : public td::actor::Actor {
private:
td::actor::ActorOwn<ton::validator::ValidatorManagerInterface> validator_manager_;
std::string db_root_ = "/var/ton-work/db/";
ton::ZeroStateIdExt zero_id_;
td::BufferSlice bs_;
std::vector<td::BufferSlice> ext_msgs_;
std::vector<td::BufferSlice> top_shard_descrs_;
std::string zero_file_path_;
bool need_save_file_{false};
bool tdescr_save_{false};
std::string tdescr_pfx_;
ton::BlockIdExt shard_top_block_id_;
ton::ShardIdFull shard_{ton::masterchainId, ton::shardIdAll};
public:
void set_db_root(std::string db_root) {
db_root_ = db_root;
}
void set_zero_root_hash(td::Bits256 hash) {
zero_id_.root_hash = hash;
}
void set_zero_file_hash(td::Bits256 hash) {
zero_id_.file_hash = hash;
}
void set_shard(ton::ShardIdFull shard) {
LOG(DEBUG) << "setting shard to " << shard.to_str();
shard_ = shard;
}
void set_shard_top_block(ton::BlockIdExt block_id) {
shard_top_block_id_ = block_id;
}
void set_top_descr_prefix(std::string tdescr_pfx) {
tdescr_pfx_ = tdescr_pfx;
tdescr_save_ = true;
}
void set_collator_flags(int flags) {
ton::collator_settings |= flags;
}
void start_up() override {
}
void alarm() override {
}
TestNode() {
zero_id_.root_hash.clear();
zero_id_.file_hash.clear();
}
void set_zero_file(std::string filename) {
try {
auto res1 = block::load_binary_file(filename);
if (res1.is_error()) {
throw IntError{res1.move_as_error()};
}
bs_ = res1.move_as_ok();
auto res = ton::validator::create_shard_state(
ton::BlockIdExt{ton::BlockId{shard_.workchain, ton::shardIdAll, 0}, zero_id_.root_hash, zero_id_.file_hash},
bs_.clone());
if (res.is_error()) {
throw IntError{res.move_as_error()};
}
auto state = res.move_as_ok();
ton::FileHash fhash = block::compute_file_hash(bs_.as_slice());
ton::RootHash rhash = state->root_hash();
CHECK(!fhash.is_zero());
CHECK(!rhash.is_zero());
if (!zero_id_.root_hash.is_zero()) {
if (zero_id_.root_hash != rhash) {
throw IntError{std::string{"root hash mismatch: expected "} + zero_id_.root_hash.to_hex() + " found " +
rhash.to_hex()};
}
}
zero_id_.root_hash = rhash;
if (!zero_id_.file_hash.is_zero()) {
if (zero_id_.file_hash != fhash) {
throw IntError{std::string{"file hash mismatch: expected "} + zero_id_.file_hash.to_hex() + " found " +
fhash.to_hex()};
}
}
zero_id_.file_hash = fhash;
need_save_file_ = true;
zero_file_path_ = filename;
} catch (IntError err) {
err.show();
std::exit(7);
}
}
void load_ext_message(std::string filename) {
try {
auto res1 = block::load_binary_file(filename);
if (res1.is_error()) {
throw IntError{res1.move_as_error()};
}
ext_msgs_.emplace_back(res1.move_as_ok());
} catch (IntError err) {
err.show();
std::exit(7);
}
}
void load_shard_block_message(std::string filename) {
try {
auto res1 = block::load_binary_file(filename);
if (res1.is_error()) {
throw IntError{res1.move_as_error()};
}
top_shard_descrs_.emplace_back(res1.move_as_ok());
} catch (IntError err) {
err.show();
std::exit(7);
}
}
void do_save_file() {
std::string fname = db_root_ + "/static/";
fname.reserve(fname.size() + 2 * 3 + 64);
static const char hex_digits[] = "0123456789ABCDEF";
for (int i = 0; i < 2 * 0; i++) {
unsigned x = zero_id_.file_hash.data()[i];
fname.push_back(hex_digits[(x >> 4) & 15]);
fname.push_back(hex_digits[x & 15]);
fname.push_back('/');
td::mkdir(fname).ensure();
}
for (int i = 0; i < 32; i++) {
unsigned x = zero_id_.file_hash.data()[i];
fname.push_back(hex_digits[(x >> 4) & 15]);
fname.push_back(hex_digits[x & 15]);
}
auto res1 = block::load_binary_file(fname);
if (res1.is_ok()) {
if (res1.move_as_ok() != bs_) {
std::cerr << "fatal: " << fname << " has wrong content" << std::endl;
std::exit(7);
}
} else {
auto res = block::save_binary_file(fname, bs_.clone());
if (res.is_error()) {
std::cerr << "fatal: cannot write file " << fname << ": " << res.to_string();
std::exit(7);
}
}
}
void run() {
zero_id_.workchain = ton::masterchainId;
td::mkdir(db_root_).ensure();
ton::errorlog::ErrorLog::create(db_root_);
if (!shard_.is_masterchain() && need_save_file_) {
td::mkdir(db_root_ + "/static").ensure();
do_save_file();
}
auto opts = ton::validator::ValidatorManagerOptions::create(
ton::BlockIdExt{ton::masterchainId, ton::shardIdAll, 0, zero_id_.root_hash, zero_id_.file_hash},
ton::BlockIdExt{ton::masterchainId, ton::shardIdAll, 0, zero_id_.root_hash, zero_id_.file_hash});
opts.write().set_initial_sync_disabled(true);
validator_manager_ = ton::validator::ValidatorManagerDiskFactory::create(ton::PublicKeyHash::zero(), opts, shard_,
shard_top_block_id_, db_root_);
for (auto &msg : ext_msgs_) {
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManager::new_external_message,
std::move(msg));
}
for (auto &topmsg : top_shard_descrs_) {
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManager::new_shard_block, ton::BlockIdExt{},
0, std::move(topmsg));
}
class Callback : public ton::validator::ValidatorManagerInterface::Callback {
private:
td::actor::ActorId<ton::validator::ValidatorManagerInterface> id_;
bool tdescr_save_;
std::string tdescr_pfx_;
int tdescr_cnt_ = 0;
public:
Callback(td::actor::ActorId<ton::validator::ValidatorManagerInterface> id, bool tdescr_save = false,
std::string tdescr_pfx = "")
: id_(id), tdescr_save_(tdescr_save), tdescr_pfx_(tdescr_pfx) {
}
void initial_read_complete(ton::validator::BlockHandle handle) override {
td::actor::send_closure(id_, &ton::validator::ValidatorManager::sync_complete,
td::PromiseCreator::lambda([](td::Unit) {}));
}
void add_shard(ton::ShardIdFull) override {
}
void del_shard(ton::ShardIdFull) override {
}
void send_ihr_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override {
}
void send_ext_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override {
}
void send_shard_block_info(ton::BlockIdExt block_id, ton::CatchainSeqno cc_seqno, td::BufferSlice data) override {
++tdescr_cnt_;
if (!tdescr_save_) {
LOG(INFO) << "Ignoring newly-generated ShardTopBlockDescr for " << block_id.to_str();
} else {
char buffer[16];
sprintf(buffer, "%d.boc", tdescr_cnt_);
std::string fname = std::string{tdescr_pfx_.empty() ? "tdescr" : tdescr_pfx_} + buffer;
LOG(INFO) << "Saving newly-generated ShardTopBlockDescr for " << block_id.to_str() << " into file " << fname;
auto res = block::save_binary_file(fname, std::move(data));
if (res.is_error()) {
LOG(ERROR) << "Cannot save ShardTopBlockDescr for " << block_id.to_str() << " into file " << fname << " : "
<< res.move_as_error().to_string();
}
}
}
void send_broadcast(ton::BlockBroadcast broadcast) override {
}
void download_block(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<ton::ReceivedBlock> promise) override {
}
void download_zero_state(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override {
}
void download_persistent_state(ton::BlockIdExt block_id, ton::BlockIdExt masterchain_block_id,
td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override {
}
void download_block_proof(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override {
}
void download_block_proof_link(ton::BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override {
}
void get_next_key_blocks(ton::BlockIdExt block_id, td::Timestamp timeout,
td::Promise<std::vector<ton::BlockIdExt>> promise) override {
}
void new_key_block(ton::validator::BlockHandle handle) override {
}
};
td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::install_callback,
std::make_unique<Callback>(validator_manager_.get(), tdescr_save_, tdescr_pfx_),
td::PromiseCreator::lambda([](td::Unit) {}));
}
};
td::Result<td::Bits256> get_uint256(td::Slice str) {
TRY_RESULT(R, td::base64url_decode(str));
if (R.length() != 32) {
return td::Status::Error("uint256 must have 64 bytes");
}
td::Bits256 x;
as_slice(x).copy_from(td::Slice(R));
return x;
}
int parse_hex_digit(int c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
c |= 0x20;
if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
return -1;
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_default_failure_signal_handler().ensure();
CHECK(vm::init_op_cp0());
td::actor::ActorOwn<TestNode> x;
td::OptionsParser p;
p.set_description("test collate block");
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('Z', "zero-root-hash", "zero state root hash (base64url-encoded)", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_zero_root_hash, get_uint256(fname).move_as_ok());
return td::Status::OK();
});
p.add_option('F', "zero-file-hash", "zero state file hash (base64url-encoded)", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_zero_file_hash, get_uint256(fname).move_as_ok());
return td::Status::OK();
});
p.add_option('z', "zero-state-file", "zero state file", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_zero_file, fname.str());
return td::Status::OK();
});
p.add_option('D', "db", "root for dbs", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_db_root, fname.str());
return td::Status::OK();
});
p.add_option('m', "ext-message", "binary file with serialized inbound external message", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::load_ext_message, fname.str());
return td::Status::OK();
});
p.add_option('M', "top-shard-message", "binary file with serialized shard top block description",
[&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::load_shard_block_message, fname.str());
return td::Status::OK();
});
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
int v = VERBOSITY_NAME(FATAL) + (verbosity = td::to_integer<int>(arg));
SET_VERBOSITY_LEVEL(v);
return td::Status::OK();
});
p.add_option('w', "workchain", "<workchain>[:<shard>]\tcollate block in this workchain", [&](td::Slice arg) {
ton::ShardId shard = 0;
auto pos = std::min(arg.find(':'), arg.size());
TRY_RESULT(workchain, td::to_integer_safe<int>(arg.substr(0, pos)));
int s = 60;
while (++pos < arg.size()) {
int x = parse_hex_digit(arg[pos]);
if (x < 0 || s < 0) {
return td::Status::Error("cannot parse hexadecimal shard id (prefix)");
}
shard |= (ton::ShardId(x) << s);
s -= 4;
}
td::actor::send_closure(x, &TestNode::set_shard, ton::ShardIdFull{workchain, shard ? shard : ton::shardIdAll});
return td::Status::OK();
});
p.add_option('S', "want-split", "forces setting want_split in the header of new shard block", [&]() {
td::actor::send_closure(x, &TestNode::set_collator_flags, 1);
return td::Status::OK();
});
p.add_option('G', "want-merge", "forces setting want_merge in the header of new shard block", [&]() {
td::actor::send_closure(x, &TestNode::set_collator_flags, 2);
return td::Status::OK();
});
p.add_option('s', "save-top-descr", "saves generated shard top block description into files with specified prefix",
[&](td::Slice arg) {
td::actor::send_closure(x, &TestNode::set_top_descr_prefix, arg.str());
return td::Status::OK();
});
p.add_option('T', "top-block", "BlockIdExt of top block (new block will be generated atop of it)",
[&](td::Slice arg) {
ton::BlockIdExt block_id;
if (block::parse_block_id_ext(arg, block_id)) {
LOG(INFO) << "setting previous block to " << block_id.to_str();
td::actor::send_closure(x, &TestNode::set_shard_top_block, block_id);
return td::Status::OK();
} else {
return td::Status::Error("cannot parse BlockIdExt");
}
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
td::actor::Scheduler scheduler({7});
scheduler.run_in_context([&] { x = td::actor::create_actor<TestNode>("testnode"); });
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
scheduler.run_in_context([&] { td::actor::send_closure(x, &TestNode::run); });
scheduler.run();
return 0;
}

View file

@ -0,0 +1,236 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "adnl/utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "dht/dht.h"
#include "overlay/overlays.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "catchain/catchain.h"
#include "validator-session/validator-session.h"
#include "ton-node/ton-node.h"
#include "validator/manager.h"
#include "td/utils/filesystem.h"
#include "td/utils/port/path.h"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
template <std::size_t size>
std::ostream &operator<<(std::ostream &stream, const td::UInt<size> &x) {
for (size_t i = 0; i < size / 8; i++) {
stream << td::format::hex_digit((x.raw[i] >> 4) & 15) << td::format::hex_digit(x.raw[i] & 15);
}
return stream;
}
class TestNode : public td::actor::Actor {
private:
td::actor::ActorOwn<ton::adnl::Adnl> adnl_;
std::vector<td::actor::ActorOwn<ton::dht::Dht>> dht_nodes_;
td::actor::ActorOwn<ton::overlay::Overlays> overlay_manager_;
td::actor::ActorOwn<ton::ValidatorManager> validator_manager_;
td::actor::ActorOwn<ton::TonNodeManager> ton_node_;
std::vector<td::actor::ActorOwn<ton::adnl::AdnlFileTransfer>> file_transfers_;
std::string local_config_ = "ton-local.config";
std::string global_config_ = "ton-global.config";
std::string inst_id_ = "";
std::string db_root_ = "/var/ton-work/db/";
std::unique_ptr<ton::adnl::Adnl::Callback> make_callback() {
class Callback : public ton::adnl::Adnl::Callback {
public:
void receive_message(td::UInt256 src, td::UInt256 dst, td::BufferSlice data) override {
td::actor::send_closure(id_, &TestNode::adnl_receive_message, src, dst, std::move(data));
}
void receive_query(td::UInt256 src, td::UInt256 dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
}
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<TestNode> id_;
};
return std::make_unique<Callback>(actor_id(this));
}
public:
void adnl_receive_message(td::UInt256 src, td::UInt256 dst, td::BufferSlice data) {
LOG(ERROR) << "ADNL MESSAGE FROM " << src << ": size=" << data.size() << "\n";
}
void set_local_config(std::string str) {
local_config_ = str;
}
void set_local_id(std::string id) {
inst_id_ = id;
}
void set_global_config(std::string str) {
global_config_ = str;
}
void set_db_root(std::string db_root) {
db_root_ = db_root;
}
void start_up() override {
}
void alarm() override {
}
TestNode() {
}
void run() {
td::mkdir(db_root_).ensure();
auto L = td::read_file(local_config_).move_as_ok();
auto lc_j = td::json_decode(L.as_slice()).move_as_ok();
ton::ton_api::config_local lc;
ton::ton_api::from_json(lc, lc_j.get_object()).ensure();
auto G = td::read_file(global_config_).move_as_ok();
auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
ton::ton_api::config_global gc;
ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
CHECK(lc.dummy0_.size() == 1);
CHECK(gc.dummy0_.size() == 1);
validator_manager_ = ton::ValidatorManagerFactory::create(lc.dummy0_[0]->id_->id_, gc.dummy0_[0]->zero_state_hash_,
gc.dummy0_[0]->zero_state_hash_, db_root_, adnl_.get());
class Callback : public ton::ValidatorManager::Callback {
private:
td::actor::ActorId<ton::ValidatorManager> id_;
public:
Callback(td::actor::ActorId<ton::ValidatorManager> id) : id_(id) {
}
void initial_read_complete(ton::WorkchainId workchain, ton::ShardId shard, ton::adnl::AdnlNodeIdShort who,
std::vector<ton::BlockHandle> top_blocks) override {
td::actor::send_closure(id_, &ton::ValidatorManager::sync_complete, workchain, shard,
td::PromiseCreator::lambda([](td::Unit) {}));
}
void new_ihr_message(ton::WorkchainId workchain, ton::adnl::AdnlNodeIdShort who, td::UInt256 dst,
td::BufferSlice data) override {
}
void download_block(ton::BlockIdExt block_id, td::Timestamp timeout, ton::adnl::AdnlNodeIdShort who,
td::Promise<ton::ReceivedBlock> promise) override {
}
};
td::actor::send_closure(validator_manager_, &ton::ValidatorManager::install_callback,
std::make_unique<Callback>(validator_manager_.get()),
td::PromiseCreator::lambda([](td::Unit) {}));
}
};
td::Result<td::UInt256> get_uint256(std::string str) {
if (str.size() != 64) {
return td::Status::Error("uint256 must have 64 bytes");
}
td::UInt256 res;
for (size_t i = 0; i < 32; i++) {
res.raw[i] = static_cast<td::uint8>(td::hex_to_int(str[2 * i]) * 16 + td::hex_to_int(str[2 * i + 1]));
}
return res;
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<TestNode> x;
td::OptionsParser p;
p.set_description("test basic adnl functionality");
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_global_config, fname.str());
return td::Status::OK();
});
p.add_option('c', "local-config", "file to read local config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_local_config, fname.str());
return td::Status::OK();
});
p.add_option('i', "id", "id of instance", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_local_id, fname.str());
return td::Status::OK();
});
p.add_option('D', "db", "root for dbs", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_db_root, fname.str());
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
td::FileFd::Flags::Create | td::FileFd::Flags::Append | td::FileFd::Flags::Write)
.move_as_ok();
dup2(FileLog.get_native_fd().fd(), 1);
dup2(FileLog.get_native_fd().fd(), 2);
return td::Status::OK();
});
#endif
td::actor::Scheduler scheduler({7});
scheduler.run_in_context([&] { x = td::actor::create_actor<TestNode>("testnode"); });
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
scheduler.run_in_context([&] { td::actor::send_closure(x, &TestNode::run); });
scheduler.run();
return 0;
}

277
test/test-ton-dummy-0.cpp Normal file
View file

@ -0,0 +1,277 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "adnl/utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "dht/dht.h"
#include "overlay/overlays.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "catchain/catchain.h"
#include "validator-session/validator-session.h"
#include "ton-node/ton-node.h"
#include "validator/manager.h"
#include "td/utils/filesystem.h"
#include "td/utils/port/path.h"
#include "crypto/vm/cp0.h"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
template <std::size_t size>
std::ostream &operator<<(std::ostream &stream, const td::UInt<size> &x) {
for (size_t i = 0; i < size / 8; i++) {
stream << td::format::hex_digit((x.raw[i] >> 4) & 15) << td::format::hex_digit(x.raw[i] & 15);
}
return stream;
}
class TestNode : public td::actor::Actor {
private:
td::actor::ActorOwn<ton::Keyring> keyring_;
td::actor::ActorOwn<ton::adnl::Adnl> adnl_;
td::actor::ActorOwn<ton::rldp::Rldp> rldp_;
std::vector<td::actor::ActorOwn<ton::dht::Dht>> dht_nodes_;
td::actor::ActorOwn<ton::overlay::Overlays> overlay_manager_;
td::actor::ActorOwn<ton::ValidatorManager> validator_manager_;
td::actor::ActorOwn<ton::TonNodeManager> ton_node_;
std::string local_config_ = "ton-local.config";
std::string global_config_ = "ton-global.config";
std::string db_root_ = "/var/ton-work/db/";
std::string zero_state_ = "";
public:
void set_local_config(std::string str) {
local_config_ = str;
}
void set_global_config(std::string str) {
global_config_ = str;
}
void set_db_root(std::string db_root) {
db_root_ = db_root;
}
void set_zero_state(std::string zero_state) {
zero_state_ = zero_state;
}
void start_up() override {
}
void alarm() override {
}
TestNode() {
}
void run() {
td::mkdir(db_root_).ensure();
keyring_ = ton::Keyring::create();
adnl_ = ton::adnl::Adnl::create(db_root_, keyring_.get());
auto L = td::read_file(local_config_).move_as_ok();
auto lc_j = td::json_decode(L.as_slice()).move_as_ok();
ton::ton_api::config_local lc;
ton::ton_api::from_json(lc, lc_j.get_object()).ensure();
auto G = td::read_file(global_config_).move_as_ok();
auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
ton::ton_api::config_global gc;
ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
for (auto &port : lc.udp_ports_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_listening_udp_port, "0.0.0.0",
static_cast<td::uint16>(port));
}
/*if (!lc.net_) {
LOG(FATAL) << "local config does not contain NET section";
}*/
//td::actor::send_closure(network_manager_, &ton::adnl::AdnlNetworkManager::load_local_config, std::move(lc.net_));
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_ids_from_config, std::move(lc.local_ids_));
if (gc.adnl_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_static_nodes_from_config,
std::move(gc.adnl_->static_nodes_));
}
if (!gc.dht_) {
LOG(FATAL) << "global config does not contain dht section";
}
for (auto &it : lc.dht_) {
if (it->get_id() == ton::ton_api::dht_config_local::ID) {
auto R = ton::dht::Dht::create_from_json(ton::clone_tl_object(gc.dht_),
ton::move_tl_object_as<ton::ton_api::dht_config_local>(it),
keyring_.get(), adnl_.get());
if (R.is_error()) {
LOG(FATAL) << "fail creating dht node: " << R.move_as_error();
}
dht_nodes_.push_back(R.move_as_ok());
} else {
auto I = ton::move_tl_object_as<ton::ton_api::dht_config_random_local>(it);
for (int i = 0; i < I->cnt_; i++) {
auto R = ton::dht::Dht::create_random(ton::clone_tl_object(gc.dht_), ton::clone_tl_object(I->addr_list_),
keyring_.get(), adnl_.get());
if (R.is_error()) {
LOG(FATAL) << "fail creating dht node: " << R.move_as_error();
}
dht_nodes_.push_back(R.move_as_ok());
}
}
}
CHECK(dht_nodes_.size() > 0);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_dht_node, dht_nodes_[0].get());
//td::actor::send_closure(overlay_manager_, &ton::overlay::Overlays::register_dht_node, dht_nodes_[0].get());
overlay_manager_ = ton::overlay::Overlays::create(keyring_.get(), adnl_.get(), dht_nodes_[0].get());
//auto C = ton::CatChainActor::create(nullptr, adnl_.get(), overlay_manager_.get(),
// std::vector<ton::tl_object_ptr<ton::ton_api::adnl_id_Full>>());
CHECK(lc.dummy0_.size() <= 1);
CHECK(gc.dummy0_.size() <= 1);
if (lc.dummy0_.size() == 1) {
CHECK(gc.dummy0_.size() == 1);
auto zero_state_id = ton::BlockIdExt{ton::masterchainId, ton::shardIdAll, 0,
ton::UInt256_2_Bits256(gc.dummy0_[0]->zero_state_hash_),
ton::UInt256_2_Bits256(gc.dummy0_[0]->zero_state_hash_)};
validator_manager_ = ton::ValidatorManagerFactory::create(
ton::PublicKeyHash{lc.dummy0_[0]->id_->id_}, zero_state_id, "", zero_state_,
{ton::ShardIdFull{ton::basechainId, ton::shardIdAll}}, db_root_, keyring_.get(), adnl_.get(), rldp_.get(),
overlay_manager_.get());
ton_node_ =
ton::TonNodeManager::create(ton::adnl::AdnlNodeIdShort{lc.dummy0_[0]->id_->id_}, adnl_.get(), rldp_.get(),
dht_nodes_[0].get(), overlay_manager_.get(), validator_manager_.get(), db_root_);
for (auto &x : lc.liteservers_) {
auto pk = ton::PrivateKey{x->id_};
auto pub_k = ton::adnl::AdnlNodeIdFull{pk.compute_public_key()};
auto id = pub_k.compute_short_id();
td::actor::send_closure(keyring_, &ton::Keyring::add_key, std::move(pk));
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, pub_k, ton::adnl::AdnlAddressList{});
td::actor::send_closure(validator_manager_, &ton::ValidatorManager::add_ext_server_id, id);
td::actor::send_closure(validator_manager_, &ton::ValidatorManager::add_ext_server_port,
static_cast<td::uint16>(x->port_));
}
}
}
};
td::Result<td::UInt256> get_uint256(std::string str) {
if (str.size() != 64) {
return td::Status::Error("uint256 must have 64 bytes");
}
td::UInt256 res;
for (size_t i = 0; i < 32; i++) {
res.raw[i] = static_cast<td::uint8>(td::hex_to_int(str[2 * i]) * 16 + td::hex_to_int(str[2 * i + 1]));
}
return res;
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_default_failure_signal_handler().ensure();
CHECK(vm::init_op_cp0());
td::actor::ActorOwn<TestNode> x;
td::OptionsParser p;
p.set_description("test basic adnl functionality");
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
int v = VERBOSITY_NAME(FATAL) + (td::to_integer<int>(arg));
SET_VERBOSITY_LEVEL(v);
return td::Status::OK();
});
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_global_config, fname.str());
return td::Status::OK();
});
p.add_option('c', "local-config", "file to read local config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_local_config, fname.str());
return td::Status::OK();
});
p.add_option('i', "id", "id of instance", [&](td::Slice fname) { return td::Status::OK(); });
p.add_option('D', "db", "root for dbs", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_db_root, fname.str());
return td::Status::OK();
});
p.add_option('z', "zero-state", "file with serialized zero state", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_zero_state, fname.str());
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
td::FileFd::Flags::Create | td::FileFd::Flags::Append | td::FileFd::Flags::Write)
.move_as_ok();
dup2(FileLog.get_native_fd().fd(), 1);
dup2(FileLog.get_native_fd().fd(), 2);
return td::Status::OK();
});
#endif
td::actor::Scheduler scheduler({7});
scheduler.run_in_context([&] { x = td::actor::create_actor<TestNode>("testnode"); });
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
scheduler.run_in_context([&] { td::actor::send_closure(x, &TestNode::run); });
scheduler.run();
return 0;
}

View file

@ -0,0 +1,996 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include "validator-session/validator-session-description.h"
#include "validator-session/validator-session-state.h"
#include <memory>
#include <set>
class Description : public ton::validatorsession::ValidatorSessionDescription {
public:
HashType compute_hash(td::Slice data) const override {
return td::crc32c(data);
}
HashType zero_hash() const {
return 0;
}
void *alloc(size_t size, size_t align, bool temp) override {
td::uint32 idx = temp ? 1 : 0;
auto s = pdata_cur_[idx].fetch_add(size);
CHECK(s + size <= pdata_size_[idx]);
return static_cast<void *>(pdata_[idx] + s);
}
bool is_persistent(const void *ptr) const override {
return ptr == nullptr || (ptr >= pdata_[0] && ptr < pdata_[0] + pdata_size_[0]);
}
void clear_temp_memory() override {
pdata_cur_[1] = 0;
}
ton::PublicKeyHash get_source_id(td::uint32 idx) const override {
CHECK(idx < total_nodes_);
td::Bits256 x = td::Bits256::zero();
auto &d = x.as_array();
d[0] = static_cast<td::uint8>(idx);
return ton::PublicKeyHash{x};
}
ton::PublicKey get_source_public_key(td::uint32 idx) const override {
UNREACHABLE();
}
ton::adnl::AdnlNodeIdShort get_source_adnl_id(td::uint32 idx) const override {
UNREACHABLE();
}
td::uint32 get_source_idx(ton::PublicKeyHash id) const override {
auto x = id.bits256_value();
auto y = x.as_array();
return y[0];
}
ton::ValidatorWeight get_node_weight(td::uint32 idx) const override {
return 1;
}
td::uint32 get_total_nodes() const override {
return total_nodes_;
}
ton::ValidatorWeight get_cutoff_weight() const override {
return 2 * total_nodes_ / 3 + 1;
}
ton::ValidatorWeight get_total_weight() const override {
return total_nodes_;
}
td::int32 get_node_priority(td::uint32 src_idx, td::uint32 round) const override {
round %= get_total_nodes();
if (src_idx < round) {
src_idx += get_total_nodes();
}
if (src_idx - round < opts_.round_candidates) {
return src_idx - round;
}
return -1;
}
td::uint32 get_max_priority() const override {
return opts_.round_candidates - 1;
}
td::uint32 get_unixtime(td::uint64 ts) const override {
return static_cast<td::uint32>(ts >> 32);
}
td::uint32 get_attempt_seqno(td::uint64 ts) const override {
return get_unixtime(ts) / opts_.round_attempt_duration;
}
td::uint32 get_self_idx() const override {
UNREACHABLE();
}
td::uint64 get_ts() const override {
auto tm = td::Clocks::system();
CHECK(tm >= 0);
auto t = static_cast<td::uint32>(tm);
auto t2 = static_cast<td::uint64>((1ll << 32) * (tm - t));
CHECK(t2 < (1ull << 32));
return ((t * 1ull) << 32) + t2;
}
const RootObject *get_by_hash(HashType hash, bool allow_temp) const override {
auto x = hash % cache_size;
return cache_[x].load(std::memory_order_relaxed).ptr;
}
void update_hash(const RootObject *obj, HashType hash) override {
if (!is_persistent(obj)) {
return;
}
auto x = hash % cache_size;
Cached p{obj};
cache_[x].store(p, std::memory_order_relaxed);
}
void on_reuse() override {
}
td::Timestamp attempt_start_at(td::uint32 att) const override {
return td::Timestamp::at_unix(att * opts_.round_attempt_duration);
}
ton::validatorsession::ValidatorSessionCandidateId candidate_id(
td::uint32 src_idx, ton::validatorsession::ValidatorSessionRootHash root_hash,
ton::validatorsession::ValidatorSessionFileHash file_hash,
ton::validatorsession::ValidatorSessionCollatedDataFileHash collated_data_file_hash) const override {
auto obj = ton::create_tl_object<ton::ton_api::validatorSession_candidateId>(get_source_id(src_idx).tl(), root_hash,
file_hash, collated_data_file_hash);
return get_tl_object_sha_bits256(obj);
}
td::Status check_signature(ton::validatorsession::ValidatorSessionRootHash root_hash,
ton::validatorsession::ValidatorSessionFileHash file_hash, td::uint32 src_idx,
td::Slice signature) const override {
if (signature.size() == 0) {
return td::Status::Error("wrong size");
}
if (signature[0] == 126) {
return td::Status::OK();
} else {
return td::Status::Error("invalid");
}
}
td::Status check_approve_signature(ton::validatorsession::ValidatorSessionRootHash root_hash,
ton::validatorsession::ValidatorSessionFileHash file_hash, td::uint32 src_idx,
td::Slice signature) const override {
if (signature.size() == 0) {
return td::Status::Error("wrong size");
}
if (signature[0] == 127) {
return td::Status::OK();
} else {
return td::Status::Error("invalid");
}
}
double get_delay(td::uint32 priority) const override {
return 0;
}
double get_empty_block_delay() const override {
return 0;
}
std::vector<ton::catchain::CatChainNode> export_catchain_nodes() const override {
UNREACHABLE();
}
td::uint32 get_vote_for_author(td::uint32 attempt_seqno) const override {
return attempt_seqno % total_nodes_;
}
const ton::validatorsession::ValidatorSessionOptions &opts() const override {
return opts_;
}
~Description() {
delete[] pdata_[0];
delete[] pdata_[1];
}
Description(ton::validatorsession::ValidatorSessionOptions opts, td::uint32 total_nodes)
: opts_(opts), total_nodes_(total_nodes) {
pdata_size_[0] = 1ull << 33;
pdata_size_[1] = 1 << 22;
pdata_[0] = new td::uint8[pdata_size_[0]];
pdata_[1] = new td::uint8[pdata_size_[1]];
pdata_cur_[0] = 0;
pdata_cur_[1] = 0;
for (auto &el : cache_) {
Cached v{nullptr};
el.store(v, std::memory_order_relaxed);
}
CHECK(total_nodes_ > 0);
}
private:
ton::validatorsession::ValidatorSessionOptions opts_;
td::uint32 total_nodes_;
static constexpr td::uint32 cache_size = (1 << 20);
struct Cached {
const RootObject *ptr;
};
std::array<std::atomic<Cached>, cache_size> cache_;
td::uint8 *pdata_[2];
std::atomic<size_t> pdata_cur_[2];
size_t pdata_size_[2];
};
double myrand() {
return td::Random::fast(0, 100) * 0.01;
}
int main() {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_default_failure_signal_handler().ensure();
td::uint32 total_nodes = 100;
ton::validatorsession::ValidatorSessionOptions opts;
{
auto descptr = new Description(opts, total_nodes);
auto &desc = *descptr;
auto c1 = desc.candidate_id(0, td::Bits256::zero(), td::Bits256::zero(), td::Bits256::zero());
auto c2 = desc.candidate_id(1, td::Bits256::zero(), td::Bits256::zero(), td::Bits256::zero());
CHECK(c1 != c2);
auto s = ton::validatorsession::ValidatorSessionState::create(desc);
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
auto att = 1000000000;
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID);
}
{
auto act = ton::create_tl_object<ton::ton_api::validatorSession_message_submittedBlock>(
0, ton::Bits256::zero(), ton::Bits256::zero(), ton::Bits256::zero());
s = ton::validatorsession::ValidatorSessionState::action(desc, s, 1, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID) << act.get();
}
for (td::uint32 i = 0; i < total_nodes; i++) {
bool found;
s->choose_block_to_sign(desc, i, found);
CHECK(!found);
auto vec = s->choose_blocks_to_approve(desc, i);
LOG_CHECK(vec.size() == 2) << vec.size();
CHECK(vec[0]);
CHECK(ton::validatorsession::SentBlock::get_block_id(vec[0]) == c2);
CHECK(vec[1] == nullptr);
CHECK(ton::validatorsession::SentBlock::get_block_id(vec[1]) == ton::validatorsession::skip_round_candidate_id());
}
for (td::uint32 i = 0; i < 2 * total_nodes / 3; i++) {
td::BufferSlice sig{1};
sig.as_slice()[0] = 127;
auto act = ton::create_tl_object<ton::ton_api::validatorSession_message_approvedBlock>(0, c2, std::move(sig));
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID) << act.get();
}
for (td::uint32 i = 2 * total_nodes / 3; i < total_nodes; i++) {
td::BufferSlice sig{1};
sig.as_slice()[0] = 127;
auto act = ton::create_tl_object<ton::ton_api::validatorSession_message_approvedBlock>(0, c2, std::move(sig));
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
for (td::uint32 i = 0; i < total_nodes; i++) {
bool found;
s->choose_block_to_sign(desc, i, found);
CHECK(!found);
auto vec = s->choose_blocks_to_approve(desc, i);
CHECK(vec.size() == 1);
CHECK(vec[1] == nullptr);
CHECK(ton::validatorsession::SentBlock::get_block_id(vec[1]) == ton::validatorsession::skip_round_candidate_id());
}
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_vote::ID) << act.get();
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
auto act2 = s->create_action(desc, i, att);
if (i < 2 * total_nodes / 3) {
LOG_CHECK(act2->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act2.get();
} else {
LOG_CHECK(act2->get_id() == ton::ton_api::validatorSession_message_precommit::ID)
<< "i=" << i << " " << act2.get();
}
}
for (td::uint32 j = 1; j < opts.max_round_attempts; j++) {
auto act = s->create_action(desc, 0, att + j);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_vote::ID) << "j=" << j << " " << act.get();
}
for (td::uint32 j = opts.max_round_attempts; j < opts.max_round_attempts + 10; j++) {
auto act = s->create_action(desc, 0, att + j);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "j=" << j << " " << act.get();
}
auto s_copy = s;
auto att_copy = att;
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
if (i <= 2 * total_nodes / 3) {
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_precommit::ID)
<< "i=" << i << " " << act.get();
} else {
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act.get();
}
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
auto act2 = s->create_action(desc, i, att);
LOG_CHECK(act2->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act2.get();
}
att += 10;
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act.get();
}
for (td::uint32 i = 0; i < total_nodes; i++) {
bool found;
auto block = s->choose_block_to_sign(desc, i, found);
CHECK(found);
CHECK(ton::validatorsession::SentBlock::get_block_id(block) == c2);
}
for (td::uint32 i = 0; i < 2 * total_nodes / 3; i++) {
td::BufferSlice sig{1};
sig.as_slice()[0] = 126;
auto act = ton::create_tl_object<ton::ton_api::validatorSession_message_commit>(0, c2, std::move(sig));
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
CHECK(s->cur_round_seqno() == 0);
for (td::uint32 i = 2 * total_nodes / 3; i < total_nodes; i++) {
td::BufferSlice sig{1};
sig.as_slice()[0] = 126;
auto act = ton::create_tl_object<ton::ton_api::validatorSession_message_commit>(0, c2, std::move(sig));
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
CHECK(s->cur_round_seqno() == 1);
auto sigs = s->get_committed_block_signatures(desc, 0);
for (td::uint32 i = 0; i < sigs->size(); i++) {
auto S = sigs->at(i);
CHECK(S);
}
s = s_copy;
att = att_copy;
for (td::uint32 i = 0; i < total_nodes / 3; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_precommit::ID) << "i=" << i << " " << act.get();
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
auto act2 = s->create_action(desc, i, att);
LOG_CHECK(act2->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act2.get();
}
att += opts.max_round_attempts - 1;
do {
att++;
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
if (i < total_nodes / 3) {
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_vote::ID) << "i=" << i << " " << act.get();
} else {
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act.get();
}
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
auto act2 = s->create_action(desc, i, att);
LOG_CHECK(act2->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act2.get();
}
desc.clear_temp_memory();
} while (desc.get_vote_for_author(att) < total_nodes / 3);
{
auto act = ton::create_tl_object<ton::ton_api::validatorSession_message_submittedBlock>(
0, ton::Bits256::zero(), ton::Bits256::zero(), ton::Bits256::zero());
s = ton::validatorsession::ValidatorSessionState::action(desc, s, 0, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
auto idx = desc.get_vote_for_author(att);
for (td::uint32 i = 0; i < total_nodes; i++) {
LOG_CHECK(s->check_need_generate_vote_for(desc, i, att) == (i == idx))
<< i << " " << idx << " " << s->check_need_generate_vote_for(desc, i, att);
}
for (td::uint32 i = 0; i < total_nodes; i++) {
td::BufferSlice sig{1};
sig.as_slice()[0] = 127;
auto act = ton::create_tl_object<ton::ton_api::validatorSession_message_approvedBlock>(0, c1, std::move(sig));
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
{
auto act = s->generate_vote_for(desc, idx, att);
CHECK(act);
act->candidate_ = c1;
s = ton::validatorsession::ValidatorSessionState::action(desc, s, idx, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
td::BufferSlice buf{10240};
td::StringBuilder sb{buf.as_slice()};
s->dump(desc, sb, att);
LOG(ERROR) << sb.as_cslice();
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
if (i < total_nodes / 3) {
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act.get();
} else {
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_vote::ID) << "i=" << i << " " << act.get();
}
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
att++;
idx = desc.get_vote_for_author(att);
for (td::uint32 i = 0; i < total_nodes; i++) {
LOG_CHECK(s->check_need_generate_vote_for(desc, i, att) == (i == idx))
<< i << " " << idx << " " << s->check_need_generate_vote_for(desc, i, att);
}
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act.get();
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
{
auto act = s->generate_vote_for(desc, idx, att);
CHECK(act);
act->candidate_ = c1;
s = ton::validatorsession::ValidatorSessionState::action(desc, s, idx, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_vote::ID) << "i=" << i << " " << act.get();
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
for (td::uint32 i = 0; i < total_nodes / 3; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_precommit::ID) << "i=" << i << " " << act.get();
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
auto act2 = s->create_action(desc, i, att);
LOG_CHECK(act2->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act2.get();
}
att++;
idx = desc.get_vote_for_author(att);
{
auto act = s->generate_vote_for(desc, idx, att);
CHECK(act);
act->candidate_ = c1;
s = ton::validatorsession::ValidatorSessionState::action(desc, s, idx, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_vote::ID) << "i=" << i << " " << act.get();
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
for (td::uint32 i = 0; i < total_nodes; i++) {
auto act = s->create_action(desc, i, att);
CHECK(act);
if (i <= 2 * total_nodes / 3) {
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_precommit::ID)
<< "i=" << i << " " << act.get();
} else {
LOG_CHECK(act->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act.get();
}
s = ton::validatorsession::ValidatorSessionState::action(desc, s, i, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
auto act2 = s->create_action(desc, i, att);
LOG_CHECK(act2->get_id() == ton::ton_api::validatorSession_message_empty::ID) << "i=" << i << " " << act2.get();
}
delete descptr;
}
{
auto descptr = new Description(opts, total_nodes);
auto &desc = *descptr;
auto sig1 = ton::validatorsession::SessionBlockCandidateSignature::create(desc, td::BufferSlice{"a"});
auto sig2 = ton::validatorsession::SessionBlockCandidateSignature::create(desc, td::BufferSlice{"b"});
auto sig3 = ton::validatorsession::SessionBlockCandidateSignature::create(desc, td::BufferSlice{"c"});
auto sig4 = ton::validatorsession::SessionBlockCandidateSignature::create(desc, td::BufferSlice{"d"});
{
auto m1 = ton::validatorsession::SessionBlockCandidateSignature::merge(desc, sig1, sig2);
CHECK(m1->as_slice() == "a");
auto m2 = ton::validatorsession::SessionBlockCandidateSignature::merge(desc, sig2, sig1);
CHECK(m2->as_slice() == "a");
}
std::vector<const ton::validatorsession::SessionBlockCandidateSignature *> sig_vec_null;
sig_vec_null.resize(desc.get_total_nodes(), nullptr);
auto sig_vec1 = ton::validatorsession::SessionBlockCandidateSignatureVector::create(desc, sig_vec_null);
auto sig_vec2 = ton::validatorsession::SessionBlockCandidateSignatureVector::create(desc, sig_vec_null);
sig_vec1 = ton::validatorsession::SessionBlockCandidateSignatureVector::change(desc, sig_vec1, 0, sig1);
sig_vec1 = ton::validatorsession::SessionBlockCandidateSignatureVector::change(desc, sig_vec1, 1, sig3);
sig_vec2 = ton::validatorsession::SessionBlockCandidateSignatureVector::change(desc, sig_vec2, 0, sig4);
sig_vec2 = ton::validatorsession::SessionBlockCandidateSignatureVector::change(desc, sig_vec2, 1, sig2);
sig_vec2 = ton::validatorsession::SessionBlockCandidateSignatureVector::change(desc, sig_vec2, 2, sig4);
{
auto m1 = ton::validatorsession::SessionBlockCandidateSignatureVector::merge(
desc, sig_vec1, sig_vec2, [&](const auto l, const auto r) {
return ton::validatorsession::SessionBlockCandidateSignature::merge(desc, l, r);
});
CHECK(m1->at(0)->as_slice() == "a");
CHECK(m1->at(1)->as_slice() == "b");
CHECK(m1->at(2)->as_slice() == "d");
CHECK(!m1->at(3));
auto m2 = ton::validatorsession::SessionBlockCandidateSignatureVector::merge(
desc, sig_vec2, sig_vec1, [&](const auto l, const auto r) {
return ton::validatorsession::SessionBlockCandidateSignature::merge(desc, l, r);
});
CHECK(m2->at(0)->as_slice() == "a");
CHECK(m2->at(1)->as_slice() == "b");
CHECK(m2->at(2)->as_slice() == "d");
CHECK(!m2->at(3));
}
auto sentb = ton::validatorsession::SentBlock::create(desc, 0, ton::Bits256::zero(), ton::Bits256::zero(),
ton::Bits256::zero());
//auto sentb2 = ton::validatorsession::SentBlock::create(desc, 1, ton::Bits256::zero(), ton::Bits256::zero(),
// ton::Bits256::zero());
auto cand1 = ton::validatorsession::SessionBlockCandidate::create(desc, sentb, sig_vec1);
auto cand2 = ton::validatorsession::SessionBlockCandidate::create(desc, sentb, sig_vec2);
{
auto m1 = ton::validatorsession::SessionBlockCandidate::merge(desc, cand1, cand2);
CHECK(m1->get_block() == sentb);
CHECK(m1->get_approvers_list()->at(0)->as_slice() == "a");
CHECK(m1->get_approvers_list()->at(1)->as_slice() == "b");
CHECK(m1->get_approvers_list()->at(2)->as_slice() == "d");
CHECK(!m1->get_approvers_list()->at(3));
auto m2 = ton::validatorsession::SessionBlockCandidate::merge(desc, cand2, cand1);
CHECK(m2->get_block() == sentb);
CHECK(m2->get_approvers_list()->at(0)->as_slice() == "a");
CHECK(m2->get_approvers_list()->at(1)->as_slice() == "b");
CHECK(m2->get_approvers_list()->at(2)->as_slice() == "d");
CHECK(!m2->get_approvers_list()->at(3));
}
std::vector<bool> vote_vec_1;
vote_vec_1.resize(desc.get_total_nodes());
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
vote_vec_1[i] = td::Random::fast(0, 1) == 0;
}
std::vector<bool> vote_vec_2;
vote_vec_2.resize(desc.get_total_nodes());
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
vote_vec_2[i] = td::Random::fast(0, 1) == 0;
}
auto vote_t1 = ton::validatorsession::SessionVoteCandidate::create(
desc, sentb, ton::validatorsession::CntVector<bool>::create(desc, vote_vec_1));
auto vote_t2 = ton::validatorsession::SessionVoteCandidate::create(
desc, sentb, ton::validatorsession::CntVector<bool>::create(desc, vote_vec_2));
{
auto m = ton::validatorsession::SessionVoteCandidate::merge(desc, vote_t1, vote_t2);
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
CHECK(m->check_block_is_voted_by(i) == vote_t1->check_block_is_voted_by(i) ||
vote_t2->check_block_is_voted_by(i));
}
}
std::vector<bool> vote_vec;
vote_vec.resize(desc.get_total_nodes(), false);
auto vote1 = ton::validatorsession::SessionVoteCandidate::create(
desc, nullptr, ton::validatorsession::CntVector<bool>::create(desc, vote_vec));
auto vote1d = ton::validatorsession::SessionVoteCandidate::create(
desc, sentb, ton::validatorsession::CntVector<bool>::create(desc, vote_vec));
auto vote2 = ton::validatorsession::SessionVoteCandidate::create(
desc, sentb, ton::validatorsession::CntVector<bool>::create(desc, vote_vec));
auto vote2d = ton::validatorsession::SessionVoteCandidate::create(
desc, sentb, ton::validatorsession::CntVector<bool>::create(desc, vote_vec));
CHECK(ton::validatorsession::SessionVoteCandidate::Compare()(vote1, vote2));
CHECK(!ton::validatorsession::SessionVoteCandidate::Compare()(vote2, vote1));
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
if (i < desc.get_cutoff_weight()) {
vote1 = ton::validatorsession::SessionVoteCandidate::push(desc, vote1, i);
} else {
vote2 = ton::validatorsession::SessionVoteCandidate::push(desc, vote2, i);
}
if (i < desc.get_cutoff_weight() - 1) {
vote1d = ton::validatorsession::SessionVoteCandidate::push(desc, vote1d, i);
} else {
vote2d = ton::validatorsession::SessionVoteCandidate::push(desc, vote2d, i);
}
}
auto v = ton::validatorsession::VoteVector::create(desc, {vote1, vote2});
auto prec0_vec = ton::validatorsession::CntVector<bool>::create(desc, vote_vec);
auto prec1_vec = ton::validatorsession::CntVector<bool>::change(desc, prec0_vec, 0, true);
auto prec2_vec = ton::validatorsession::CntVector<bool>::change(desc, prec0_vec, 1, true);
auto att0_0 =
ton::validatorsession::ValidatorSessionRoundAttemptState::create(desc, 1, v, prec1_vec, nullptr, false);
bool f;
CHECK(att0_0->get_voted_block(desc, f) == nullptr);
CHECK(f);
auto att1_0 = ton::validatorsession::ValidatorSessionRoundAttemptState::create(
desc, 2, ton::validatorsession::VoteVector::create(desc, {vote1d}), prec0_vec, nullptr, false);
CHECK(att1_0->get_voted_block(desc, f) == nullptr);
CHECK(!f);
auto att1_1 = ton::validatorsession::ValidatorSessionRoundAttemptState::create(
desc, 2, ton::validatorsession::VoteVector::create(desc, {vote2d}), prec0_vec, nullptr, false);
CHECK(att1_1->get_voted_block(desc, f) == nullptr);
CHECK(!f);
auto att2_0 =
ton::validatorsession::ValidatorSessionRoundAttemptState::create(desc, 3, v, prec2_vec, nullptr, false);
CHECK(att2_0->get_voted_block(desc, f) == nullptr);
CHECK(f);
{
auto m = ton::validatorsession::ValidatorSessionRoundAttemptState::merge(desc, att1_0, att1_1);
CHECK(m->get_voted_block(desc, f) == sentb);
CHECK(f);
}
std::vector<td::uint32> first_att_1;
first_att_1.resize(desc.get_total_nodes());
std::vector<td::uint32> first_att_2;
first_att_2.resize(desc.get_total_nodes());
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
first_att_1[i] = td::Random::fast(0, 1000000000);
first_att_2[i] = td::Random::fast(0, 1000000000);
}
std::vector<td::uint32> last_precommit0;
last_precommit0.resize(desc.get_total_nodes());
last_precommit0[0] = 1;
last_precommit0[1] = 3;
std::vector<td::uint32> last_precommit1;
last_precommit1.resize(desc.get_total_nodes());
auto r1 = ton::validatorsession::ValidatorSessionRoundState::create(
desc, nullptr, 0, false, ton::validatorsession::CntVector<td::uint32>::create(desc, first_att_1),
ton::validatorsession::CntVector<td::uint32>::create(desc, last_precommit0), nullptr, sig_vec1,
ton::validatorsession::AttemptVector::create(desc, {att0_0, att1_0, att2_0}));
CHECK(r1->get_last_precommit(0) == 1);
CHECK(r1->get_last_precommit(1) == 3);
auto r2 = ton::validatorsession::ValidatorSessionRoundState::create(
desc, nullptr, 0, false, ton::validatorsession::CntVector<td::uint32>::create(desc, first_att_2),
ton::validatorsession::CntVector<td::uint32>::create(desc, last_precommit1), nullptr, sig_vec2,
ton::validatorsession::AttemptVector::create(desc, {att1_1}));
{
auto m = ton::validatorsession::ValidatorSessionRoundState::merge(desc, r1, r2);
CHECK(m);
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
CHECK(m->get_first_attempt(i) == first_att_1[i]
? first_att_2[i] ? std::min(first_att_1[i], first_att_2[i]) : first_att_1[i]
: first_att_2[i]);
}
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
if (i == 1) {
CHECK(m->get_last_precommit(i) == 3);
} else {
CHECK(m->get_last_precommit(i) == 0);
}
}
}
delete descptr;
}
for (td::uint32 ver = 0; ver < 2; ver++) {
double sign_prob = 1.0;
double submit_prob = 0.8;
double approve_prob = 0.5;
double blocks_per_sec_per_node = 0.5;
auto descptr = new Description(opts, total_nodes);
auto &desc = *descptr;
auto adj_total_nodes = total_nodes + (ver ? total_nodes / 3 : 0);
std::vector<std::vector<const ton::validatorsession::ValidatorSessionState *>> states;
states.resize(adj_total_nodes);
td::uint64 ts = desc.get_ts();
auto virt_state = ton::validatorsession::ValidatorSessionState::create(desc);
virt_state = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, virt_state);
for (td::uint32 ri = 0; ri < 100000; ri++) {
auto ts_adj = ts;
auto att = desc.get_attempt_seqno(ts_adj);
//auto virt_round = virt_state->cur_round_seqno();
auto virt_x = desc.get_vote_for_author(att);
td::int32 x = virt_x;
if (!virt_state->check_need_generate_vote_for(desc, virt_x, att) || myrand() < 0.5) {
x = td::Random::fast(0, total_nodes - 1);
}
auto adj_x = x;
if (x + total_nodes < adj_total_nodes && td::Random::fast(0, 1) == 0) {
adj_x += total_nodes;
}
const ton::validatorsession::ValidatorSessionState *s;
if (states[adj_x].size() == 0) {
s = ton::validatorsession::ValidatorSessionState::create(desc);
} else {
s = *states[adj_x].rbegin();
}
for (td::uint32 z = 0; z < 3; z++) {
auto y = td::Random::fast(0, adj_total_nodes - 2);
if (adj_x <= y) {
y++;
}
if (states[y].size() > 0) {
auto k = td::Random::fast(static_cast<td::int32>(states[y].size() - 2),
static_cast<td::int32>(states[y].size() - 1));
if (k < 0) {
k = 0;
}
s = ton::validatorsession::ValidatorSessionState::merge(desc, s, states[y][k]);
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
}
auto round = s->cur_round_seqno();
if (desc.get_node_priority(x, round) >= 0 && myrand() <= submit_prob && !s->check_block_is_sent_by(desc, x)) {
auto act = ton::create_tl_object<ton::ton_api::validatorSession_message_submittedBlock>(
round, ton::Bits256::zero(), ton::Bits256::zero(), ton::Bits256::zero());
s = ton::validatorsession::ValidatorSessionState::action(desc, s, x, att, act.get());
CHECK(s);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
}
auto vec = s->choose_blocks_to_approve(desc, x);
if (vec.size() > 0 && myrand() <= approve_prob) {
auto B = vec[td::Random::fast(0, static_cast<td::uint32>(vec.size() - 1))];
auto id = ton::validatorsession::SentBlock::get_block_id(B);
td::BufferSlice sig{B ? 1u : 0u};
if (B) {
sig.as_slice()[0] = 127;
}
auto act =
ton::create_tl_object<ton::ton_api::validatorSession_message_approvedBlock>(round, id, std::move(sig));
s = ton::validatorsession::ValidatorSessionState::action(desc, s, x, att, act.get());
CHECK(s);
}
bool found;
auto to_sign = s->choose_block_to_sign(desc, x, found);
if (found && myrand() <= sign_prob) {
auto id = ton::validatorsession::SentBlock::get_block_id(to_sign);
td::BufferSlice sig{to_sign ? 1u : 0u};
if (to_sign) {
sig.as_slice()[0] = 126;
}
auto act = ton::create_tl_object<ton::ton_api::validatorSession_message_commit>(round, id, std::move(sig));
s = ton::validatorsession::ValidatorSessionState::action(desc, s, x, att, act.get());
CHECK(s);
}
if (s->check_need_generate_vote_for(desc, x, att)) {
auto act = s->generate_vote_for(desc, x, att);
s = ton::validatorsession::ValidatorSessionState::action(desc, s, x, att, act.get());
CHECK(s);
}
while (true) {
auto act = s->create_action(desc, x, att);
bool stop = false;
if (act->get_id() == ton::ton_api::validatorSession_message_empty::ID) {
stop = true;
}
s = ton::validatorsession::ValidatorSessionState::action(desc, s, x, att, act.get());
CHECK(s);
if (stop) {
break;
}
}
bool made = false;
s = ton::validatorsession::ValidatorSessionState::make_one(desc, s, x, att, made);
CHECK(!made);
s = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, s);
CHECK(s);
states[adj_x].push_back(s);
if (myrand() <= 1.0 / blocks_per_sec_per_node / total_nodes) {
ts += 1ull << 32;
}
desc.clear_temp_memory();
virt_state = ton::validatorsession::ValidatorSessionState::merge(desc, virt_state, s);
virt_state = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, virt_state);
}
td::BufferSlice buf{10240};
td::StringBuilder sb{buf.as_slice()};
virt_state->dump(desc, sb, desc.get_attempt_seqno(ts));
LOG(ERROR) << sb.as_cslice();
for (auto &x : states) {
if (x.size() == 0) {
std::cout << "<EMPTY>"
<< "\n";
} else {
auto s = *x.rbegin();
std::cout << "round=" << s->cur_round_seqno() << "\n";
}
}
for (td::uint32 i = 0; i < total_nodes; i++) {
for (td::uint32 j = 0; j < total_nodes; j++) {
td::uint32 x = td::Random::fast(0, static_cast<td::uint32>(states[i].size() - 1));
td::uint32 y = td::Random::fast(0, static_cast<td::uint32>(states[j].size() - 1));
auto s1 = states[i][x];
auto s2 = states[j][y];
auto m1 = ton::validatorsession::ValidatorSessionState::merge(desc, s1, s2);
auto m2 = ton::validatorsession::ValidatorSessionState::merge(desc, s2, s1);
CHECK(m1->get_hash(desc) == m2->get_hash(desc));
desc.clear_temp_memory();
}
}
auto x_state = ton::validatorsession::ValidatorSessionState::create(desc);
x_state = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, x_state);
for (td::uint32 i = 0; i < adj_total_nodes; i++) {
x_state = ton::validatorsession::ValidatorSessionState::merge(desc, x_state, *states[i].rbegin());
x_state = ton::validatorsession::ValidatorSessionState::move_to_persistent(desc, x_state);
}
CHECK(x_state->get_hash(desc) == virt_state->get_hash(desc));
delete descptr;
}
std::_Exit(0);
return 0;
}

View file

@ -0,0 +1,355 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "rldp/rldp.h"
#include "adnl/utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "dht/dht.h"
#include "overlay/overlays.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "td/utils/overloaded.h"
#include "catchain/catchain.h"
#include "validator-session/validator-session.h"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
class TestNode : public td::actor::Actor {
private:
td::actor::ActorOwn<ton::keyring::Keyring> keyring_;
td::actor::ActorOwn<ton::adnl::Adnl> adnl_;
td::actor::ActorOwn<ton::rldp::Rldp> rldp_;
std::vector<td::actor::ActorOwn<ton::dht::Dht>> dht_nodes_;
td::actor::ActorOwn<ton::overlay::Overlays> overlay_manager_;
std::vector<td::actor::ActorOwn<ton::validatorsession::ValidatorSession>> validator_sessions_;
std::string local_config_ = "ton-local.config";
std::string global_config_ = "ton-global.config";
std::unique_ptr<ton::validatorsession::ValidatorSession::Callback> make_vs_callback() {
class Callback : public ton::validatorsession::ValidatorSession::Callback {
public:
void on_candidate(td::uint32 round, ton::PublicKeyHash source,
ton::validatorsession::ValidatorSessionRootHash root_hash, td::BufferSlice data,
td::BufferSlice extra,
td::Promise<ton::validatorsession::ValidatorSession::CandidateDecision> promise) override {
td::actor::send_closure(id_, &TestNode::on_candidate, round, source, root_hash, std::move(data),
std::move(extra), std::move(promise));
}
void on_generate_slot(td::uint32 round, td::Promise<ton::BlockCandidate> promise) override {
td::actor::send_closure(id_, &TestNode::on_generate_slot, round, std::move(promise));
}
void on_block_committed(td::uint32 round, ton::PublicKeyHash src,
ton::validatorsession::ValidatorSessionRootHash root_hash,
ton::validatorsession::ValidatorSessionFileHash file_hash, td::BufferSlice data,
std::vector<std::pair<ton::PublicKeyHash, td::BufferSlice>> signatures) override {
td::actor::send_closure(id_, &TestNode::on_block_committed, round, root_hash, std::move(data),
std::move(signatures));
}
/*void on_missing_block_committed(
td::uint32 round, ton::validatorsession::ValidatorSessionRootHash root_hash, ton::validatorsession::ValidatorSessionFileHash file_hash,
td::BufferSlice data, std::vector<std::pair<ton::adnl::AdnlNodeIdShort, td::BufferSlice>> signatures) override {
td::actor::send_closure(id_, &TestNode::on_block_committed_abscent, round, root_hash, file_hash,
std::move(data), std::move(signatures));
}*/
void on_block_skipped(td::uint32 round) override {
td::actor::send_closure(id_, &TestNode::on_block_skipped, round);
}
void get_approved_candidate(ton::validatorsession::ValidatorSessionRootHash root_hash,
ton::validatorsession::ValidatorSessionFileHash file_hash,
ton::validatorsession::ValidatorSessionFileHash collated_data_file_hash,
td::Promise<ton::BlockCandidate> promise) override {
UNREACHABLE();
}
Callback(td::actor::ActorId<TestNode> id) : id_(std::move(id)) {
}
private:
td::actor::ActorId<TestNode> id_;
};
return std::make_unique<Callback>(actor_id(this));
}
td::uint64 height_ = 0;
public:
void on_candidate(td::uint32 round, ton::PublicKeyHash source,
ton::validatorsession::ValidatorSessionRootHash root_hash, td::BufferSlice data,
td::BufferSlice collated,
td::Promise<ton::validatorsession::ValidatorSession::CandidateDecision> promise) {
auto sh = sha256_bits256(data.as_slice());
auto B = ton::fetch_tl_object<ton::ton_api::test_validatorSession_block>(std::move(data), true);
if (B.is_error()) {
promise.set_result(
ton::validatorsession::ValidatorSession::CandidateDecision{B.move_as_error().to_string(), td::BufferSlice()});
return;
}
if (collated.size() != 32) {
promise.set_result(
ton::validatorsession::ValidatorSession::CandidateDecision{"bad collated data length", td::BufferSlice()});
return;
}
td::Bits256 x;
x.as_slice().copy_from(collated.as_slice().truncate(32));
if (x != sh) {
promise.set_result(
ton::validatorsession::ValidatorSession::CandidateDecision{"bad block hash", td::BufferSlice()});
return;
}
auto block = B.move_as_ok();
if (block->root_hash_ != root_hash) {
promise.set_result(
ton::validatorsession::ValidatorSession::CandidateDecision{"bad root hash", td::BufferSlice()});
return;
}
if (block->root_hash_ != sha256_bits256(block->data_.as_slice())) {
promise.set_result(
ton::validatorsession::ValidatorSession::CandidateDecision{"bad root hash (2)", td::BufferSlice()});
return;
}
if (block->height_ != static_cast<td::int64>(height_) + 1) {
promise.set_result(
ton::validatorsession::ValidatorSession::CandidateDecision{"bad root height", td::BufferSlice()});
return;
}
promise.set_result(ton::validatorsession::ValidatorSession::CandidateDecision{0});
}
void on_generate_slot(td::uint32 round, td::Promise<ton::BlockCandidate> promise) {
auto data = td::BufferSlice{10000};
td::Random::secure_bytes(data.as_slice());
auto root_hash = sha256_bits256(data.as_slice());
auto block =
ton::create_tl_object<ton::ton_api::test_validatorSession_block>(root_hash, height_ + 1, std::move(data));
auto B = ton::serialize_tl_object(block, true);
auto hash = sha256_bits256(B.as_slice());
auto collated = td::BufferSlice{32};
collated.as_slice().copy_from(as_slice(hash));
/*BlockId id;
BlockStatus status;
RootHash root_hash;
FileHash file_hash;
FileHash collated_file_hash;
td::BufferSlice data;
td::BufferSlice collated_data;*/
auto collated_file_hash = td::sha256_bits256(collated.as_slice());
ton::BlockCandidate candidate{ton::BlockIdExt{ton::BlockId{0, 0, 0}, root_hash, td::sha256_bits256(B.as_slice())},
collated_file_hash, std::move(B), std::move(collated)};
promise.set_result(std::move(candidate));
}
void on_block_committed(td::uint32 round, ton::validatorsession::ValidatorSessionRootHash root_hash,
td::BufferSlice data,
std::vector<std::pair<ton::PublicKeyHash, td::BufferSlice>> signatures) {
LOG(ERROR) << "COMITTED BLOCK: ROUND=" << round << " ROOT_HASH=" << root_hash
<< " DATA_HASH=" << sha256_bits256(data.as_slice()) << " SIGNED BY " << signatures.size();
}
void on_block_skipped(td::uint32 round) {
LOG(ERROR) << "SKIPPED ROUND=" << round;
}
void set_local_config(std::string str) {
local_config_ = str;
}
void set_global_config(std::string str) {
global_config_ = str;
}
void start_up() override {
}
void alarm() override {
}
TestNode() {
}
void run() {
keyring_ = ton::keyring::Keyring::create("/var/ton-work/db.keyring");
adnl_ = ton::adnl::Adnl::create("/var/ton-work/db.adnl", keyring_.get());
rldp_ = ton::rldp::Rldp::create(adnl_.get());
auto L = td::read_file(local_config_).move_as_ok();
auto lc_j = td::json_decode(L.as_slice()).move_as_ok();
ton::ton_api::config_local lc;
ton::ton_api::from_json(lc, lc_j.get_object()).ensure();
auto G = td::read_file(global_config_).move_as_ok();
auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
ton::ton_api::config_global gc;
ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
for (auto &port : lc.udp_ports_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_listening_udp_port, "0.0.0.0",
static_cast<td::uint16>(port));
}
/*if (!lc.net_) {
LOG(FATAL) << "local config does not contain NET section";
}*/
//td::actor::send_closure(network_manager_, &ton::adnl::AdnlNetworkManager::load_local_config, std::move(lc.net_));
//td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_ids_from_config, std::move(lc.local_ids_));
if (gc.adnl_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_static_nodes_from_config,
std::move(gc.adnl_->static_nodes_));
}
if (!gc.dht_) {
LOG(FATAL) << "global config does not contain dht section";
}
auto dhtR = ton::dht::Dht::create_global_config(std::move(gc.dht_));
if (dhtR.is_error()) {
LOG(FATAL) << "bad dht config: " << dhtR.move_as_error();
}
auto dht = dhtR.move_as_ok();
for (auto &it : lc.dht_) {
std::vector<ton::adnl::AdnlNodeIdShort> adnl_ids;
ton::ton_api::downcast_call(
*it.get(), td::overloaded(
[&](ton::ton_api::dht_config_local &obj) {
adnl_ids.push_back(ton::adnl::AdnlNodeIdShort{obj.id_->id_});
},
[&](ton::ton_api::dht_config_random_local &obj) {
auto addrR = ton::adnl::AdnlAddressList::create(std::move(obj.addr_list_));
addrR.ensure();
auto addr = addrR.move_as_ok();
for (td::int32 i = 0; i < obj.cnt_; i++) {
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub = pk.compute_public_key();
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub},
addr);
auto adnl_id = ton::adnl::AdnlNodeIdShort{pub.compute_short_id()};
adnl_ids.push_back(adnl_id);
}
}));
for (auto &id : adnl_ids) {
auto R = ton::dht::Dht::create(id, "/var/ton-work/db/", dht, keyring_.get(), adnl_.get());
R.ensure();
dht_nodes_.push_back(R.move_as_ok());
}
}
CHECK(dht_nodes_.size() > 0);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_dht_node, dht_nodes_[0].get());
//td::actor::send_closure(overlay_manager_, &ton::overlay::Overlays::register_dht_node, dht_nodes_[0].get());
overlay_manager_ =
ton::overlay::Overlays::create("/var/ton-work/db.overlays", keyring_.get(), adnl_.get(), dht_nodes_[0].get());
//auto C = ton::CatChainActor::create(nullptr, adnl_.get(), overlay_manager_.get(),
// std::vector<ton::tl_object_ptr<ton::ton_api::adnl_id_Full>>());
for (auto &it : lc.catchains_) {
auto tag = it->tag_;
for (auto &V : gc.catchains_) {
if (V->tag_ == tag) {
auto v = std::move(clone_tl_object(V)->nodes_);
std::vector<ton::validatorsession::ValidatorSessionNode> w;
w.resize(v.size());
for (size_t i = 0; i < w.size(); i++) {
w[i].pub_key = ton::PublicKey{v[i]};
w[i].adnl_id = ton::adnl::AdnlNodeIdShort{w[i].pub_key.compute_short_id()};
w[i].weight = 1;
}
auto C = ton::validatorsession::ValidatorSession::create(
tag, ton::PublicKeyHash{it->id_->id_}, std::move(w), make_vs_callback(), keyring_.get(), adnl_.get(),
rldp_.get(), overlay_manager_.get(), "/var/ton-work/db/");
td::actor::send_closure(C, &ton::validatorsession::ValidatorSession::start);
validator_sessions_.emplace_back(std::move(C));
}
}
}
}
};
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<TestNode> x;
td::OptionsParser p;
p.set_description("test basic adnl functionality");
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_global_config, fname.str());
return td::Status::OK();
});
p.add_option('c', "local-config", "file to read local config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_local_config, fname.str());
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
auto FileLog = td::FileFd::open(td::CSlice(fname.str().c_str()),
td::FileFd::Flags::Create | td::FileFd::Flags::Append | td::FileFd::Flags::Write)
.move_as_ok();
dup2(FileLog.get_native_fd().fd(), 1);
dup2(FileLog.get_native_fd().fd(), 2);
return td::Status::OK();
});
#endif
td::actor::Scheduler scheduler({7});
scheduler.run_in_context([&] { x = td::actor::create_actor<TestNode>("testnode"); });
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
scheduler.run_in_context([&] { td::actor::send_closure(x, &TestNode::run); });
scheduler.run();
return 0;
}

356
test/test-validator.cpp Normal file
View file

@ -0,0 +1,356 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "adnl/adnl.h"
#include "rldp/rldp.h"
#include "adnl/utils.hpp"
#include "auto/tl/ton_api_json.h"
#include "auto/tl/ton_api.hpp"
#include "dht/dht.h"
#include "overlay/overlays.h"
#include "td/utils/OptionsParser.h"
#include "td/utils/Time.h"
#include "td/utils/TsFileLog.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "catchain/catchain.h"
#include "validator-session/validator-session.h"
#include "ton-node/ton-node.h"
#include "validator/manager.h"
#include "td/utils/filesystem.h"
#include "td/utils/ThreadSafeCounter.h"
#include "td/utils/port/path.h"
#include "crypto/vm/cp0.h"
#include "td/utils/overloaded.h"
#include "memprof/memprof.h"
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <algorithm>
#include <iostream>
#include <sstream>
class TestNode : public td::actor::Actor {
private:
td::actor::ActorOwn<ton::keyring::Keyring> keyring_;
td::actor::ActorOwn<ton::adnl::Adnl> adnl_;
td::actor::ActorOwn<ton::rldp::Rldp> rldp_;
std::vector<td::actor::ActorOwn<ton::dht::Dht>> dht_nodes_;
td::actor::ActorOwn<ton::overlay::Overlays> overlay_manager_;
td::actor::ActorOwn<ton::ValidatorManager> validator_manager_;
td::actor::ActorOwn<ton::TonNodeManager> ton_node_;
std::string local_config_ = "ton-local.config";
std::string global_config_ = "ton-global.config";
std::string db_root_ = "/var/ton-work/db/";
std::string zero_state_ = "";
public:
void set_local_config(std::string str) {
local_config_ = str;
}
void set_global_config(std::string str) {
global_config_ = str;
}
void set_db_root(std::string db_root) {
db_root_ = db_root;
}
void set_zero_state(std::string zero_state) {
zero_state_ = zero_state;
}
void start_up() override {
}
void alarm() override {
}
TestNode() {
}
void run() {
td::mkdir(db_root_).ensure();
keyring_ = ton::keyring::Keyring::create(db_root_ + "/keyring");
adnl_ = ton::adnl::Adnl::create(db_root_, keyring_.get());
rldp_ = ton::rldp::Rldp::create(adnl_.get());
auto L = td::read_file(local_config_).move_as_ok();
auto lc_j = td::json_decode(L.as_slice()).move_as_ok();
ton::ton_api::config_local lc;
ton::ton_api::from_json(lc, lc_j.get_object()).ensure();
auto G = td::read_file(global_config_).move_as_ok();
auto gc_j = td::json_decode(G.as_slice()).move_as_ok();
ton::ton_api::config_global gc;
ton::ton_api::from_json(gc, gc_j.get_object()).ensure();
for (auto &port : lc.udp_ports_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_listening_udp_port, "0.0.0.0",
static_cast<td::uint16>(port));
}
/*if (!lc.net_) {
LOG(FATAL) << "local config does not contain NET section";
}*/
//td::actor::send_closure(network_manager_, &ton::adnl::AdnlNetworkManager::load_local_config, std::move(lc.net_));
//td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_ids_from_config, std::move(lc.local_ids_));
for (auto &local_id : lc.local_ids_) {
auto pk = ton::PrivateKey{local_id->id_};
auto pub = pk.compute_public_key();
auto addr_list = ton::adnl::AdnlAddressList::create(local_id->addr_list_);
addr_list.ensure();
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, addr_list.move_as_ok());
}
if (gc.adnl_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_static_nodes_from_config,
std::move(gc.adnl_->static_nodes_));
}
if (!gc.dht_) {
LOG(FATAL) << "global config does not contain dht section";
}
auto dhtR = ton::dht::Dht::create_global_config(std::move(gc.dht_));
if (dhtR.is_error()) {
LOG(FATAL) << "bad dht config: " << dhtR.move_as_error();
}
auto dht = dhtR.move_as_ok();
for (auto &it : lc.dht_) {
std::vector<ton::adnl::AdnlNodeIdShort> adnl_ids;
ton::ton_api::downcast_call(
*it.get(), td::overloaded(
[&](ton::ton_api::dht_config_local &obj) {
adnl_ids.push_back(ton::adnl::AdnlNodeIdShort{obj.id_->id_});
},
[&](ton::ton_api::dht_config_random_local &obj) {
auto addrR = ton::adnl::AdnlAddressList::create(std::move(obj.addr_list_));
addrR.ensure();
auto addr = addrR.move_as_ok();
for (td::int32 i = 0; i < obj.cnt_; i++) {
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub = pk.compute_public_key();
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub},
addr);
auto adnl_id = ton::adnl::AdnlNodeIdShort{pub.compute_short_id()};
adnl_ids.push_back(adnl_id);
}
}));
for (auto &id : adnl_ids) {
auto R = ton::dht::Dht::create(id, db_root_, dht, keyring_.get(), adnl_.get());
R.ensure();
dht_nodes_.push_back(R.move_as_ok());
}
}
CHECK(dht_nodes_.size() > 0);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_dht_node, dht_nodes_[0].get());
overlay_manager_ = ton::overlay::Overlays::create(db_root_, keyring_.get(), adnl_.get(), dht_nodes_[0].get());
CHECK(lc.validators_.size() <= 1);
CHECK(gc.validators_.size() <= 1);
bool is_validator = false;
if (lc.validators_.size() == 1) {
CHECK(gc.validators_.size() == 1);
auto zero_state_id =
ton::BlockIdExt{ton::masterchainId, ton::shardIdAll, 0, gc.validators_[0]->zero_state_root_hash_,
gc.validators_[0]->zero_state_file_hash_};
ton::PublicKeyHash id;
ton::adnl::AdnlNodeIdShort adnl_id;
ton::ton_api::downcast_call(*lc.validators_[0].get(),
td::overloaded(
[&](ton::ton_api::validator_config_local &cfg) {
id = ton::PublicKeyHash{cfg.id_->id_};
adnl_id = ton::adnl::AdnlNodeIdShort{id};
is_validator = true;
},
[&](ton::ton_api::validator_config_random_local &cfg) {
auto privkey = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pubkey = ton::adnl::AdnlNodeIdFull{privkey.compute_public_key()};
auto addrR = ton::adnl::AdnlAddressList::create(std::move(cfg.addr_list_));
addrR.ensure();
auto addr = addrR.move_as_ok();
id = privkey.compute_short_id();
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key,
std::move(privkey), false);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, pubkey, addr);
adnl_id = ton::adnl::AdnlNodeIdShort{id};
}));
auto opts = ton::ValidatorManagerOptions::create(
zero_state_id, std::vector<ton::ShardIdFull>{ton::ShardIdFull{ton::basechainId, ton::shardIdAll}});
CHECK(!opts.is_null());
opts.write().set_allow_blockchain_init(is_validator);
validator_manager_ =
ton::ValidatorManagerFactory::create(is_validator ? id : ton::PublicKeyHash::zero(), opts, db_root_,
keyring_.get(), adnl_.get(), rldp_.get(), overlay_manager_.get());
ton_node_ =
ton::TonNodeManager::create(adnl_id, gc.validators_[0]->zero_state_file_hash_, adnl_.get(), rldp_.get(),
dht_nodes_[0].get(), overlay_manager_.get(), validator_manager_.get(), db_root_);
for (auto &x : lc.liteservers_) {
auto pk = ton::PrivateKey{x->id_};
auto pub_k = ton::adnl::AdnlNodeIdFull{pk.compute_public_key()};
auto id = pub_k.compute_short_id();
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), false);
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, pub_k, ton::adnl::AdnlAddressList{});
td::actor::send_closure(validator_manager_, &ton::ValidatorManager::add_ext_server_id, id);
td::actor::send_closure(validator_manager_, &ton::ValidatorManager::add_ext_server_port,
static_cast<td::uint16>(x->port_));
}
}
}
};
td::Result<td::UInt256> get_uint256(std::string str) {
if (str.size() != 64) {
return td::Status::Error("uint256 must have 64 bytes");
}
td::UInt256 res;
for (size_t i = 0; i < 32; i++) {
res.raw[i] = static_cast<td::uint8>(td::hex_to_int(str[2 * i]) * 16 + td::hex_to_int(str[2 * i + 1]));
}
return res;
}
std::atomic<bool> need_stats_flag{false};
void need_stats(int sig) {
need_stats_flag.store(true);
}
void dump_memory_stats() {
if (!is_memprof_on()) {
return;
}
LOG(WARNING) << "memory_dump";
std::vector<AllocInfo> v;
dump_alloc([&](const AllocInfo &info) { v.push_back(info); });
std::sort(v.begin(), v.end(), [](const AllocInfo &a, const AllocInfo &b) { return a.size > b.size; });
size_t total_size = 0;
size_t other_size = 0;
int cnt = 0;
for (auto &info : v) {
if (cnt++ < 50) {
LOG(WARNING) << td::format::as_size(info.size) << td::format::as_array(info.backtrace);
} else {
other_size += info.size;
}
total_size += info.size;
}
LOG(WARNING) << td::tag("other", td::format::as_size(other_size));
LOG(WARNING) << td::tag("total", td::format::as_size(total_size));
LOG(WARNING) << td::tag("total traces", get_ht_size());
LOG(WARNING) << td::tag("fast_backtrace_success_rate", get_fast_backtrace_success_rate());
}
void dump_stats() {
dump_memory_stats();
LOG(WARNING) << td::NamedThreadSafeCounter::get_default();
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_default_failure_signal_handler().ensure();
CHECK(vm::init_op_cp0());
td::actor::ActorOwn<TestNode> x;
td::unique_ptr<td::LogInterface> logger_;
SCOPE_EXIT {
td::log_interface = td::default_log_interface;
};
td::OptionsParser p;
p.set_description("test basic adnl functionality");
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
int v = VERBOSITY_NAME(FATAL) + (td::to_integer<int>(arg));
SET_VERBOSITY_LEVEL(v);
return td::Status::OK();
});
p.add_option('h', "help", "prints_help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
std::cout << sb.as_cslice().c_str();
std::exit(2);
return td::Status::OK();
});
p.add_option('C', "global-config", "file to read global config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_global_config, fname.str());
return td::Status::OK();
});
p.add_option('c', "local-config", "file to read local config", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_local_config, fname.str());
return td::Status::OK();
});
p.add_option('i', "id", "id of instance", [&](td::Slice fname) { return td::Status::OK(); });
p.add_option('D', "db", "root for dbs", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_db_root, fname.str());
return td::Status::OK();
});
p.add_option('z', "zero-state", "file with serialized zero state", [&](td::Slice fname) {
td::actor::send_closure(x, &TestNode::set_zero_state, fname.str());
return td::Status::OK();
});
p.add_option('d', "daemonize", "set SIGHUP", [&]() {
td::set_signal_handler(td::SignalType::HangUp, [](int sig) {
#if TD_DARWIN || TD_LINUX
close(0);
setsid();
#endif
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
logger_ = td::TsFileLog::create(fname.str()).move_as_ok();
td::log_interface = logger_.get();
return td::Status::OK();
});
#endif
td::set_runtime_signal_handler(1, need_stats).ensure();
td::actor::Scheduler scheduler({7});
scheduler.run_in_context([&] { x = td::actor::create_actor<TestNode>("testnode"); });
scheduler.run_in_context([&] { p.run(argc, argv).ensure(); });
scheduler.run_in_context([&] { td::actor::send_closure(x, &TestNode::run); });
while (scheduler.run(1)) {
if (need_stats_flag.exchange(false)) {
dump_stats();
}
}
return 0;
}