mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
2053
test/ed25519_crypto.cpp
Normal file
2053
test/ed25519_crypto.cpp
Normal file
File diff suppressed because it is too large
Load diff
207
test/generate-test-node-config.py
Normal file
207
test/generate-test-node-config.py
Normal 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
54
test/regression-tests.ans
Normal 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
322
test/test-adnl.cpp
Normal 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
318
test/test-catchain.cpp
Normal 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
407
test/test-dht.cpp
Normal 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;
|
||||
}
|
236
test/test-dummy-0-lite-client.cpp
Normal file
236
test/test-dummy-0-lite-client.cpp
Normal 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
220
test/test-ext-client.cpp
Normal 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
221
test/test-ext-server.cpp
Normal 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
138
test/test-hello-world.cpp
Normal 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
376
test/test-node.cpp
Normal 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
202
test/test-rldp.cpp
Normal 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
55
test/test-td-main.cpp
Normal 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
446
test/test-ton-collator.cpp
Normal 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;
|
||||
}
|
236
test/test-ton-dummy-0-disk.cpp
Normal file
236
test/test-ton-dummy-0-disk.cpp
Normal 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
277
test/test-ton-dummy-0.cpp
Normal 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;
|
||||
}
|
996
test/test-validator-session-state.cpp
Normal file
996
test/test-validator-session-state.cpp
Normal 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;
|
||||
}
|
355
test/test-validator-session.cpp
Normal file
355
test/test-validator-session.cpp
Normal 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
356
test/test-validator.cpp
Normal 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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue