From f40822b58a06f8fc9d88a5350b22f43b204ddfc8 Mon Sep 17 00:00:00 2001 From: ton Date: Thu, 19 Sep 2019 23:15:32 +0400 Subject: [PATCH] fullnode: support for TCP master/slave replication --- CMakeLists.txt | 22 +- adnl/CMakeLists.txt | 4 + crypto/openssl/bignum.cpp | 3 +- crypto/openssl/bignum.h | 2 +- crypto/smartcont/gen-zerostate.fif | 3 +- crypto/smartcont/new-testgiver.fif | 50 +++ crypto/smartcont/testgiver.fif | 2 +- crypto/test/test-cells.cpp | 2 +- dht-server/dht-server.cpp | 6 +- doc/FullNode-HOWTO | 2 +- doc/LiteClient-HOWTO | 67 ++-- .../java/drinkless/org/ton/TonTest.kt | 18 +- .../java/drinkless/org/ton/TonTestJava.java | 39 +- tdutils/CMakeLists.txt | 14 +- tdutils/generate/CMakeLists.txt | 4 + tdutils/td/utils/tl_parsers.h | 5 +- tl/generate/scheme/ton_api.tl | 9 +- tl/generate/scheme/ton_api.tlo | Bin 50984 -> 51664 bytes ton/ton-types.h | 10 + tonlib/CMakeLists.txt | 5 +- tonlib/tonlib/ExtClient.h | 3 +- tonlib/tonlib/TestGiver.cpp | 4 +- tonlib/tonlib/keys/DecryptedKey.h | 2 +- validator-engine/validator-engine.cpp | 102 ++++- validator-engine/validator-engine.hpp | 14 +- validator/CMakeLists.txt | 3 + validator/full-node-master.cpp | 357 ++++++++++++++++++ validator/full-node-master.h | 45 +++ validator/full-node-master.hpp | 83 ++++ validator/full-node-shard.cpp | 71 +++- validator/full-node-shard.h | 13 +- validator/full-node-shard.hpp | 6 +- validator/full-node.cpp | 10 +- validator/full-node.h | 3 +- validator/full-node.hpp | 4 +- validator/impl/collator.cpp | 66 ++-- validator/impl/validate-query.cpp | 7 +- validator/manager-init.cpp | 19 +- validator/manager-init.hpp | 2 +- validator/net/download-block.cpp | 108 ++++-- validator/net/download-block.hpp | 6 +- validator/net/download-next-block.cpp | 20 +- validator/net/download-next-block.hpp | 5 +- validator/net/download-proof.cpp | 52 ++- validator/net/download-proof.hpp | 5 +- validator/net/download-state.cpp | 40 +- validator/net/download-state.hpp | 5 +- validator/net/get-next-key-blocks.cpp | 23 +- validator/net/get-next-key-blocks.hpp | 5 +- validator/validator.h | 3 + 50 files changed, 1109 insertions(+), 244 deletions(-) create mode 100644 crypto/smartcont/new-testgiver.fif create mode 100644 validator/full-node-master.cpp create mode 100644 validator/full-node-master.h create mode 100644 validator/full-node-master.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dbdaa8..eb51cf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,8 +70,14 @@ else() endif() #BEGIN internal -option(TON_USE_ROCKSDB "Use \"ON\" to enable RocksDb." ON) -option(TON_USE_ABSEIL "Use \"ON\" to enable Abseil." ON) +option(TON_ONLY_TONLIB "Use \"ON\" to build only tonlib." OFF) +if (TON_ONLY_TONBLIB) + set(NOT_TON_ONLY_TONLIB false) +else() + set(NOT_TON_ONLY_TONLIB true) +endif() +option(TON_USE_ROCKSDB "Use \"ON\" to enable RocksDb." ${NOT_TON_ONLY_TONLIB}) +option(TON_USE_ABSEIL "Use \"ON\" to enable Abseil." ${NOT_TON_ONLY_TONLIB}) option(TON_USE_JEMALLOC "Use \"ON\" to enable JeMalloc." OFF) #END internal @@ -328,6 +334,7 @@ function(target_link_libraries_system target) endforeach(lib) endfunction(target_link_libraries_system) +set(TDUTILS_MIME_TYPE OFF CACHE BOOL "Generate mime type conversion") add_subdirectory(tdutils) add_subdirectory(memprof) add_subdirectory(tdactor) @@ -350,6 +357,7 @@ add_subdirectory(tonlib) #END tonlib #BEGIN internal +if (NOT TON_ONLY_TONLIB) add_subdirectory(common) add_subdirectory(tdfec) add_subdirectory(keyring) @@ -365,10 +373,14 @@ add_subdirectory(validator-engine) add_subdirectory(validator-engine-console) add_subdirectory(dht-server) add_subdirectory(utils) +endif() #END internal if (NOT CMAKE_CROSSCOMPILING) - add_custom_target(prepare_cross_compiling DEPENDS tl_generate_common tdmime_auto tlb_generate_block) + if (TDUTILS_MIME_TYPE) + set(TDMIME_AUTO tdmime_auto) + endif() + add_custom_target(prepare_cross_compiling DEPENDS tl_generate_common tlb_generate_block ${TDMIME_AUTO}) endif() #TESTS @@ -406,6 +418,7 @@ target_link_libraries(test-tonlib-offline tdutils tdactor adnllite tl_api ton_cr #END tonlib #BEGIN internal +if (NOT TON_ONLY_TONLIB) add_executable(test-db test/test-td-main.cpp ${TONDB_TEST_SOURCE}) target_link_libraries(test-db PRIVATE ton_db memprof) @@ -467,6 +480,7 @@ if (HAS_PARENT) endif() add_library(all_tests INTERFACE) target_link_libraries(all_tests INTERFACE tdutils tdactor tdnet tdfec ton_db ton_crypto fift-lib) +endif() #END internal enable_testing() @@ -485,8 +499,10 @@ add_test(test-tonlib-offline test-tonlib-offline) #END tonlib #BEGIN internal +if (NOT TON_ONLY_TONLIB) add_test(test-fec test-fec) add_test(test-tddb test-tddb ${TEST_OPTIONS}) add_test(test-db test-db ${TEST_OPTIONS}) +endif() #END internal diff --git a/adnl/CMakeLists.txt b/adnl/CMakeLists.txt index b7c2c19..04c7304 100644 --- a/adnl/CMakeLists.txt +++ b/adnl/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) #BEGIN internal +if (NOT TON_ONLY_TONLIB) set(ADNL_HEADERS adnl-address-list.h adnl-address-list.hpp @@ -66,6 +67,7 @@ set(ADNL_PROXY_SOURCE #FIXME set(ADNL_LITE_HEADERS ${ADNL_HEADERS}) +endif() #END internal set(ADNL_LITE_SOURCE @@ -77,6 +79,7 @@ set(ADNL_LITE_SOURCE ) #BEGIN internal +if (NOT TON_ONLY_TONLIB) add_library(adnl STATIC ${ADNL_SOURCE}) target_include_directories(adnl PUBLIC $) @@ -95,6 +98,7 @@ target_link_libraries(adnl-pong PUBLIC tdactor ton_crypto tl_api tdnet common add_library(adnltest STATIC ${ADNL_TEST_SOURCE}) target_include_directories(adnltest PUBLIC $) target_link_libraries(adnltest PUBLIC adnl ) +endif() #END internal add_library(adnllite STATIC ${ADNL_LITE_SOURCE}) diff --git a/crypto/openssl/bignum.cpp b/crypto/openssl/bignum.cpp index a696cb5..275b01b 100644 --- a/crypto/openssl/bignum.cpp +++ b/crypto/openssl/bignum.cpp @@ -209,7 +209,8 @@ Bignum& Bignum::import_lsb(const unsigned char* buffer, std::size_t size) { size--; } if (!size) { - bn_assert(BN_zero(val)); + // Use BN_set_word, because from 1.1.0 BN_zero may return void + bn_assert(BN_set_word(val, 0)); return *this; } unsigned char tmp_buff[1024]; diff --git a/crypto/openssl/bignum.h b/crypto/openssl/bignum.h index e9ebd4f..40d7d58 100644 --- a/crypto/openssl/bignum.h +++ b/crypto/openssl/bignum.h @@ -79,7 +79,7 @@ class Bignum { } Bignum(const bin_string& bs) { val = BN_new(); - set_dec_str(bs.str); + set_raw_bytes(bs.str); } Bignum(const dec_string& ds) { val = BN_new(); diff --git a/crypto/smartcont/gen-zerostate.fif b/crypto/smartcont/gen-zerostate.fif index 16db629..f5f9aac 100644 --- a/crypto/smartcont/gen-zerostate.fif +++ b/crypto/smartcont/gen-zerostate.fif @@ -66,9 +66,10 @@ Masterchain over // SmartContract #2 (Simple money giver for test network) <{ SETCP0 DUP IFNOTRET // return if recv_internal - DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method + DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method DROP c4 PUSHCTR CTOS 32 PLDU // cnt }> + INC 32 THROWIF // fail unless recv_external 32 LDU SWAP // cs cnt c4 PUSHCTR CTOS 32 LDU ENDS // cs cnt cnt' TUCK EQUAL 33 THROWIFNOT // ( seqno mismatch? ) diff --git a/crypto/smartcont/new-testgiver.fif b/crypto/smartcont/new-testgiver.fif new file mode 100644 index 0000000..9a901a0 --- /dev/null +++ b/crypto/smartcont/new-testgiver.fif @@ -0,0 +1,50 @@ +#!/usr/bin/env fift -s +"TonUtil.fif" include +"Asm.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates a new money giver in specified workchain, with address saved to .addr" cr + ."('new-testgiver.addr' by default)" cr 1 halt +} : usage +$# 1- -2 and ' usage if + +$1 parse-workchain-id =: wc // set workchain id from command line argument +def? $2 { @' $2 } { "new-testgiver" } cond constant file-base + +."Creating new money giver in workchain " wc . cr +0 constant init_seqno + +// Create new simple money giver +<{ SETCP0 DUP IFNOTRET // return if recv_internal + DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method + DROP c4 PUSHCTR CTOS 32 PLDU // cnt + }> + INC 32 THROWIF // fail unless recv_external + 32 LDU SWAP // cs cnt + c4 PUSHCTR CTOS 32 LDU ENDS // cs cnt cnt' + TUCK EQUAL 33 THROWIFNOT // ( seqno mismatch? ) + ACCEPT // cs cnt' + SWAP DUP SREFS // cnt' cs msg? + IF:<{ + 8 LDU LDREF -ROT // cnt'' cs mode msg + GR$20 INT 3 INT RAWRESERVE // reserve all but 20 Grams from the balance + SWAP SENDRAWMSG + }> + ENDS INC NEWC 32 STU ENDC c4 POPCTR // store cnt'' +}>c +// code + // data +null // no libraries + // create StateInit +dup ."StateInit: " +dup ."External message for initialization is " B dup Bx. cr +file-base +"-query.boc" tuck B>file +."(Saved money giver creating query to file " type .")" cr diff --git a/crypto/smartcont/testgiver.fif b/crypto/smartcont/testgiver.fif index 1b90fdb..bd9f886 100644 --- a/crypto/smartcont/testgiver.fif +++ b/crypto/smartcont/testgiver.fif @@ -9,7 +9,7 @@ $# 3 - -2 and ' usage if // "testgiver.addr" load-address -Masterchain 0x8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d +Masterchain 0xfcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260 2constant giver_addr ."Test giver address = " giver_addr 2dup .addr cr 6 .Addr cr diff --git a/crypto/test/test-cells.cpp b/crypto/test/test-cells.cpp index 17d5415..bda9caa 100644 --- a/crypto/test/test-cells.cpp +++ b/crypto/test/test-cells.cpp @@ -572,7 +572,7 @@ TEST(bits256_scan, main) { } bool check_exp(std::ostream& stream, const td::NegExpBinTable& tab, double x) { - long long xx = lround(x * (1LL << 52)); + long long xx = llround(x * (1LL << 52)); td::BigInt256 yy; if (!tab.nexpf(yy, -xx, 52)) { stream << "cannot compute exp(" << x << ") = exp(" << xx << " * 2^(-52))" << std::endl; diff --git a/dht-server/dht-server.cpp b/dht-server/dht-server.cpp index 26905b5..a96434b 100644 --- a/dht-server/dht-server.cpp +++ b/dht-server/dht-server.cpp @@ -139,6 +139,9 @@ ton::tl_object_ptr Config::tl() const { std::vector> val_vec; + ton::tl_object_ptr full_node_slave_ = nullptr; + std::vector> full_node_masters_; + std::vector> liteserver_vec; std::vector> control_vec; @@ -157,7 +160,8 @@ ton::tl_object_ptr Config::tl() const { } return ton::create_tl_object( out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec), - ton::PublicKeyHash::zero().tl(), std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec)); + ton::PublicKeyHash::zero().tl(), std::move(full_node_slave_), std::move(full_node_masters_), + std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec)); } td::Result Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip, diff --git a/doc/FullNode-HOWTO b/doc/FullNode-HOWTO index 09f5021..843c680 100644 --- a/doc/FullNode-HOWTO +++ b/doc/FullNode-HOWTO @@ -5,7 +5,7 @@ Notice that you need a machine with a public IP address and a high-bandwidth net 0. Downloading and compiling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The complete TON Blockchain Library and Validator software is downloaded and compiled similarly to the Lite Client. This process is outlined in the corresponding README file. The most important difference is that you have to download the complete source archive available at https://test.ton.org/ton-blockchain-full.tar.xz instead of the smaller Lite Client source archive. You should also build all goals defined in CMakeLists.txt (e.g. by running `cmake ` and `make` in your build directory), not only those specifically related to the Lite Client (which is also included in the larger distribution; you don't have to download and build it separately). We strongly recommend building a "release" or a "release with debug information" version of the TON Blockchain Library and especially of the Validator/Full Node by passing `-DCMAKE_BUILD_TYPE=Release` or `-DCMAKE_BUILD_TYPE=RelWithDebInfo` as an extra argument to `cmake` during its first run (if you forgot to do this, you can later delete file `CMakeCache.txt` from your build directory and re-run `cmake` with the appropriate options). +The complete TON Blockchain Library and Validator software is downloaded and compiled similarly to the Lite Client. This process is outlined in the corresponding README file. The most important difference is that you have to download the complete sources from public GitHub repository https://github.com/ton-blockchain/ton (e.g., by running `git clone https://github.com/ton-blockchain/ton`) instead of downloading the smaller Lite Client source archive. You should also build all goals defined in CMakeLists.txt (e.g. by running `cmake ` and `make` in your build directory), not only those specifically related to the Lite Client (which is also included in the larger distribution; you don't have to download and build it separately). We strongly recommend building a "release" or a "release with debug information" version of the TON Blockchain Library and especially of the Validator/Full Node by passing `-DCMAKE_BUILD_TYPE=Release` or `-DCMAKE_BUILD_TYPE=RelWithDebInfo` as an extra argument to `cmake` during its first run (if you forgot to do this, you can later delete file `CMakeCache.txt` from your build directory and re-run `cmake` with the appropriate options). 1. Full Node binaries ~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/LiteClient-HOWTO b/doc/LiteClient-HOWTO index a4aacbb..272c447 100644 --- a/doc/LiteClient-HOWTO +++ b/doc/LiteClient-HOWTO @@ -22,14 +22,14 @@ Example: The "test giver" (a special smart contract residing in the masterchain of the Test Network that gives up to 20 test Grams to anybody who asks) has the address --1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d +-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260 in the "raw" form (notice that uppercase Latin letters 'A'..'F' may be used instead of 'a'..'f') and -Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb (base64) or -Ef-BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb (base64url) +kf/8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny (base64) +kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny (base64url) in the "user-friendly" form (to be displayed by user-friendly clients). Notice that both forms (base64 and base64url) are valid and must be accepted. @@ -50,27 +50,27 @@ Inspecting the state of smart contracts with the aid of the TON Lite Client is e > last ... -> getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d +> getaccount -1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260 or -> getaccount Ef-BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb +> getaccount kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny You will see something like this: ------------------------------------ -got account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D with respect to blocks (-1,8000000000000000,1645):4D5E1B928490BE34A4F03C9BC996661B8AD4E988F1460DB69BE3634B1E843DAF:9D85BB116D1DA4BFD999E9092BBD43B3A9F96EC9C9ED7AFDC81B27B08D3861A0 and (-1,8000000000000000,1645):4D5E1B928490BE34A4F03C9BC996661B8AD4E988F1460DB69BE3634B1E843DAF:9D85BB116D1DA4BFD999E9092BBD43B3A9F96EC9C9ED7AFDC81B27B08D3861A0 +got account state for -1 : FCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260 with respect to blocks (-1,8000000000000000,2075):BFE876CE2085274FEDAF1BD80F3ACE50F42B5A027DF230AD66DCED1F09FB39A7:522C027A721FABCB32574E3A809ABFBEE6A71DE929C1FA2B1CD0DDECF3056505 account state is (account addr:(addr_std - anycast:nothing workchain_id:-1 address:x8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D) + anycast:nothing workchain_id:-1 address:xFCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260) storage_stat:(storage_info used:(storage_used cells:(var_uint len:1 value:3) - bits:(var_uint len:2 value:539) - public_cells:(var_uint len:0 value:0)) last_paid:0 + bits:(var_uint len:2 value:707) + public_cells:(var_uint len:0 value:0)) last_paid:1568899526 due_payment:nothing) - storage:(account_storage last_trans_lt:0 + storage:(account_storage last_trans_lt:2310000003 balance:(currencies grams:(nanograms - amount:(var_uint len:7 value:1000000000000000)) + amount:(var_uint len:6 value:9998859500889)) other:(extra_currencies dict:hme_empty)) state:(account_active @@ -80,7 +80,7 @@ account state is (account code:(just value:(raw@^Cell x{} - x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} + x{FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F260D31F01ED44D0D31FD166BAF2A1F8000120D74A8E11D307D459821804A817C80073FB0201FB00DED1A4C8CB1FC9ED54} )) data:(just value:(raw@^Cell @@ -88,9 +88,10 @@ account state is (account x{00009A15} )) library:hme_empty)))) -x{CFF8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D2068086C0000000000000000000000001C0E35FA931A000134_} - x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} - x{00000000} +x{CFFFCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB2923226020680B0C2EC1C0E300000000226BF360D8246029DFF56534_} + x{FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F260D31F01ED44D0D31FD166BAF2A1F8000120D74A8E11D307D459821804A817C80073FB0201FB00DED1A4C8CB1FC9ED54} + x{00000003} +last transaction lt = 2310000001 hash = 73F89C6F8910F598AD84504A777E5945C798AC8C847FF861C090109665EAC6BA ------------------------------------ The first information line "got account state ... for ..." shows the account address and the masterchain block identifier with respect to which the account state has been dumped. Notice that even if the account state changes in a subsequent block, the `getaccount xxx` command will return the same result until the reference block is updated to a newer value by a `last` command. In this way one can study the state of all accounts and obtain consistent results. @@ -99,7 +100,7 @@ The "account state is (account ... " line begins the pretty-printed deserialized Finally, the last several lines beginning with x{CFF538... (the "raw dump") contain the same information displayed as a tree of cells. In this case, we have one root cell containing the data bits CFF...134_ (the underscore means that the last binary one and all subsequent binary zeroes are to be removed, so hexadecimal "4_" corresponds to binary "0"), and two cells that are its children (displayed with one-space indentation). -We can see that x{FF0020DDA4F260...} is the code of this smart contract. If we consult the Appendix A of the TON Virtual Machine documentation, we can even disassemble this code: FF00 is SETCP 0, 20 is DUP, DD is IFNOTRET, A4 is INC, F260 is THROWIF 32, and so on. (Incidentally, you can find the source code of this smartcontract in the source file crypto/block/mc0.fif .) +We can see that x{FF0020DD20...} is the code of this smart contract. If we consult the Appendix A of the TON Virtual Machine documentation, we can even disassemble this code: FF00 is SETCP 0, 20 is DUP, DD is IFNOTRET, 20 is DUP, and so on. (Incidentally, you can find the source code of this smartcontract in the source file crypto/block/new-testgiver.fif .) We can also see that x{00009A15} (the actual value you see may be different) is the persistent data of this smart contract. It is actually an unsigned 32-bit integer, used by the smart contract as the counter of operations performed so far. Notice that this value is big-endian (i.e., 3 is encoded as x{00000003}, not as x{03000000}), as are all integers inside the TON Blockchain. In this case the counter is equal to 0x9A15 = 39445. @@ -246,12 +247,26 @@ In the Test Network, you have another option: you can ask the "test giver" to gi 5. Using the test giver smart contract ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You need to know the address of the test giver smart contract. We'll assume that it is -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d, or, equivalently, Ef-BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb, as indicated in one of the previous examples. You inspect the state of this smart contract in the Lite Client by typing +You need to know the address of the test giver smart contract. We'll assume that it is -1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260, or, equivalently, kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny, as indicated in one of the previous examples. You inspect the state of this smart contract in the Lite Client by typing > last -> getaccount Ef-BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb +> getaccount kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny -as explained above in Section 2. The only number you need from the output is the 32-bit sequence number stored in the smart contract data (it is zero in the example above, but generally it will be non-zero). +as explained above in Section 2. The only number you need from the output is the 32-bit sequence number stored in the smart contract data (it is 0x9A15 in the example above, but generally it will be different). A simpler way of obtaining the current value of this sequence number is by typing + +> last +> runmethod kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny seqno + +producing the correct value 39445 = 0x9A15: + +-------------------------------------------- +got account state for -1 : FCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260 with respect to blocks (-1,8000000000000000,2240):18E6DA7707191E76C71EABBC5277650666B7E2CFA2AEF2CE607EAFE8657A3820:4EFA2540C5D1E4A1BA2B529EE0B65415DF46BFFBD27A8EB74C4C0E17770D03B1 +creating VM +starting VM to run method `seqno` (85143) of smart contract -1:FCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260 +... +arguments: [ 85143 ] +result: [ 39445 ] +-------------------------------------------- Next, you create an external message to the test giver asking it to send another message to your (uninitialized) smart contract carrying a specified amount of test Grams. There is a special Fift script for generating this external message located at crypto/smartcont/testgiver.fif: @@ -267,7 +282,7 @@ Next, you create an external message to the test giver asking it to send another $# 3 - -2 and ' usage if // "testgiver.addr" load-address -Masterchain 0x8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d +Masterchain 0xfcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260 2constant giver_addr ."Test giver address = " giver_addr 2dup .addr cr 6 .Addr cr @@ -314,8 +329,8 @@ This Fift code creates an internal message from the test giver smart contract to The external message is serialized and saved into the file `wallet-query.boc`. Some output is generated in the process: --------------------------------------------- -Test giver address = -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d -kf-BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODZKR +Test giver address = -1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260 +kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny Requesting GR$6.666 to account 0QAu6bT9Twd8myIygMNXY9-e2rC0GsINNvQAlnfflcOv4uVb = 0:2ee9b4fd4f077c9b223280c35763df9edab0b41ac20d36f4009677df95c3afe2 seqno=0x9a15 bounce=0 enveloping message: x{00009A1501} x{42001774DA7EA783BE4D91194061ABB1EFCF6D585A0D61069B7A004B3BEFCAE1D7F1280C6A98B4000000000000000000000000000047494654} @@ -340,19 +355,19 @@ We will see some output: which means that the external message has been delivered to the collator pool. Afterwards one of the collators might choose to include this external message in a block, creating a transaction for the test giver smart contract to process this external message. We can check whether the state of the test giver has changed: > last -> getaccount Ef-BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb +> getaccount kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny (If you forget to type `last`, you are likely to see the unchanged state of the test giver smart contract.) The resulting output would be: --------------------------------------------- -got account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D with respect to blocks (-1,8000000000000000,10441):2DCFB7F734913261B85B8866DFF7CBEF07205EAA0769F4EE15E242AB520A2CC5:4F96F417BCD74D5DAE0CC3CCC285E513B85652002D9AD8CC884781D8465E3591 and (-1,8000000000000000,10441):2DCFB7F734913261B85B8866DFF7CBEF07205EAA0769F4EE15E242AB520A2CC5:4F96F417BCD74D5DAE0CC3CCC285E513B85652002D9AD8CC884781D8465E3591 +got account state for -1 : FCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260 with respect to blocks (-1,8000000000000000,2240):18E6DA7707191E76C71EABBC5277650666B7E2CFA2AEF2CE607EAFE8657A3820:4EFA2540C5D1E4A1BA2B529EE0B65415DF46BFFBD27A8EB74C4C0E17770D03B1 account state is (account addr:(addr_std - anycast:nothing workchain_id:-1 address:x8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D) + anycast:nothing workchain_id:-1 address:xFCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260) storage_stat:(storage_info used:(storage_used cells:(var_uint len:1 value:3) - bits:(var_uint len:2 value:539) + bits:(var_uint len:2 value:707) public_cells:(var_uint len:0 value:0)) last_paid:0 due_payment:nothing) storage:(account_storage last_trans_lt:10697000003 diff --git a/example/android/test/ton/src/androidTest/java/drinkless/org/ton/TonTest.kt b/example/android/test/ton/src/androidTest/java/drinkless/org/ton/TonTest.kt index 5696ad5..68fe1a7 100644 --- a/example/android/test/ton/src/androidTest/java/drinkless/org/ton/TonTest.kt +++ b/example/android/test/ton/src/androidTest/java/drinkless/org/ton/TonTest.kt @@ -33,10 +33,8 @@ class ClientKotlin { @SmallTest class TonTest { val config = """{ - "@type": "config.global", - "liteclients": [ + "liteservers": [ { - "@type": "liteclient.config.global", "ip": 1137658550, "port": 4924, "id": { @@ -44,7 +42,17 @@ class TonTest { "key": "peJTw/arlRfssgTuf9BMypJzqOi7SXEqSPSWiEw2U1M=" } } - ] + ], + "validator": { + "@type": "validator.config.global", + "zero_state": { + "workchain": -1, + "shard": -9223372036854775808, + "seqno": 0, + "root_hash": "VCSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=", + "file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo=" + } + } }""" @Test fun createTestWallet() { @@ -52,7 +60,7 @@ class TonTest { val dir = getContext().getExternalFilesDir(null).toString() + "/"; runBlocking { client.send(TonApi.Init(TonApi.Options(config, dir))) - val key = client.send(TonApi.CreateNewKey("local password".toByteArray(), "mnemonic password".toByteArray())) as TonApi.Key + val key = client.send(TonApi.CreateNewKey("local password".toByteArray(), "mnemonic password".toByteArray(), "".toByteArray())) as TonApi.Key val walletAddress = client.send(TonApi.TestWalletGetAccountAddress(TonApi.TestWalletInitialAccountState(key.publicKey))) as TonApi.AccountAddress; val testGiverState = client.send(TonApi.TestGiverGetAccountState()) as TonApi.TestGiverAccountState diff --git a/example/android/test/ton/src/androidTest/java/drinkless/org/ton/TonTestJava.java b/example/android/test/ton/src/androidTest/java/drinkless/org/ton/TonTestJava.java index 1a9f2ad..5f8de61 100644 --- a/example/android/test/ton/src/androidTest/java/drinkless/org/ton/TonTestJava.java +++ b/example/android/test/ton/src/androidTest/java/drinkless/org/ton/TonTestJava.java @@ -54,21 +54,28 @@ public class TonTestJava { } } - String config = - "{" + - "\"@type\": \"config.global\"," + - "\"liteclients\": [" + - "{" + - "\"@type\": \"liteclient.config.global\"," + - "\"ip\": 1137658550," + - "\"port\": 4924," + - "\"id\": {" + - "\"@type\": \"pub.ed25519\"," + - "\"key\": \"peJTw/arlRfssgTuf9BMypJzqOi7SXEqSPSWiEw2U1M=\"" + - "}" + - "}" + - "]" + - "}"; + String config = "{\n" + + " \"liteservers\": [\n" + + " {\n" + + " \"ip\": 1137658550,\n" + + " \"port\": 4924,\n" + + " \"id\": {\n" + + " \"@type\": \"pub.ed25519\",\n" + + " \"key\": \"peJTw/arlRfssgTuf9BMypJzqOi7SXEqSPSWiEw2U1M=\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"validator\": {\n" + + " \"@type\": \"validator.config.global\",\n" + + " \"zero_state\": {\n" + + " \"workchain\": -1,\n" + + " \"shard\": -9223372036854775808,\n" + + " \"seqno\": 0,\n" + + " \"root_hash\": \"VCSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=\",\n" + + " \"file_hash\": \"eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo=\"\n" + + " }\n" + + " }\n" + + "}"; private void appendLog(String log) { Log.w("XX", log); @@ -85,7 +92,7 @@ public class TonTestJava { return; } appendLog("config set ok"); - TonApi.Key key = (TonApi.Key) client.send(new TonApi.CreateNewKey("local password".getBytes(), "mnemonic password".getBytes())); + TonApi.Key key = (TonApi.Key) client.send(new TonApi.CreateNewKey("local password".getBytes(), "mnemonic password".getBytes(), "".getBytes())); appendLog("got private key"); TonApi.AccountAddress walletAddress = (TonApi.AccountAddress) client.send(new TonApi.TestWalletGetAccountAddress(new TonApi.TestWalletInitialAccountState(key.publicKey))); appendLog("got account address"); diff --git a/tdutils/CMakeLists.txt b/tdutils/CMakeLists.txt index b8081aa..ed82dbb 100644 --- a/tdutils/CMakeLists.txt +++ b/tdutils/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +option(TDUTILS_MIME_TYPE "Generate mime types conversion (gperf is required)" ON) + if (WIN32) if (WINGETOPT_FOUND) set(TD_HAVE_GETOPT 1) @@ -96,7 +98,6 @@ set(TDUTILS_SOURCE td/utils/JsonBuilder.cpp td/utils/logging.cpp td/utils/misc.cpp - td/utils/MimeType.cpp td/utils/MpmcQueue.cpp td/utils/OptionsParser.cpp td/utils/Random.cpp @@ -202,7 +203,6 @@ set(TDUTILS_SOURCE td/utils/List.h td/utils/logging.h td/utils/MemoryLog.h - td/utils/MimeType.h td/utils/misc.h td/utils/MovableValue.h td/utils/MpmcQueue.h @@ -251,6 +251,14 @@ set(TDUTILS_SOURCE td/utils/VectorQueue.h ) +if (TDUTILS_MIME_TYPE) + set(TDUTILS_SOURCE + ${TDUTILS_SOURCE} + td/utils/MimeType.cpp + td/utils/MimeType.h + ) +endif() + set(TDUTILS_TEST_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/test/buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/ConcurrentHashMap.cpp @@ -284,7 +292,7 @@ if (WIN32) # target_link_libraries(tdutils PRIVATE ${WS2_32_LIBRARY} ${MSWSOCK_LIBRARY}) target_link_libraries(tdutils PRIVATE ws2_32 Mswsock Normaliz) endif() -if (NOT CMAKE_CROSSCOMPILING) +if (NOT CMAKE_CROSSCOMPILING AND TDUTILS_MIME_TYPE) add_dependencies(tdutils tdmime_auto) endif() diff --git a/tdutils/generate/CMakeLists.txt b/tdutils/generate/CMakeLists.txt index 9eca574..07353e5 100644 --- a/tdutils/generate/CMakeLists.txt +++ b/tdutils/generate/CMakeLists.txt @@ -3,6 +3,10 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) # Generates files for MIME type <-> extension conversions # DEPENDS ON: gperf grep bash/powershell +if (NOT TDUTILS_MIME_TYPE) + return() +endif() + file(MAKE_DIRECTORY auto) set(TDMIME_SOURCE diff --git a/tdutils/td/utils/tl_parsers.h b/tdutils/td/utils/tl_parsers.h index d9efc3e..734afdb 100644 --- a/tdutils/td/utils/tl_parsers.h +++ b/tdutils/td/utils/tl_parsers.h @@ -168,8 +168,9 @@ class TlParser { data += sizeof(int32); } else { check_len(sizeof(int32)); - result_len = data[1] + (data[2] << 8) + (data[3] << 16) + (data[4] << 24) + (static_cast(data[5]) << 32) + - (static_cast(data[6]) << 40) + (static_cast(data[7]) << 48); + result_len = narrow_cast(data[1] + (data[2] << 8) + (data[3] << 16) + (data[4] << 24) + + (static_cast(data[5]) << 32) + (static_cast(data[6]) << 40) + + (static_cast(data[7]) << 48)); if (result_len > std::numeric_limits::max() - 3) { set_error("Too big string found"); return T(); diff --git a/tl/generate/scheme/ton_api.tl b/tl/generate/scheme/ton_api.tl index a4212bb..073595c 100644 --- a/tl/generate/scheme/ton_api.tl +++ b/tl/generate/scheme/ton_api.tl @@ -367,6 +367,10 @@ tonNode.downloadZeroState block:tonNode.blockIdExt = tonNode.Data; tonNode.downloadBlockProof block:tonNode.blockIdExt = tonNode.Data; tonNode.downloadBlockProofLink block:tonNode.blockIdExt = tonNode.Data; +tonNode.slave.sendExtMessage message:tonNode.externalMessage = True; + +tonNode.query = Object; + ---types--- // bit 0 - started @@ -482,9 +486,12 @@ engine.controlInterface id:int256 port:int allowed:(vector engine.controlProcess engine.gc ids:(vector int256) = engine.Gc; engine.dht.config dht:(vector engine.dht) gc:engine.gc = engine.dht.Config; +engine.validator.fullNodeMaster port:int adnl:int256 = engine.validator.FullNodeMaster; +engine.validator.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave; engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl) dht:(vector engine.dht) - validators:(vector engine.validator) fullnode:int256 + validators:(vector engine.validator) fullnode:int256 fullnodeslave:engine.validator.fullNodeSlave + fullnodemasters:(vector engine.validator.fullNodeMaster) liteservers:(vector engine.liteServer) control:(vector engine.controlInterface) gc:engine.gc = engine.validator.Config; diff --git a/tl/generate/scheme/ton_api.tlo b/tl/generate/scheme/ton_api.tlo index 10e98bde912e0131c4910aa5c5919abe484d8146..00dc97c4e01c909e9d9d044767f1066cac991239 100644 GIT binary patch delta 484 zcmZ3{$9!QjGw-9>`c@23uxul*x**H9U{=P>7J@pADjDBeTjW#o(lhf?^~w@+GE)*u z@{9D`N^^4j@>5cM6N^hyizaT6P_E2Y?U2K%E;uK#EOp{~$;~N354agQHoMC04qydY zB0f2Bs|Zh8W;%#-^O%qi_vFHjI+FwQKb!KV0WHY`T2c(s3~?TZZQDVRO^i_2NwW>Q7ka|g*gvTku#eP%om$IiXBWD z?KgL>*exq_S>7XF8y!_UFa>FE<$sChKCLIu%>~ic00AU`nWdHyG delta 111 zcmcaGnR!JYGw-9>`c@23uw)~zx*&^$#code_, f->message_); } - auto res = ton::fetch_result(std::move(data)); - return std::move(res); + return ton::fetch_result(std::move(data)); }()); }); } diff --git a/tonlib/tonlib/TestGiver.cpp b/tonlib/tonlib/TestGiver.cpp index c4b5986..c9ebbcc 100644 --- a/tonlib/tonlib/TestGiver.cpp +++ b/tonlib/tonlib/TestGiver.cpp @@ -24,12 +24,12 @@ namespace tonlib { const block::StdAddress& TestGiver::address() { static block::StdAddress res = - block::StdAddress::parse("-1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d").move_as_ok(); + block::StdAddress::parse("kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny").move_as_ok(); return res; } vm::CellHash TestGiver::get_init_code_hash() { - return vm::CellHash::from_slice(td::base64_decode("s7RouN9wfJ4Avx8h0uw6X3ZEJfN3MYOUmzrC8JXfMAw=").move_as_ok()); + return vm::CellHash::from_slice(td::base64_decode("wDkZp0yR4xo+9+BnuAPfGVjBzK6FPzqdv2DwRq3z3KE=").move_as_ok()); } td::Ref TestGiver::make_a_gift_message(td::uint32 seqno, td::uint64 gramms, diff --git a/tonlib/tonlib/keys/DecryptedKey.h b/tonlib/tonlib/keys/DecryptedKey.h index 19f60ad..14086d0 100644 --- a/tonlib/tonlib/keys/DecryptedKey.h +++ b/tonlib/tonlib/keys/DecryptedKey.h @@ -48,7 +48,7 @@ struct RawDecryptedKey { struct EncryptedKey; struct DecryptedKey { - DecryptedKey() = default; + DecryptedKey() = delete; explicit DecryptedKey(const Mnemonic &mnemonic); DecryptedKey(std::vector mnemonic_words, td::Ed25519::PrivateKey key); DecryptedKey(RawDecryptedKey key); diff --git a/validator-engine/validator-engine.cpp b/validator-engine/validator-engine.cpp index 4746062..a118fcd 100644 --- a/validator-engine/validator-engine.cpp +++ b/validator-engine/validator-engine.cpp @@ -121,6 +121,18 @@ Config::Config(ton::ton_api::engine_validator_config &config) { } config_add_full_node_adnl_id(ton::PublicKeyHash{config.fullnode_}).ensure(); + if (config.fullnodeslave_) { + td::IPAddress ip; + ip.init_ipv4_port(td::IPAddress::ipv4_to_str(config.fullnodeslave_->ip_), + static_cast(config.fullnodeslave_->port_)) + .ensure(); + config_add_full_node_slave(ip, ton::PublicKey{config.fullnodeslave_->adnl_}).ensure(); + } + + for (auto &s : config.fullnodemasters_) { + config_add_full_node_master(s->port_, ton::PublicKeyHash{s->adnl_}).ensure(); + } + for (auto &serv : config.liteservers_) { config_add_lite_server(ton::PublicKeyHash{serv->id_}, serv->port_).ensure(); } @@ -180,6 +192,17 @@ ton::tl_object_ptr Config::tl() const { val.first.tl(), std::move(temp_vec), std::move(adnl_val_vec), val.second.election_date, val.second.expire_at)); } + ton::tl_object_ptr full_node_slave = nullptr; + if (!full_node_slave_adnl_id.empty()) { + full_node_slave = ton::create_tl_object( + full_node_slave_addr.get_ipv4(), full_node_slave_addr.get_port(), full_node_slave_adnl_id.tl()); + } + std::vector> full_node_masters_vec; + for (auto &x : full_node_masters) { + full_node_masters_vec.push_back( + ton::create_tl_object(x.first, x.second.tl())); + } + std::vector> liteserver_vec; for (auto &x : liteservers) { liteserver_vec.push_back(ton::create_tl_object(x.second.tl(), x.first)); @@ -201,7 +224,8 @@ ton::tl_object_ptr Config::tl() const { } return ton::create_tl_object( out_port, std::move(addrs_vec), std::move(adnl_vec), std::move(dht_vec), std::move(val_vec), full_node.tl(), - std::move(liteserver_vec), std::move(control_vec), std::move(gc_vec)); + std::move(full_node_slave), std::move(full_node_masters_vec), std::move(liteserver_vec), std::move(control_vec), + std::move(gc_vec)); } td::Result Config::config_add_network_addr(td::IPAddress in_ip, td::IPAddress out_ip, @@ -362,6 +386,36 @@ td::Result Config::config_add_full_node_adnl_id(ton::PublicKeyHash id) { return true; } +td::Result Config::config_add_full_node_slave(td::IPAddress addr, ton::PublicKey id) { + if (full_node_slave_adnl_id == id && addr == full_node_slave_addr) { + return false; + } + full_node_slave_adnl_id = id; + full_node_slave_addr = addr; + return true; +} + +td::Result Config::config_add_full_node_master(td::int32 port, ton::PublicKeyHash id) { + if (adnl_ids.count(id) == 0) { + return td::Status::Error(ton::ErrorCode::notready, + "to-be-added full node master adnl address not in adnl nodes list"); + } + auto it = full_node_masters.find(port); + if (it != full_node_masters.end()) { + if (it->second == id) { + return false; + } else { + return td::Status::Error("duplicate master port"); + } + } + if (liteservers.count(port) > 0 || controls.count(port) > 0) { + return td::Status::Error("duplicate master port"); + } + incref(id); + full_node_masters.emplace(port, id); + return true; +} + td::Result Config::config_add_lite_server(ton::PublicKeyHash key, td::int32 port) { if (controls.count(port) > 0) { return td::Status::Error(ton::ErrorCode::error, "duplicate port"); @@ -1351,8 +1405,11 @@ void ValidatorEngine::start_dht() { add_dht(dht); } - CHECK(!default_dht_node_.is_zero()); - td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_dht_node, dht_nodes_[default_dht_node_].get()); + if (default_dht_node_.is_zero()) { + LOG(ERROR) << "trying to work without DHT"; + } else { + td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_dht_node, dht_nodes_[default_dht_node_].get()); + } started_dht(); } @@ -1371,8 +1428,10 @@ void ValidatorEngine::started_rldp() { } void ValidatorEngine::start_overlays() { - overlay_manager_ = - ton::overlay::Overlays::create(db_root_, keyring_.get(), adnl_.get(), dht_nodes_[default_dht_node_].get()); + if (!default_dht_node_.is_zero()) { + overlay_manager_ = + ton::overlay::Overlays::create(db_root_, keyring_.get(), adnl_.get(), dht_nodes_[default_dht_node_].get()); + } started_overlays(); } @@ -1403,14 +1462,26 @@ void ValidatorEngine::started_validator() { } void ValidatorEngine::start_full_node() { - if (!config_.full_node.is_zero()) { + if (!config_.full_node.is_zero() || !config_.full_node_slave_adnl_id.empty()) { auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()}; auto short_id = pk.compute_short_id(); td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {}); + if (!config_.full_node_slave_adnl_id.empty()) { + class Cb : public ton::adnl::AdnlExtClient::Callback { + public: + void on_ready() override { + } + void on_stop_ready() override { + } + }; + full_node_client_ = ton::adnl::AdnlExtClient::create(ton::adnl::AdnlNodeIdFull{config_.full_node_slave_adnl_id}, + config_.full_node_slave_addr, std::make_unique()); + } full_node_ = ton::validator::fullnode::FullNode::create( short_id, ton::adnl::AdnlNodeIdShort{config_.full_node}, validator_options_->zero_block_id().file_hash, - keyring_.get(), adnl_.get(), rldp_.get(), dht_nodes_[default_dht_node_].get(), overlay_manager_.get(), - validator_manager_.get(), db_root_); + keyring_.get(), adnl_.get(), rldp_.get(), + default_dht_node_.is_zero() ? td::actor::ActorId{} : dht_nodes_[default_dht_node_].get(), + overlay_manager_.get(), validator_manager_.get(), full_node_client_.get(), db_root_); } for (auto &v : config_.validators) { @@ -1499,6 +1570,21 @@ void ValidatorEngine::started_control_interface(td::actor::ActorOwn(s.first), p.first, p.second); } } + start_full_node_masters(); +} + +void ValidatorEngine::start_full_node_masters() { + for (auto &x : config_.full_node_masters) { + full_node_masters_.emplace( + static_cast(x.first), + ton::validator::fullnode::FullNodeMaster::create( + ton::adnl::AdnlNodeIdShort{x.second}, static_cast(x.first), + validator_options_->zero_block_id().file_hash, keyring_.get(), adnl_.get(), validator_manager_.get())); + } + started_full_node_masters(); +} + +void ValidatorEngine::started_full_node_masters() { started(); } diff --git a/validator-engine/validator-engine.hpp b/validator-engine/validator-engine.hpp index e31da0f..b0eae3d 100644 --- a/validator-engine/validator-engine.hpp +++ b/validator-engine/validator-engine.hpp @@ -33,6 +33,8 @@ #include "validator/manager.h" #include "validator/validator.h" #include "validator/full-node.h" +#include "validator/full-node-master.h" +#include "adnl/adnl-ext-client.h" #include "td/actor/MultiPromise.h" @@ -74,7 +76,10 @@ struct Config { std::map adnl_ids; std::set dht_ids; std::map validators; - ton::PublicKeyHash full_node; + ton::PublicKeyHash full_node = ton::PublicKeyHash::zero(); + td::IPAddress full_node_slave_addr; + ton::PublicKey full_node_slave_adnl_id; + std::map full_node_masters; std::map liteservers; std::map controls; std::set gc; @@ -96,6 +101,8 @@ struct Config { td::Result config_add_validator_adnl_id(ton::PublicKeyHash perm_key, ton::PublicKeyHash adnl_id, ton::UnixTime expire_at); td::Result config_add_full_node_adnl_id(ton::PublicKeyHash id); + td::Result config_add_full_node_slave(td::IPAddress addr, ton::PublicKey id); + td::Result config_add_full_node_master(td::int32 port, ton::PublicKeyHash id); td::Result config_add_lite_server(ton::PublicKeyHash key, td::int32 port); td::Result config_add_control_interface(ton::PublicKeyHash key, td::int32 port); td::Result config_add_control_process(ton::PublicKeyHash key, td::int32 port, ton::PublicKeyHash id, @@ -130,7 +137,9 @@ class ValidatorEngine : public td::actor::Actor { ton::PublicKeyHash default_dht_node_ = ton::PublicKeyHash::zero(); td::actor::ActorOwn overlay_manager_; td::actor::ActorOwn validator_manager_; + td::actor::ActorOwn full_node_client_; td::actor::ActorOwn full_node_; + std::map> full_node_masters_; td::actor::ActorOwn control_ext_server_; std::string local_config_ = ""; @@ -266,6 +275,9 @@ class ValidatorEngine : public td::actor::Actor { void start_control_interface(); void started_control_interface(td::actor::ActorOwn control_ext_server); + void start_full_node_masters(); + void started_full_node_masters(); + void started(); void alarm() override; diff --git a/validator/CMakeLists.txt b/validator/CMakeLists.txt index c74b602..4bc908d 100644 --- a/validator/CMakeLists.txt +++ b/validator/CMakeLists.txt @@ -111,6 +111,9 @@ set(FULL_NODE_SOURCE full-node-shard.h full-node-shard.hpp full-node-shard.cpp + full-node-master.h + full-node-master.hpp + full-node-master.cpp net/download-block.hpp net/download-block.cpp diff --git a/validator/full-node-master.cpp b/validator/full-node-master.cpp new file mode 100644 index 0000000..93543fe --- /dev/null +++ b/validator/full-node-master.cpp @@ -0,0 +1,357 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser 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 Library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2019 Telegram Systems LLP +*/ +#include "td/utils/SharedSlice.h" +#include "full-node-master.hpp" + +#include "ton/ton-shard.h" +#include "ton/ton-tl.hpp" + +#include "adnl/utils.hpp" + +#include "common/delay.h" + +namespace ton { + +namespace validator { + +namespace fullnode { + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextBlockDescription &query, + td::Promise promise) { + auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result R) mutable { + if (R.is_error()) { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + } else { + auto B = R.move_as_ok(); + if (!B->received() || !B->inited_proof()) { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + } else { + auto x = create_serialize_tl_object(create_tl_block_id(B->id())); + promise.set_value(std::move(x)); + } + } + }); + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_next_block, + create_block_id(query.prev_block_), std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlock &query, + td::Promise promise) { + auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result R) mutable { + if (R.is_error()) { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + } else { + auto B = R.move_as_ok(); + if (!B->received()) { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + } else { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + } + } + }); + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle, + create_block_id(query.block_), false, std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlock &query, + td::Promise promise) { + auto P = td::PromiseCreator::lambda([validator_manager = validator_manager_, + promise = std::move(promise)](td::Result R) mutable { + if (R.is_error()) { + promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block")); + } else { + auto B = R.move_as_ok(); + if (!B->received()) { + promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block")); + } else { + td::actor::send_closure(validator_manager, &ValidatorManagerInterface::get_block_data, B, std::move(promise)); + } + } + }); + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle, + create_block_id(query.block_), false, std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlockProof &query, + td::Promise promise) { + if (query.block_->seqno_ == 0) { + promise.set_error(td::Status::Error(ErrorCode::protoviolation, "cannot download proof for zero state")); + return; + } + auto P = td::PromiseCreator::lambda([allow_partial = query.allow_partial_, promise = std::move(promise), + validator_manager = validator_manager_](td::Result R) mutable { + if (R.is_error()) { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + return; + } else { + auto handle = R.move_as_ok(); + if (!handle || (!handle->inited_proof() && (!allow_partial || !handle->inited_proof_link()))) { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + return; + } + if (handle->inited_proof() && handle->id().is_masterchain()) { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + } else { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + } + } + }); + + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle, + create_block_id(query.block_), false, std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProof &query, + td::Promise promise) { + auto P = td::PromiseCreator::lambda( + [promise = std::move(promise), validator_manager = validator_manager_](td::Result R) mutable { + if (R.is_error()) { + promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof")); + return; + } else { + auto handle = R.move_as_ok(); + if (!handle || !handle->inited_proof()) { + promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof")); + return; + } + + td::actor::send_closure(validator_manager, &ValidatorManagerInterface::get_block_proof, handle, + std::move(promise)); + } + }); + + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle, + create_block_id(query.block_), false, std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProofLink &query, + td::Promise promise) { + auto P = td::PromiseCreator::lambda( + [promise = std::move(promise), validator_manager = validator_manager_](td::Result R) mutable { + if (R.is_error()) { + promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof")); + return; + } else { + auto handle = R.move_as_ok(); + if (!handle || !handle->inited_proof_link()) { + promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof")); + return; + } + + td::actor::send_closure(validator_manager, &ValidatorManagerInterface::get_block_proof_link, handle, + std::move(promise)); + } + }); + + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle, + create_block_id(query.block_), false, std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareZeroState &query, + td::Promise promise) { + auto P = + td::PromiseCreator::lambda([SelfId = actor_id(this), promise = std::move(promise)](td::Result R) mutable { + if (R.is_error() || !R.move_as_ok()) { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + return; + } + + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + }); + auto block_id = create_block_id(query.block_); + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::check_zero_state_exists, block_id, + std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_preparePersistentState &query, + td::Promise promise) { + auto P = + td::PromiseCreator::lambda([SelfId = actor_id(this), promise = std::move(promise)](td::Result R) mutable { + if (R.is_error() || !R.move_as_ok()) { + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + return; + } + + auto x = create_serialize_tl_object(); + promise.set_value(std::move(x)); + }); + auto block_id = create_block_id(query.block_); + auto masterchain_block_id = create_block_id(query.masterchain_block_); + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::check_persistent_state_exists, block_id, + masterchain_block_id, std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextKeyBlockIds &query, + td::Promise promise) { + auto cnt = static_cast(query.max_size_); + if (cnt > 8) { + cnt = 8; + } + auto P = + td::PromiseCreator::lambda([promise = std::move(promise), cnt](td::Result> R) mutable { + if (R.is_error()) { + LOG(WARNING) << "getnextkey: " << R.move_as_error(); + auto x = create_serialize_tl_object( + std::vector>{}, false, true); + promise.set_value(std::move(x)); + return; + } + auto res = R.move_as_ok(); + std::vector> v; + for (auto &b : res) { + v.emplace_back(create_tl_block_id(b)); + } + auto x = create_serialize_tl_object(std::move(v), res.size() < cnt, false); + promise.set_value(std::move(x)); + }); + auto block_id = create_block_id(query.block_); + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_next_key_blocks, block_id, cnt, + std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadZeroState &query, + td::Promise promise) { + auto P = td::PromiseCreator::lambda( + [SelfId = actor_id(this), promise = std::move(promise)](td::Result R) mutable { + if (R.is_error()) { + promise.set_error(R.move_as_error_prefix("failed to get state from db: ")); + return; + } + + promise.set_value(R.move_as_ok()); + }); + auto block_id = create_block_id(query.block_); + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_zero_state, block_id, std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentState &query, + td::Promise promise) { + auto P = td::PromiseCreator::lambda( + [SelfId = actor_id(this), promise = std::move(promise)](td::Result R) mutable { + if (R.is_error()) { + promise.set_error(R.move_as_error_prefix("failed to get state from db: ")); + return; + } + + promise.set_value(R.move_as_ok()); + }); + auto block_id = create_block_id(query.block_); + auto masterchain_block_id = create_block_id(query.masterchain_block_); + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state, block_id, + masterchain_block_id, std::move(P)); +} + +void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSlice &query, + td::Promise promise) { + auto P = td::PromiseCreator::lambda( + [SelfId = actor_id(this), promise = std::move(promise)](td::Result R) mutable { + if (R.is_error()) { + promise.set_error(R.move_as_error_prefix("failed to get state from db: ")); + return; + } + + promise.set_value(R.move_as_ok()); + }); + auto block_id = create_block_id(query.block_); + auto masterchain_block_id = create_block_id(query.masterchain_block_); + td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state_slice, block_id, + masterchain_block_id, query.offset_, query.max_size_, std::move(P)); +} + +void FullNodeMasterImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, + td::Promise promise) { + auto BX = fetch_tl_prefix(query, true); + if (BX.is_error()) { + promise.set_error(td::Status::Error(ErrorCode::protoviolation, "cannot parse tonnode query")); + return; + } + auto B = fetch_tl_object(std::move(query), true); + if (B.is_error()) { + promise.set_error(td::Status::Error(ErrorCode::protoviolation, "cannot parse tonnode query")); + return; + } + ton_api::downcast_call(*B.move_as_ok().get(), [&](auto &obj) { this->process_query(src, obj, std::move(promise)); }); +} + +void FullNodeMasterImpl::start_up() { + class Cb : public adnl::Adnl::Callback { + public: + Cb(td::actor::ActorId id) : id_(std::move(id)) { + } + void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) override { + } + void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data, + td::Promise promise) override { + td::actor::send_closure(id_, &FullNodeMasterImpl::receive_query, src, std::move(data), std::move(promise)); + } + + private: + td::actor::ActorId id_; + }; + + td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, adnl_id_, + adnl::Adnl::int_to_bytestring(ton_api::tonNode_query::ID), + std::make_unique(actor_id(this))); + + auto P = + td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result> R) { + R.ensure(); + R.move_as_ok().release(); + }); + td::actor::send_closure(adnl_, &adnl::Adnl::create_ext_server, std::vector{adnl_id_}, + std::vector{port_}, std::move(P)); +} + +FullNodeMasterImpl::FullNodeMasterImpl(adnl::AdnlNodeIdShort adnl_id, td::uint16 port, FileHash zero_state_file_hash, + td::actor::ActorId keyring, + td::actor::ActorId adnl, + td::actor::ActorId validator_manager) + : adnl_id_(adnl_id) + , port_(port) + , zero_state_file_hash_(zero_state_file_hash) + , keyring_(keyring) + , adnl_(adnl) + , validator_manager_(validator_manager) { +} + +td::actor::ActorOwn FullNodeMaster::create( + adnl::AdnlNodeIdShort adnl_id, td::uint16 port, FileHash zero_state_file_hash, + td::actor::ActorId keyring, td::actor::ActorId adnl, + td::actor::ActorId validator_manager) { + return td::actor::create_actor("tonnode", adnl_id, port, zero_state_file_hash, keyring, adnl, + validator_manager); +} + +} // namespace fullnode + +} // namespace validator + +} // namespace ton diff --git a/validator/full-node-master.h b/validator/full-node-master.h new file mode 100644 index 0000000..ae7cc49 --- /dev/null +++ b/validator/full-node-master.h @@ -0,0 +1,45 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser 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 Library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2019 Telegram Systems LLP +*/ +#pragma once + +#include "full-node.h" +#include "validator/interfaces/block-handle.h" + +namespace ton { + +namespace validator { + +namespace fullnode { + +class FullNodeMaster : public td::actor::Actor { + public: + virtual ~FullNodeMaster() = default; + + static td::actor::ActorOwn create(adnl::AdnlNodeIdShort adnl_id, td::uint16 port, + FileHash zero_state_file_hash, + td::actor::ActorId keyring, + td::actor::ActorId adnl, + td::actor::ActorId validator_manager); +}; + +} // namespace fullnode + +} // namespace validator + +} // namespace ton diff --git a/validator/full-node-master.hpp b/validator/full-node-master.hpp new file mode 100644 index 0000000..83bd88f --- /dev/null +++ b/validator/full-node-master.hpp @@ -0,0 +1,83 @@ +/* + This file is part of TON Blockchain Library. + + TON Blockchain Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser 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 Library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with TON Blockchain Library. If not, see . + + Copyright 2017-2019 Telegram Systems LLP +*/ +#pragma once + +#include "full-node-master.h" + +namespace ton { + +namespace validator { + +namespace fullnode { + +class FullNodeMasterImpl : public FullNodeMaster { + public: + void start_up() override; + + template + void process_query(adnl::AdnlNodeIdShort src, T &query, td::Promise promise) { + promise.set_error(td::Status::Error(ErrorCode::error, "unknown query")); + } + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextBlockDescription &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlockProof &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProof &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProofLink &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlock &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlock &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareZeroState &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_preparePersistentState &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextKeyBlockIds &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadZeroState &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentState &query, + td::Promise promise); + void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSlice &query, + td::Promise promise); + // void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareNextKeyBlockProof &query, + // td::Promise promise); + void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, td::Promise promise); + + FullNodeMasterImpl(adnl::AdnlNodeIdShort adnl_id, td::uint16 port, FileHash zero_state_file_hash, + td::actor::ActorId keyring, td::actor::ActorId adnl, + td::actor::ActorId validator_manager); + + private: + adnl::AdnlNodeIdShort adnl_id_; + td::uint16 port_; + FileHash zero_state_file_hash_; + + td::actor::ActorId keyring_; + td::actor::ActorId adnl_; + td::actor::ActorId validator_manager_; +}; + +} // namespace fullnode + +} // namespace validator + +} // namespace ton diff --git a/validator/full-node-shard.cpp b/validator/full-node-shard.cpp index 566e771..912dc1c 100644 --- a/validator/full-node-shard.cpp +++ b/validator/full-node-shard.cpp @@ -78,7 +78,8 @@ void FullNodeShardImpl::try_get_next_block(td::Timestamp timeout, td::Promise("downloadnext", adnl_id_, overlay_id_, handle_, download_next_priority(), - timeout, validator_manager_, rldp_, overlays_, adnl_, std::move(promise)) + timeout, validator_manager_, rldp_, overlays_, adnl_, client_, + std::move(promise)) .release(); } @@ -446,6 +447,10 @@ void FullNodeShardImpl::receive_broadcast(PublicKeyHash src, td::BufferSlice bro } void FullNodeShardImpl::send_ihr_message(td::BufferSlice data) { + if (!client_.empty()) { + UNREACHABLE(); + return; + } auto B = create_serialize_tl_object( create_tl_object(std::move(data))); if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) { @@ -458,6 +463,18 @@ void FullNodeShardImpl::send_ihr_message(td::BufferSlice data) { } void FullNodeShardImpl::send_external_message(td::BufferSlice data) { + if (!client_.empty()) { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "send_ext_query", + create_serialize_tl_object_suffix( + create_serialize_tl_object( + create_tl_object(std::move(data)))), + td::Timestamp::in(1.0), [](td::Result R) { + if (R.is_error()) { + VLOG(FULL_NODE_WARNING) << "failed to send ext message: " << R.move_as_error(); + } + }); + return; + } auto B = create_serialize_tl_object( create_tl_object(std::move(data))); if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) { @@ -470,6 +487,10 @@ void FullNodeShardImpl::send_external_message(td::BufferSlice data) { } void FullNodeShardImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) { + if (!client_.empty()) { + UNREACHABLE(); + return; + } auto B = create_serialize_tl_object( create_tl_object(create_tl_block_id(block_id), cc_seqno, std::move(data))); if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) { @@ -482,6 +503,10 @@ void FullNodeShardImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno } void FullNodeShardImpl::send_broadcast(BlockBroadcast broadcast) { + if (!client_.empty()) { + UNREACHABLE(); + return; + } std::vector> sigs; for (auto &sig : broadcast.signatures) { sigs.emplace_back(create_tl_object(sig.node, sig.signature.clone())); @@ -496,7 +521,7 @@ void FullNodeShardImpl::send_broadcast(BlockBroadcast broadcast) { void FullNodeShardImpl::download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout, td::Promise promise) { td::actor::create_actor("downloadreq", id, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(), - priority, timeout, validator_manager_, rldp_, overlays_, adnl_, + priority, timeout, validator_manager_, rldp_, overlays_, adnl_, client_, std::move(promise)) .release(); } @@ -505,7 +530,7 @@ void FullNodeShardImpl::download_zero_state(BlockIdExt id, td::uint32 priority, td::Promise promise) { td::actor::create_actor("downloadstatereq", id, BlockIdExt{}, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_, - overlays_, adnl_, std::move(promise)) + overlays_, adnl_, client_, std::move(promise)) .release(); } @@ -513,7 +538,7 @@ void FullNodeShardImpl::download_persistent_state(BlockIdExt id, BlockIdExt mast td::Timestamp timeout, td::Promise promise) { td::actor::create_actor("downloadstatereq", id, masterchain_block_id, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_, - overlays_, adnl_, std::move(promise)) + overlays_, adnl_, client_, std::move(promise)) .release(); } @@ -521,7 +546,7 @@ void FullNodeShardImpl::download_block_proof(BlockIdExt block_id, td::uint32 pri td::Promise promise) { td::actor::create_actor("downloadproofreq", block_id, false, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_, - overlays_, adnl_, std::move(promise)) + overlays_, adnl_, client_, std::move(promise)) .release(); } @@ -529,14 +554,15 @@ void FullNodeShardImpl::download_block_proof_link(BlockIdExt block_id, td::uint3 td::Promise promise) { td::actor::create_actor("downloadproofreq", block_id, true, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_, - overlays_, adnl_, std::move(promise)) + overlays_, adnl_, client_, std::move(promise)) .release(); } void FullNodeShardImpl::get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout, td::Promise> promise) { td::actor::create_actor("next", block_id, 16, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(), - 1, timeout, validator_manager_, rldp_, overlays_, adnl_, std::move(promise)) + 1, timeout, validator_manager_, rldp_, overlays_, adnl_, client_, + std::move(promise)) .release(); } @@ -570,15 +596,17 @@ void FullNodeShardImpl::alarm() { } void FullNodeShardImpl::start_up() { - auto X = - create_hash_tl_object(get_workchain(), get_shard(), zero_state_file_hash_); - td::BufferSlice b{32}; - b.as_slice().copy_from(as_slice(X)); - overlay_id_full_ = overlay::OverlayIdFull{std::move(b)}; - overlay_id_ = overlay_id_full_.compute_short_id(); - rules_ = overlay::OverlayPrivacyRules{overlay::Overlays::max_fec_broadcast_size()}; + if (client_.empty()) { + auto X = create_hash_tl_object(get_workchain(), get_shard(), + zero_state_file_hash_); + td::BufferSlice b{32}; + b.as_slice().copy_from(as_slice(X)); + overlay_id_full_ = overlay::OverlayIdFull{std::move(b)}; + overlay_id_ = overlay_id_full_.compute_short_id(); + rules_ = overlay::OverlayPrivacyRules{overlay::Overlays::max_fec_broadcast_size()}; - create_overlay(); + create_overlay(); + } } void FullNodeShardImpl::sign_new_certificate(PublicKeyHash sign_by) { @@ -613,6 +641,9 @@ void FullNodeShardImpl::signed_new_certificate(ton::overlay::Certificate cert) { } void FullNodeShardImpl::update_validators(std::vector public_key_hashes, PublicKeyHash local_hash) { + if (!client_.empty()) { + return; + } bool update_cert = false; if (!local_hash.is_zero() && local_hash != sign_cert_by_) { update_cert = true; @@ -638,7 +669,8 @@ FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id, FileHash zero_state_file_hash, td::actor::ActorId keyring, td::actor::ActorId adnl, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId validator_manager) + td::actor::ActorId validator_manager, + td::actor::ActorId client) : shard_(shard) , local_id_(local_id) , adnl_id_(adnl_id) @@ -647,16 +679,17 @@ FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id, , adnl_(adnl) , rldp_(rldp) , overlays_(overlays) - , validator_manager_(validator_manager) { + , validator_manager_(validator_manager) + , client_(client) { } td::actor::ActorOwn FullNodeShard::create( ShardIdFull shard, PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash, td::actor::ActorId keyring, td::actor::ActorId adnl, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId validator_manager) { + td::actor::ActorId validator_manager, td::actor::ActorId client) { return td::actor::create_actor("tonnode", shard, local_id, adnl_id, zero_state_file_hash, keyring, - adnl, rldp, overlays, validator_manager); + adnl, rldp, overlays, validator_manager, client); } } // namespace fullnode diff --git a/validator/full-node-shard.h b/validator/full-node-shard.h index 55928a0..4527e81 100644 --- a/validator/full-node-shard.h +++ b/validator/full-node-shard.h @@ -20,6 +20,7 @@ #include "full-node.h" #include "validator/interfaces/block-handle.h" +#include "adnl/adnl-ext-client.h" namespace ton { @@ -59,13 +60,11 @@ class FullNodeShard : public td::actor::Actor { virtual void update_validators(std::vector public_key_hashes, PublicKeyHash local_hash) = 0; - static td::actor::ActorOwn create(ShardIdFull shard, PublicKeyHash local_id, - adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash, - td::actor::ActorId keyring, - td::actor::ActorId adnl, - td::actor::ActorId rldp, - td::actor::ActorId overlays, - td::actor::ActorId validator_manager); + static td::actor::ActorOwn create( + ShardIdFull shard, PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash, + td::actor::ActorId keyring, td::actor::ActorId adnl, + td::actor::ActorId rldp, td::actor::ActorId overlays, + td::actor::ActorId validator_manager, td::actor::ActorId client); }; } // namespace fullnode diff --git a/validator/full-node-shard.hpp b/validator/full-node-shard.hpp index 836a0d5..20e96a3 100644 --- a/validator/full-node-shard.hpp +++ b/validator/full-node-shard.hpp @@ -54,7 +54,7 @@ class FullNodeShardImpl : public FullNodeShard { template void process_query(adnl::AdnlNodeIdShort src, T &query, td::Promise promise) { - UNREACHABLE(); + promise.set_error(td::Status::Error(ErrorCode::error, "unknown query")); } void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextBlockDescription &query, td::Promise promise); @@ -122,7 +122,8 @@ class FullNodeShardImpl : public FullNodeShard { FileHash zero_state_file_hash, td::actor::ActorId keyring, td::actor::ActorId adnl, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId validator_manager); + td::actor::ActorId validator_manager, + td::actor::ActorId client); private: ShardIdFull shard_; @@ -138,6 +139,7 @@ class FullNodeShardImpl : public FullNodeShard { td::actor::ActorId rldp_; td::actor::ActorId overlays_; td::actor::ActorId validator_manager_; + td::actor::ActorId client_; td::uint32 attempt_ = 0; diff --git a/validator/full-node.cpp b/validator/full-node.cpp index e9c55ca..9204046 100644 --- a/validator/full-node.cpp +++ b/validator/full-node.cpp @@ -103,7 +103,7 @@ void FullNodeImpl::add_shard(ShardIdFull shard) { while (true) { if (shards_.count(shard) == 0) { shards_.emplace(shard, FullNodeShard::create(shard, local_id_, adnl_id_, zero_state_file_hash_, keyring_, adnl_, - rldp_, overlays_, validator_manager_)); + rldp_, overlays_, validator_manager_, client_)); if (all_validators_.size() > 0) { td::actor::send_closure(shards_[shard], &FullNodeShard::update_validators, all_validators_, sign_cert_by_); } @@ -413,7 +413,8 @@ FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id td::actor::ActorId keyring, td::actor::ActorId adnl, td::actor::ActorId rldp, td::actor::ActorId dht, td::actor::ActorId overlays, - td::actor::ActorId validator_manager, std::string db_root) + td::actor::ActorId validator_manager, + td::actor::ActorId client, std::string db_root) : local_id_(local_id) , adnl_id_(adnl_id) , zero_state_file_hash_(zero_state_file_hash) @@ -423,6 +424,7 @@ FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id , dht_(dht) , overlays_(overlays) , validator_manager_(validator_manager) + , client_(client) , db_root_(db_root) { add_shard(ShardIdFull{masterchainId}); } @@ -434,9 +436,9 @@ td::actor::ActorOwn FullNode::create(ton::PublicKeyHash local_id, adnl td::actor::ActorId dht, td::actor::ActorId overlays, td::actor::ActorId validator_manager, - std::string db_root) { + td::actor::ActorId client, std::string db_root) { return td::actor::create_actor("fullnode", local_id, adnl_id, zero_state_file_hash, keyring, adnl, rldp, - dht, overlays, validator_manager, db_root); + dht, overlays, validator_manager, client, db_root); } } // namespace fullnode diff --git a/validator/full-node.h b/validator/full-node.h index fd3d2d1..1323974 100644 --- a/validator/full-node.h +++ b/validator/full-node.h @@ -30,6 +30,7 @@ #include "dht/dht.h" #include "overlay/overlays.h" #include "validator/validator.h" +#include "adnl/adnl-ext-client.h" namespace ton { @@ -71,7 +72,7 @@ class FullNode : public td::actor::Actor { td::actor::ActorId dht, td::actor::ActorId overlays, td::actor::ActorId validator_manager, - std::string db_root); + td::actor::ActorId client, std::string db_root); }; } // namespace fullnode diff --git a/validator/full-node.hpp b/validator/full-node.hpp index e597d81..8d08f6c 100644 --- a/validator/full-node.hpp +++ b/validator/full-node.hpp @@ -75,7 +75,8 @@ class FullNodeImpl : public FullNode { td::actor::ActorId keyring, td::actor::ActorId adnl, td::actor::ActorId rldp, td::actor::ActorId dht, td::actor::ActorId overlays, - td::actor::ActorId validator_manager, std::string db_root); + td::actor::ActorId validator_manager, + td::actor::ActorId client, std::string db_root); private: PublicKeyHash local_id_; @@ -93,6 +94,7 @@ class FullNodeImpl : public FullNode { td::actor::ActorId dht_; td::actor::ActorId overlays_; td::actor::ActorId validator_manager_; + td::actor::ActorId client_; std::string db_root_; diff --git a/validator/impl/collator.cpp b/validator/impl/collator.cpp index 77e0c26..f6739bf 100644 --- a/validator/impl/collator.cpp +++ b/validator/impl/collator.cpp @@ -74,10 +74,6 @@ void Collator::start_up() { if (prev_blocks.size() > 1) { LOG(DEBUG) << "Previous block #2 is " << prev_blocks.at(1).to_str(); } - //if (created_by_.is_zero()) { - // !!FIXME!! remove this debug later - //td::as(created_by_.data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8); - //} // 1. check validity of parameters, especially prev_blocks, shard and min_mc_block_id if (shard.workchain != ton::masterchainId && shard.workchain != ton::basechainId) { fatal_error(-667, "can create block candidates only for masterchain (-1) and base workchain (0)"); @@ -180,7 +176,7 @@ void Collator::start_up() { LOG(DEBUG) << "sending wait_block_state() query #" << i << " for " << prev_blocks[i].to_str() << " to Manager"; ++pending; td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, prev_blocks[i], priority(), - timeout, [self = get_self(), i](td::Result> res) { + timeout, [ self = get_self(), i ](td::Result> res) { LOG(DEBUG) << "got answer to wait_block_state query #" << i; td::actor::send_closure_later(std::move(self), &Collator::after_get_shard_state, i, std::move(res)); @@ -191,7 +187,7 @@ void Collator::start_up() { LOG(DEBUG) << "sending wait_block_data() query #" << i << " for " << prev_blocks[i].to_str() << " to Manager"; ++pending; td::actor::send_closure_later(manager, &ValidatorManager::wait_block_data_short, prev_blocks[i], priority(), - timeout, [self = get_self(), i](td::Result> res) { + timeout, [ self = get_self(), i ](td::Result> res) { LOG(DEBUG) << "got answer to wait_block_data query #" << i; td::actor::send_closure_later(std::move(self), &Collator::after_get_block_data, i, std::move(res)); @@ -201,8 +197,8 @@ void Collator::start_up() { // 4. load external messages LOG(DEBUG) << "sending get_external_messages() query to Manager"; ++pending; - td::actor::send_closure_later(manager, &ValidatorManager::get_external_messages, shard, - [self = get_self()](td::Result>> res) -> void { + td::actor::send_closure_later(manager, &ValidatorManager::get_external_messages, + shard, [self = get_self()](td::Result>> res)->void { LOG(DEBUG) << "got answer to get_external_messages() query"; td::actor::send_closure_later(std::move(self), &Collator::after_get_external_messages, std::move(res)); @@ -212,8 +208,8 @@ void Collator::start_up() { LOG(DEBUG) << "sending get_shard_blocks() query to Manager"; ++pending; td::actor::send_closure_later( - manager, &ValidatorManager::get_shard_blocks, prev_blocks[0], - [self = get_self()](td::Result>> res) -> void { + manager, &ValidatorManager::get_shard_blocks, + prev_blocks[0], [self = get_self()](td::Result>> res)->void { LOG(DEBUG) << "got answer to get_shard_blocks() query"; td::actor::send_closure_later(std::move(self), &Collator::after_get_shard_blocks, std::move(res)); }); @@ -330,7 +326,7 @@ bool Collator::request_aux_mc_state(BlockSeqno seqno, Ref& st LOG(DEBUG) << "sending auxiliary wait_block_state() query for " << blkid.to_str() << " to Manager"; ++pending; td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, blkid, priority(), timeout, - [self = get_self(), blkid](td::Result> res) { + [ self = get_self(), blkid ](td::Result> res) { LOG(DEBUG) << "got answer to wait_block_state query for " << blkid.to_str(); td::actor::send_closure_later(std::move(self), &Collator::after_get_aux_shard_state, blkid, std::move(res)); @@ -418,8 +414,8 @@ void Collator::after_get_mc_state(td::Result, Bl // NB. it is needed only for creating a correct ExtBlkRef reference to it, which requires start_lt and end_lt LOG(DEBUG) << "sending wait_block_data() query #-1 for " << mc_block_id_.to_str() << " to Manager"; ++pending; - td::actor::send_closure_later(manager, &ValidatorManager::wait_block_data_short, mc_block_id_, priority(), timeout, - [self = get_self()](td::Result> res) { + td::actor::send_closure_later(manager, &ValidatorManager::wait_block_data_short, mc_block_id_, priority(), + timeout, [self = get_self()](td::Result> res) { LOG(DEBUG) << "got answer to wait_block_data query #-1"; td::actor::send_closure_later(std::move(self), &Collator::after_get_block_data, -1, std::move(res)); @@ -558,7 +554,7 @@ bool Collator::request_neighbor_msg_queues() { LOG(DEBUG) << "neighbor #" << i << " : " << descr.blk_.to_str(); ++pending; send_closure_later(manager, &ValidatorManager::wait_block_message_queue_short, descr.blk_, priority(), timeout, - [self = get_self(), i](td::Result> res) { + [ self = get_self(), i ](td::Result> res) { td::actor::send_closure(std::move(self), &Collator::got_neighbor_out_queue, i, std::move(res)); }); ++i; @@ -2936,24 +2932,24 @@ bool Collator::update_shard_config(const block::WorkchainSet& wc_set, const bloc WorkchainId wc_id{ton::workchainInvalid}; Ref wc_info; ton::BlockSeqno& min_seqno = min_ref_mc_seqno_; - return shard_conf_->process_sibling_shard_hashes( - [&wc_set, &wc_id, &wc_info, &ccvc, &min_seqno, now = now_, update_cc](block::McShardHash& cur, - const block::McShardHash* sibling) { - if (!cur.is_valid()) { - return -2; - } - if (wc_id != cur.workchain()) { - wc_id = cur.workchain(); - auto it = wc_set.find(wc_id); - if (it == wc_set.end()) { - wc_info.clear(); - } else { - wc_info = it->second; - } - } - min_seqno = std::min(min_seqno, cur.min_ref_mc_seqno_); - return update_one_shard(cur, sibling, wc_info.get(), now, ccvc, update_cc); - }); + return shard_conf_->process_sibling_shard_hashes([ + &wc_set, &wc_id, &wc_info, &ccvc, &min_seqno, now = now_, update_cc + ](block::McShardHash & cur, const block::McShardHash* sibling) { + if (!cur.is_valid()) { + return -2; + } + if (wc_id != cur.workchain()) { + wc_id = cur.workchain(); + auto it = wc_set.find(wc_id); + if (it == wc_set.end()) { + wc_info.clear(); + } else { + wc_info = it->second; + } + } + min_seqno = std::min(min_seqno, cur.min_ref_mc_seqno_); + return update_one_shard(cur, sibling, wc_info.get(), now, ccvc, update_cc); + }); } bool Collator::create_mc_state_extra() { @@ -3198,10 +3194,10 @@ bool Collator::update_block_creator_stats() { return fatal_error("cannot update CreatorStats for "s + p.first.to_hex()); } } - if (/*!created_by_.is_zero() &&*/ !update_block_creator_count(created_by_.as_bits256().bits(), 0, 1)) { + if (!created_by_.is_zero() && !update_block_creator_count(created_by_.as_bits256().bits(), 0, 1)) { return fatal_error("cannot update CreatorStats for "s + created_by_.as_bits256().to_hex()); } - if (!update_block_creator_count(td::Bits256::zero().bits(), block_create_total_, 1)) { + if (!update_block_creator_count(td::Bits256::zero().bits(), block_create_total_, !created_by_.is_zero())) { return fatal_error("cannot update CreatorStats with zero index (representing the sum of other CreatorStats)"); } int cnt = block_create_stats_->filter([this](vm::CellSlice& cs, td::ConstBitPtr key, int key_len) { @@ -3766,7 +3762,7 @@ bool Collator::create_block_candidate() { // 4. save block candidate LOG(INFO) << "saving new BlockCandidate"; td::actor::send_closure_later(manager, &ValidatorManager::set_block_candidate, block_candidate->id, - block_candidate->clone(), [self = get_self()](td::Result saved) -> void { + block_candidate->clone(), [self = get_self()](td::Result saved)->void { LOG(DEBUG) << "got answer to set_block_candidate"; td::actor::send_closure_later(std::move(self), &Collator::return_block_candidate, std::move(saved)); diff --git a/validator/impl/validate-query.cpp b/validator/impl/validate-query.cpp index 7f13b27..3b574cd 100644 --- a/validator/impl/validate-query.cpp +++ b/validator/impl/validate-query.cpp @@ -151,12 +151,7 @@ void ValidateQuery::start_up() { LOG(INFO) << "validate query for " << block_candidate.id.to_str() << " started"; alarm_timestamp() = timeout; rand_seed_.set_zero(); - created_by_ = block_candidate.pubkey; - if (created_by_.is_zero()) { - // !!FIXME!! remove this debug later - td::as(created_by_.data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8); - } CHECK(id_ == block_candidate.id); if (ShardIdFull(id_) != shard_) { @@ -5179,7 +5174,7 @@ bool ValidateQuery::check_one_block_creator_update(td::ConstBitPtr key, Refallow_blockchain_init()) { download_new_key_blocks_until_ = td::Timestamp::in(60.0); @@ -115,15 +115,18 @@ void ValidatorManagerMasterchainReiniter::try_download_key_blocks() { download_new_key_blocks_until_ = td::Timestamp::in(600.0); } } - if (key_blocks_.size() > 0) { + if (key_blocks_.size() > 0 && try_start) { auto h = *key_blocks_.rbegin(); CHECK(h->inited_unix_time()); if (h->unix_time() + opts_->sync_blocks_before() > td::Clocks::system()) { choose_masterchain_state(); return; } - if ((opts_->allow_blockchain_init() || h->unix_time() + 2 * 86400 > td::Clocks::system()) && - download_new_key_blocks_until_.is_in_past()) { + if (h->unix_time() + 2 * opts_->key_block_utime_step() > td::Clocks::system()) { + choose_masterchain_state(); + return; + } + if (opts_->allow_blockchain_init() && download_new_key_blocks_until_.is_in_past()) { choose_masterchain_state(); return; } @@ -146,7 +149,7 @@ void ValidatorManagerMasterchainReiniter::got_next_key_blocks(std::vector 0); if (!--pending_) { - try_download_key_blocks(); + try_download_key_blocks(false); } } diff --git a/validator/manager-init.hpp b/validator/manager-init.hpp index 40004e8..3004134 100644 --- a/validator/manager-init.hpp +++ b/validator/manager-init.hpp @@ -45,7 +45,7 @@ class ValidatorManagerMasterchainReiniter : public td::actor::Actor { void downloaded_proof_link(td::BufferSlice data); void downloaded_zero_state(); - void try_download_key_blocks(); + void try_download_key_blocks(bool try_start); void got_next_key_blocks(std::vector vec); void got_key_block_handle(td::uint32 idx, BlockHandle handle); diff --git a/validator/net/download-block.cpp b/validator/net/download-block.cpp index db0ee92..60155dc 100644 --- a/validator/net/download-block.cpp +++ b/validator/net/download-block.cpp @@ -34,7 +34,8 @@ DownloadBlock::DownloadBlock(BlockIdExt block_id, adnl::AdnlNodeIdShort local_id adnl::AdnlNodeIdShort download_from, td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise promise) + td::actor::ActorId adnl, td::actor::ActorId client, + td::Promise promise) : block_id_(block_id) , local_id_(local_id) , overlay_id_(overlay_id) @@ -45,6 +46,7 @@ DownloadBlock::DownloadBlock(BlockIdExt block_id, adnl::AdnlNodeIdShort local_id , rldp_(rldp) , overlays_(overlays) , adnl_(adnl) + , client_(client) , promise_(std::move(promise)) , block_{block_id, td::BufferSlice()} , allow_partial_proof_{!block_id_.is_masterchain()} { @@ -54,7 +56,8 @@ DownloadBlock::DownloadBlock(BlockIdExt block_id, adnl::AdnlNodeIdShort local_id BlockHandle prev, adnl::AdnlNodeIdShort download_from, td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise promise) + td::actor::ActorId adnl, td::actor::ActorId client, + td::Promise promise) : block_id_(block_id) , local_id_(local_id) , overlay_id_(overlay_id) @@ -66,6 +69,7 @@ DownloadBlock::DownloadBlock(BlockIdExt block_id, adnl::AdnlNodeIdShort local_id , rldp_(rldp) , overlays_(overlays) , adnl_(adnl) + , client_(client) , promise_(std::move(promise)) , block_{block_id, td::BufferSlice()} { } @@ -139,7 +143,7 @@ void DownloadBlock::got_block_handle(BlockHandle handle) { void DownloadBlock::got_download_token(std::unique_ptr token) { token_ = std::move(token); - if (download_from_.is_zero() && !short_) { + if (download_from_.is_zero() && !short_ && client_.empty()) { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result> R) { if (R.is_error()) { td::actor::send_closure(SelfId, &DownloadBlock::abort_query, R.move_as_error()); @@ -179,10 +183,16 @@ void DownloadBlock::got_node_to_download(adnl::AdnlNodeIdShort node) { } }); - td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, - "get_prepare", std::move(P), td::Timestamp::in(1.0), - create_serialize_tl_object(create_tl_block_id(block_id_), - allow_partial_proof_)); + auto q = create_serialize_tl_object(create_tl_block_id(block_id_), + allow_partial_proof_); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, + "get_prepare", std::move(P), td::Timestamp::in(1.0), std::move(q)); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare", + create_serialize_tl_object_suffix(std::move(q)), + td::Timestamp::in(1.0), std::move(P)); + } } void DownloadBlock::got_block_proof_description(td::BufferSlice proof_description) { @@ -207,11 +217,16 @@ void DownloadBlock::got_block_proof_description(td::BufferSlice proof_descriptio } }); - td::actor::send_closure( - overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_, - "download block proof", std::move(P), td::Timestamp::in(3.0), - create_serialize_tl_object(create_tl_block_id(block_id_)), - FullNode::max_proof_size(), rldp_); + auto q = create_serialize_tl_object(create_tl_block_id(block_id_)); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, + overlay_id_, "get_proof", std::move(P), td::Timestamp::in(3.0), std::move(q), + FullNode::max_proof_size(), rldp_); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_proof", + create_serialize_tl_object_suffix(std::move(q)), + td::Timestamp::in(3.0), std::move(P)); + } }, [&](ton_api::tonNode_preparedProofLink &obj) { if (!allow_partial_proof_) { @@ -226,11 +241,16 @@ void DownloadBlock::got_block_proof_description(td::BufferSlice proof_descriptio } }); - td::actor::send_closure( - overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_, - "download block proof link", std::move(P), td::Timestamp::in(3.0), - create_serialize_tl_object(create_tl_block_id(block_id_)), - FullNode::max_proof_size(), rldp_); + auto q = create_serialize_tl_object(create_tl_block_id(block_id_)); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, + overlay_id_, "get_proof_link", std::move(P), td::Timestamp::in(3.0), std::move(q), + FullNode::max_proof_size(), rldp_); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_proof_link", + create_serialize_tl_object_suffix(std::move(q)), + td::Timestamp::in(3.0), std::move(P)); + } }, [&](ton_api::tonNode_preparedProofEmpty &obj) { abort_query(td::Status::Error(ErrorCode::notready, "proof not found")); @@ -317,9 +337,15 @@ void DownloadBlock::got_block_handle_2(BlockHandle handle) { } }); - td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, - "get_prepare", std::move(P), td::Timestamp::in(1.0), - create_serialize_tl_object(create_tl_block_id(block_id_))); + auto q = create_serialize_tl_object(create_tl_block_id(block_id_)); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, + "get_prepare_block", std::move(P), td::Timestamp::in(1.0), std::move(q)); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare_block", + create_serialize_tl_object_suffix(std::move(q)), + td::Timestamp::in(1.0), std::move(P)); + } } } @@ -333,25 +359,31 @@ void DownloadBlock::got_block_data_description(td::BufferSlice data_description) auto f = F.move_as_ok(); ton_api::downcast_call( - *f.get(), td::overloaded( - [&, self = this](ton_api::tonNode_prepared &val) { - auto P = td::PromiseCreator::lambda([SelfId = actor_id(self)](td::Result R) { - if (R.is_error()) { - td::actor::send_closure(SelfId, &DownloadBlock::abort_query, R.move_as_error()); - } else { - td::actor::send_closure(SelfId, &DownloadBlock::got_block_data, R.move_as_ok()); - } - }); + *f.get(), + td::overloaded( + [&, self = this](ton_api::tonNode_prepared &val) { + auto P = td::PromiseCreator::lambda([SelfId = actor_id(self)](td::Result R) { + if (R.is_error()) { + td::actor::send_closure(SelfId, &DownloadBlock::abort_query, R.move_as_error()); + } else { + td::actor::send_closure(SelfId, &DownloadBlock::got_block_data, R.move_as_ok()); + } + }); - td::actor::send_closure( - overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_, - "download block", std::move(P), td::Timestamp::in(3.0), - create_serialize_tl_object(create_tl_block_id(block_id_)), - FullNode::max_block_size(), rldp_); - }, - [&](ton_api::tonNode_notFound &val) { - abort_query(td::Status::Error(ErrorCode::notready, "dst node does not have block")); - })); + auto q = create_serialize_tl_object(create_tl_block_id(block_id_)); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, + overlay_id_, "get_block", std::move(P), td::Timestamp::in(3.0), std::move(q), + FullNode::max_block_size(), rldp_); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_block", + create_serialize_tl_object_suffix(std::move(q)), + td::Timestamp::in(3.0), std::move(P)); + } + }, + [&](ton_api::tonNode_notFound &val) { + abort_query(td::Status::Error(ErrorCode::notready, "dst node does not have block")); + })); } void DownloadBlock::got_block_data(td::BufferSlice data) { diff --git a/validator/net/download-block.hpp b/validator/net/download-block.hpp index 4d5165a..54a5a6c 100644 --- a/validator/net/download-block.hpp +++ b/validator/net/download-block.hpp @@ -22,6 +22,7 @@ #include "ton/ton-types.h" #include "validator/validator.h" #include "rldp/rldp.h" +#include "adnl/adnl-ext-client.h" namespace ton { @@ -35,12 +36,12 @@ class DownloadBlock : public td::actor::Actor { adnl::AdnlNodeIdShort download_from, td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, td::actor::ActorId adnl, - td::Promise promise); + td::actor::ActorId client, td::Promise promise); DownloadBlock(BlockIdExt block_id, adnl::AdnlNodeIdShort local_id, overlay::OverlayIdShort overlay_id, BlockHandle prev, adnl::AdnlNodeIdShort download_from, td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, td::actor::ActorId adnl, - td::Promise promise); + td::actor::ActorId client, td::Promise promise); void abort_query(td::Status reason); void alarm() override; @@ -75,6 +76,7 @@ class DownloadBlock : public td::actor::Actor { td::actor::ActorId rldp_; td::actor::ActorId overlays_; td::actor::ActorId adnl_; + td::actor::ActorId client_; td::Promise promise_; BlockHandle handle_; diff --git a/validator/net/download-next-block.cpp b/validator/net/download-next-block.cpp index a745068..2512e82 100644 --- a/validator/net/download-next-block.cpp +++ b/validator/net/download-next-block.cpp @@ -33,7 +33,8 @@ DownloadNextBlock::DownloadNextBlock(adnl::AdnlNodeIdShort local_id, overlay::Ov td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise promise) + td::actor::ActorId adnl, + td::actor::ActorId client, td::Promise promise) : local_id_(local_id) , overlay_id_(overlay_id) , prev_(prev) @@ -43,6 +44,7 @@ DownloadNextBlock::DownloadNextBlock(adnl::AdnlNodeIdShort local_id, overlay::Ov , rldp_(rldp) , overlays_(overlays) , adnl_(adnl) + , client_(client) , promise_(std::move(promise)) { } @@ -76,6 +78,10 @@ void DownloadNextBlock::start_up() { false, std::move(P)); return; } + if (!client_.empty()) { + got_node(node_); + return; + } auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result> R) { if (R.is_error()) { @@ -107,8 +113,14 @@ void DownloadNextBlock::got_node(adnl::AdnlNodeIdShort id) { }); auto query = create_serialize_tl_object(create_tl_block_id(prev_->id())); - td::actor::send_closure(overlays_, &overlay::Overlays::send_query, id, local_id_, overlay_id_, "get_prepare", - std::move(P), td::Timestamp::in(1.0), std::move(query)); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query, id, local_id_, overlay_id_, "get_prepare", + std::move(P), td::Timestamp::in(1.0), std::move(query)); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare", + create_serialize_tl_object_suffix(std::move(query)), + td::Timestamp::in(1.0), std::move(P)); + } } void DownloadNextBlock::got_next_node(td::BufferSlice data) { @@ -138,7 +150,7 @@ void DownloadNextBlock::got_next_node_handle(BlockHandle handle) { void DownloadNextBlock::finish_query() { if (promise_) { td::actor::create_actor("downloadnext", next_block_id_, local_id_, overlay_id_, prev_, node_, - priority_, timeout_, validator_manager_, rldp_, overlays_, adnl_, + priority_, timeout_, validator_manager_, rldp_, overlays_, adnl_, client_, std::move(promise_)) .release(); } diff --git a/validator/net/download-next-block.hpp b/validator/net/download-next-block.hpp index 0f14af9..8dc768b 100644 --- a/validator/net/download-next-block.hpp +++ b/validator/net/download-next-block.hpp @@ -23,6 +23,7 @@ #include "validator/validator.h" #include "rldp/rldp.h" #include "ton/ton-io.hpp" +#include "adnl/adnl-ext-client.h" namespace ton { @@ -36,7 +37,8 @@ class DownloadNextBlock : public td::actor::Actor { td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise promise); + td::actor::ActorId adnl, td::actor::ActorId client, + td::Promise promise); void abort_query(td::Status reason); void finish_query(); @@ -62,6 +64,7 @@ class DownloadNextBlock : public td::actor::Actor { td::actor::ActorId rldp_; td::actor::ActorId overlays_; td::actor::ActorId adnl_; + td::actor::ActorId client_; td::Promise promise_; adnl::AdnlNodeIdShort node_ = adnl::AdnlNodeIdShort::zero(); diff --git a/validator/net/download-proof.cpp b/validator/net/download-proof.cpp index ef9f91a..3fcfd6a 100644 --- a/validator/net/download-proof.cpp +++ b/validator/net/download-proof.cpp @@ -35,7 +35,8 @@ DownloadProof::DownloadProof(BlockIdExt block_id, bool allow_partial_proof, adnl td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise promise) + td::actor::ActorId adnl, td::actor::ActorId client, + td::Promise promise) : block_id_(block_id) , allow_partial_proof_(allow_partial_proof) , local_id_(local_id) @@ -47,6 +48,7 @@ DownloadProof::DownloadProof(BlockIdExt block_id, bool allow_partial_proof, adnl , rldp_(rldp) , overlays_(overlays) , adnl_(adnl) + , client_(client) , promise_(std::move(promise)) { } @@ -92,7 +94,7 @@ void DownloadProof::start_up() { void DownloadProof::got_download_token(std::unique_ptr token) { token_ = std::move(token); - if (download_from_.is_zero()) { + if (download_from_.is_zero() && client_.empty()) { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result> R) { if (R.is_error()) { td::actor::send_closure(SelfId, &DownloadProof::abort_query, R.move_as_error()); @@ -126,10 +128,17 @@ void DownloadProof::got_node_to_download(adnl::AdnlNodeIdShort node) { } }); - td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, - "get_prepare", std::move(P), td::Timestamp::in(1.0), - create_serialize_tl_object(create_tl_block_id(block_id_), - allow_partial_proof_)); + auto query = create_serialize_tl_object(create_tl_block_id(block_id_), + allow_partial_proof_); + + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, + "get_prepare", std::move(P), td::Timestamp::in(1.0), std::move(query)); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare", + create_serialize_tl_object_suffix(std::move(query)), + td::Timestamp::in(1.0), std::move(P)); + } } void DownloadProof::got_block_proof_description(td::BufferSlice proof_description) { @@ -154,11 +163,16 @@ void DownloadProof::got_block_proof_description(td::BufferSlice proof_descriptio } }); - td::actor::send_closure( - overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_, - "download block proof", std::move(P), td::Timestamp::in(3.0), - create_serialize_tl_object(create_tl_block_id(block_id_)), - FullNode::max_proof_size(), rldp_); + auto query = create_serialize_tl_object(create_tl_block_id(block_id_)); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, + overlay_id_, "download block proof", std::move(P), td::Timestamp::in(3.0), + std::move(query), FullNode::max_proof_size(), rldp_); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare", + create_serialize_tl_object_suffix(std::move(query)), + td::Timestamp::in(3.0), std::move(P)); + } }, [&](ton_api::tonNode_preparedProofLink &obj) { if (!allow_partial_proof_) { @@ -173,11 +187,17 @@ void DownloadProof::got_block_proof_description(td::BufferSlice proof_descriptio } }); - td::actor::send_closure( - overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_, - "download block proof link", std::move(P), td::Timestamp::in(3.0), - create_serialize_tl_object(create_tl_block_id(block_id_)), - FullNode::max_proof_size(), rldp_); + auto query = + create_serialize_tl_object(create_tl_block_id(block_id_)); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, + overlay_id_, "download block proof link", std::move(P), td::Timestamp::in(3.0), + std::move(query), FullNode::max_proof_size(), rldp_); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "download block proof link", + create_serialize_tl_object_suffix(std::move(query)), + td::Timestamp::in(3.0), std::move(P)); + } }, [&](ton_api::tonNode_preparedProofEmpty &obj) { abort_query(td::Status::Error(ErrorCode::notready, "proof not found")); diff --git a/validator/net/download-proof.hpp b/validator/net/download-proof.hpp index 0dd9d0f..64ed65b 100644 --- a/validator/net/download-proof.hpp +++ b/validator/net/download-proof.hpp @@ -22,6 +22,7 @@ #include "ton/ton-types.h" #include "validator/validator.h" #include "rldp/rldp.h" +#include "adnl/adnl-ext-client.h" namespace ton { @@ -35,7 +36,8 @@ class DownloadProof : public td::actor::Actor { overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from, td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise promise); + td::actor::ActorId adnl, td::actor::ActorId client, + td::Promise promise); void abort_query(td::Status reason); void alarm() override; @@ -63,6 +65,7 @@ class DownloadProof : public td::actor::Actor { td::actor::ActorId rldp_; td::actor::ActorId overlays_; td::actor::ActorId adnl_; + td::actor::ActorId client_; td::Promise promise_; td::BufferSlice data_; diff --git a/validator/net/download-state.cpp b/validator/net/download-state.cpp index 09bbf3e..17a684b 100644 --- a/validator/net/download-state.cpp +++ b/validator/net/download-state.cpp @@ -33,7 +33,8 @@ DownloadState::DownloadState(BlockIdExt block_id, BlockIdExt masterchain_block_i td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise promise) + td::actor::ActorId adnl, td::actor::ActorId client, + td::Promise promise) : block_id_(block_id) , masterchain_block_id_(masterchain_block_id) , local_id_(local_id) @@ -45,6 +46,7 @@ DownloadState::DownloadState(BlockIdExt block_id, BlockIdExt masterchain_block_i , rldp_(rldp) , overlays_(overlays) , adnl_(adnl) + , client_(client) , promise_(std::move(promise)) { } @@ -89,7 +91,7 @@ void DownloadState::start_up() { void DownloadState::got_block_handle(BlockHandle handle) { handle_ = std::move(handle); - if (!download_from_.is_zero()) { + if (!download_from_.is_zero() || !client_.empty()) { got_node_to_download(download_from_); } else { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result> R) { @@ -130,8 +132,14 @@ void DownloadState::got_node_to_download(adnl::AdnlNodeIdShort node) { query = create_serialize_tl_object(create_tl_block_id(block_id_)); } - td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, - "get_prepare", std::move(P), td::Timestamp::in(1.0), std::move(query)); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, + "get_prepare", std::move(P), td::Timestamp::in(1.0), std::move(query)); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare", + create_serialize_tl_object_suffix(std::move(query)), + td::Timestamp::in(1.0), std::move(P)); + } } void DownloadState::got_block_state_description(td::BufferSlice data) { @@ -162,9 +170,15 @@ void DownloadState::got_block_state_description(td::BufferSlice data) { td::BufferSlice query = create_serialize_tl_object(create_tl_block_id(block_id_)); - td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, - overlay_id_, "download state", std::move(P), timeout_, std::move(query), - FullNode::max_state_size(), rldp_); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, + overlay_id_, "download state", std::move(P), timeout_, std::move(query), + FullNode::max_state_size(), rldp_); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "download state", + create_serialize_tl_object_suffix(std::move(query)), + timeout_, std::move(P)); + } })); } @@ -197,9 +211,15 @@ void DownloadState::got_block_state_part(td::BufferSlice data, td::uint32 reques td::BufferSlice query = create_serialize_tl_object( create_tl_block_id(block_id_), create_tl_block_id(masterchain_block_id_), sum_, part_size); - td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_, - "download state", std::move(P), timeout_, std::move(query), FullNode::max_state_size(), - rldp_); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_, + "download state", std::move(P), timeout_, std::move(query), FullNode::max_state_size(), + rldp_); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "download state", + create_serialize_tl_object_suffix(std::move(query)), timeout_, + std::move(P)); + } } void DownloadState::got_block_state(td::BufferSlice data) { diff --git a/validator/net/download-state.hpp b/validator/net/download-state.hpp index 9b5e47a..a12f357 100644 --- a/validator/net/download-state.hpp +++ b/validator/net/download-state.hpp @@ -22,6 +22,7 @@ #include "ton/ton-types.h" #include "validator/validator.h" #include "rldp/rldp.h" +#include "adnl/adnl-ext-client.h" namespace ton { @@ -35,7 +36,8 @@ class DownloadState : public td::actor::Actor { overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from, td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise promise); + td::actor::ActorId adnl, td::actor::ActorId client, + td::Promise promise); void abort_query(td::Status reason); void alarm() override; @@ -63,6 +65,7 @@ class DownloadState : public td::actor::Actor { td::actor::ActorId rldp_; td::actor::ActorId overlays_; td::actor::ActorId adnl_; + td::actor::ActorId client_; td::Promise promise_; BlockHandle handle_; diff --git a/validator/net/get-next-key-blocks.cpp b/validator/net/get-next-key-blocks.cpp index 8323f14..02c3a66 100644 --- a/validator/net/get-next-key-blocks.cpp +++ b/validator/net/get-next-key-blocks.cpp @@ -36,7 +36,8 @@ GetNextKeyBlocks::GetNextKeyBlocks(BlockIdExt block_id, td::uint32 limit, adnl:: td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise> promise) + td::actor::ActorId adnl, td::actor::ActorId client, + td::Promise> promise) : block_id_(block_id) , limit_(limit) , local_id_(local_id) @@ -48,6 +49,7 @@ GetNextKeyBlocks::GetNextKeyBlocks(BlockIdExt block_id, td::uint32 limit, adnl:: , rldp_(rldp) , overlays_(overlays) , adnl_(adnl) + , client_(client) , promise_(std::move(promise)) { } @@ -97,7 +99,7 @@ void GetNextKeyBlocks::start_up() { void GetNextKeyBlocks::got_download_token(std::unique_ptr token) { token_ = std::move(token); - if (download_from_.is_zero()) { + if (download_from_.is_zero() && client_.empty()) { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result> R) { if (R.is_error()) { td::actor::send_closure(SelfId, &GetNextKeyBlocks::abort_query, R.move_as_error()); @@ -130,11 +132,15 @@ void GetNextKeyBlocks::got_node_to_download(adnl::AdnlNodeIdShort node) { td::actor::send_closure(SelfId, &GetNextKeyBlocks::got_result, R.move_as_ok()); } }); - - td::actor::send_closure( - overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, "get_prepare", std::move(P), - td::Timestamp::in(1.0), - create_serialize_tl_object(create_tl_block_id(block_id_), limit_)); + auto query = create_serialize_tl_object(create_tl_block_id(block_id_), limit_); + if (client_.empty()) { + td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, + "get_prepare", std::move(P), td::Timestamp::in(1.0), std::move(query)); + } else { + td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare", + create_serialize_tl_object_suffix(std::move(query)), + td::Timestamp::in(1.0), std::move(P)); + } } void GetNextKeyBlocks::got_result(td::BufferSlice data) { @@ -173,7 +179,8 @@ void GetNextKeyBlocks::download_next_proof() { }); td::actor::create_actor("downloadproofreq", block_id, false, local_id_, overlay_id_, download_from_, - priority_, timeout_, validator_manager_, rldp_, overlays_, adnl_, std::move(P)) + priority_, timeout_, validator_manager_, rldp_, overlays_, adnl_, client_, + std::move(P)) .release(); } diff --git a/validator/net/get-next-key-blocks.hpp b/validator/net/get-next-key-blocks.hpp index a06756f..12f7ad3 100644 --- a/validator/net/get-next-key-blocks.hpp +++ b/validator/net/get-next-key-blocks.hpp @@ -22,6 +22,7 @@ #include "ton/ton-types.h" #include "validator/validator.h" #include "rldp/rldp.h" +#include "adnl/adnl-ext-client.h" namespace ton { @@ -35,7 +36,8 @@ class GetNextKeyBlocks : public td::actor::Actor { overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from, td::uint32 priority, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, - td::actor::ActorId adnl, td::Promise> promise); + td::actor::ActorId adnl, td::actor::ActorId client, + td::Promise> promise); void abort_query(td::Status reason); void alarm() override; @@ -67,6 +69,7 @@ class GetNextKeyBlocks : public td::actor::Actor { td::actor::ActorId rldp_; td::actor::ActorId overlays_; td::actor::ActorId adnl_; + td::actor::ActorId client_; td::Promise> promise_; std::vector pending_; diff --git a/validator/validator.h b/validator/validator.h index 299e04e..70b01e6 100644 --- a/validator/validator.h +++ b/validator/validator.h @@ -59,6 +59,9 @@ struct ValidatorManagerOptions : public td::CntObject { virtual bool is_hardfork(BlockIdExt block_id) const = 0; virtual td::uint32 get_vertical_height(BlockSeqno seqno) const = 0; virtual td::uint32 get_filedb_depth() const = 0; + virtual td::uint32 key_block_utime_step() const { + return 86400; + } virtual void set_zero_block_id(BlockIdExt block_id) = 0; virtual void set_init_block_id(BlockIdExt block_id) = 0;