mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Merge remote-tracking branch 'origin/testnet' into testnet
This commit is contained in:
commit
c5a1234ebc
53 changed files with 1146 additions and 259 deletions
14
Changelog.md
14
Changelog.md
|
@ -1,3 +1,17 @@
|
||||||
|
## 2024.12 Update
|
||||||
|
|
||||||
|
1. FunC 0.4.6: Fix in try/catch handling, fixing pure flag for functions stored in variables
|
||||||
|
2. Merging parts of Accelerator: support of specific shard monitoring, archive/liteserver slice format, support for partial liteservers, proxy liteserver, on-demand neighbour queue loading
|
||||||
|
3. Fix of asynchronous cell loading
|
||||||
|
4. Various improvements: caching certificates checks, better block overloading detection, `_malloc` in emulator
|
||||||
|
5. Introduction of telemetry in overlays
|
||||||
|
6. Use non-null local-id for tonlib-LS interaction - mitigates MitM attack.
|
||||||
|
7. Adding `SECP256K1_XONLY_PUBKEY_TWEAK_ADD`, `SETCONTCTRMANY` instructions to TVM (activated by `Config8.version >= 9`)
|
||||||
|
8. Private keys export via validator-engine-console - required for better backups
|
||||||
|
9. Fix proof checking in tonlib, `hash` in `raw.Message` in tonlib_api
|
||||||
|
|
||||||
|
Besides the work of the core team, this update is based on the efforts of OtterSec and LayerZero (FunC), tg:@throwunless (FunC), Aviv Frenkel and Dima Kogan from Fordefi (LS MitM), @hacker-volodya (Tonlib), OKX team (async cell loading), @krigga (emulator)
|
||||||
|
|
||||||
## 2024.10 Update
|
## 2024.10 Update
|
||||||
|
|
||||||
1. Parallel write to celldb: substantial improvement of sync and GC speed, especially with slow disks.
|
1. Parallel write to celldb: substantial improvement of sync and GC speed, especially with slow disks.
|
||||||
|
|
|
@ -272,6 +272,10 @@ class HardforkCreator : public td::actor::Actor {
|
||||||
void download_archive(ton::BlockSeqno masterchain_seqno, ton::ShardIdFull shard_prefix, std::string tmp_dir,
|
void download_archive(ton::BlockSeqno masterchain_seqno, ton::ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
||||||
}
|
}
|
||||||
|
void download_out_msg_queue_proof(
|
||||||
|
ton::ShardIdFull dst_shard, std::vector<ton::BlockIdExt> blocks, block::ImportedMsgQueueLimits limits,
|
||||||
|
td::Timestamp timeout, td::Promise<std::vector<td::Ref<ton::validator::OutMsgQueueProof>>> promise) override {
|
||||||
|
}
|
||||||
|
|
||||||
void new_key_block(ton::validator::BlockHandle handle) override {
|
void new_key_block(ton::validator::BlockHandle handle) override {
|
||||||
}
|
}
|
||||||
|
|
|
@ -660,6 +660,12 @@ bool EnqueuedMsgDescr::check_key(td::ConstBitPtr key) const {
|
||||||
hash_ == key + 96;
|
hash_ == key + 96;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImportedMsgQueueLimits::deserialize(vm::CellSlice& cs) {
|
||||||
|
return cs.fetch_ulong(8) == 0xd3 // imported_msg_queue_limits#d3
|
||||||
|
&& cs.fetch_uint_to(32, max_bytes) // max_bytes:#
|
||||||
|
&& cs.fetch_uint_to(32, max_msgs); // max_msgs:#
|
||||||
|
}
|
||||||
|
|
||||||
bool ParamLimits::deserialize(vm::CellSlice& cs) {
|
bool ParamLimits::deserialize(vm::CellSlice& cs) {
|
||||||
return cs.fetch_ulong(8) == 0xc3 // param_limits#c3
|
return cs.fetch_ulong(8) == 0xc3 // param_limits#c3
|
||||||
&& cs.fetch_uint_to(32, limits_[0]) // underload:uint32
|
&& cs.fetch_uint_to(32, limits_[0]) // underload:uint32
|
||||||
|
|
|
@ -216,6 +216,16 @@ static inline std::ostream& operator<<(std::ostream& os, const MsgProcessedUptoC
|
||||||
return proc_coll.print(os);
|
return proc_coll.print(os);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ImportedMsgQueueLimits {
|
||||||
|
// Default values
|
||||||
|
td::uint32 max_bytes = 1 << 16;
|
||||||
|
td::uint32 max_msgs = 30;
|
||||||
|
bool deserialize(vm::CellSlice& cs);
|
||||||
|
ImportedMsgQueueLimits operator*(td::uint32 x) const {
|
||||||
|
return {max_bytes * x, max_msgs * x};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct ParamLimits {
|
struct ParamLimits {
|
||||||
enum { limits_cnt = 4 };
|
enum { limits_cnt = 4 };
|
||||||
enum { cl_underload = 0, cl_normal = 1, cl_soft = 2, cl_medium = 3, cl_hard = 4 };
|
enum { cl_underload = 0, cl_normal = 1, cl_soft = 2, cl_medium = 3, cl_hard = 4 };
|
||||||
|
|
|
@ -554,11 +554,7 @@ class BitArray {
|
||||||
set_same(0);
|
set_same(0);
|
||||||
}
|
}
|
||||||
void set_zero_s() {
|
void set_zero_s() {
|
||||||
volatile uint8* p = data();
|
as_slice().fill_zero_secure();
|
||||||
auto x = m;
|
|
||||||
while (x--) {
|
|
||||||
*p++ = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void set_ones() {
|
void set_ones() {
|
||||||
set_same(1);
|
set_same(1);
|
||||||
|
|
|
@ -111,14 +111,16 @@ class DynamicBagOfCellsDbImpl : public DynamicBagOfCellsDb, private ExtCellCreat
|
||||||
}
|
}
|
||||||
void load_cell_async(td::Slice hash, std::shared_ptr<AsyncExecutor> executor,
|
void load_cell_async(td::Slice hash, std::shared_ptr<AsyncExecutor> executor,
|
||||||
td::Promise<Ref<DataCell>> promise) override {
|
td::Promise<Ref<DataCell>> promise) override {
|
||||||
|
auto promise_ptr = std::make_shared<td::Promise<Ref<DataCell>>>(std::move(promise));
|
||||||
auto info = hash_table_.get_if_exists(hash);
|
auto info = hash_table_.get_if_exists(hash);
|
||||||
if (info && info->sync_with_db) {
|
if (info && info->sync_with_db) {
|
||||||
TRY_RESULT_PROMISE(promise, loaded_cell, info->cell->load_cell());
|
executor->execute_async([promise = std::move(promise_ptr), cell = info->cell]() mutable {
|
||||||
promise.set_result(loaded_cell.data_cell);
|
TRY_RESULT_PROMISE((*promise), loaded_cell, cell->load_cell());
|
||||||
|
promise->set_result(loaded_cell.data_cell);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SimpleExtCellCreator ext_cell_creator(cell_db_reader_);
|
SimpleExtCellCreator ext_cell_creator(cell_db_reader_);
|
||||||
auto promise_ptr = std::make_shared<td::Promise<Ref<DataCell>>>(std::move(promise));
|
|
||||||
executor->execute_async(
|
executor->execute_async(
|
||||||
[executor, loader = *loader_, hash = CellHash::from_slice(hash), db = this,
|
[executor, loader = *loader_, hash = CellHash::from_slice(hash), db = this,
|
||||||
ext_cell_creator = std::move(ext_cell_creator), promise = std::move(promise_ptr)]() mutable {
|
ext_cell_creator = std::move(ext_cell_creator), promise = std::move(promise_ptr)]() mutable {
|
||||||
|
|
|
@ -47,8 +47,8 @@ endif()
|
||||||
if (USE_EMSCRIPTEN)
|
if (USE_EMSCRIPTEN)
|
||||||
add_executable(emulator-emscripten ${EMULATOR_EMSCRIPTEN_SOURCE})
|
add_executable(emulator-emscripten ${EMULATOR_EMSCRIPTEN_SOURCE})
|
||||||
target_link_libraries(emulator-emscripten PUBLIC emulator)
|
target_link_libraries(emulator-emscripten PUBLIC emulator)
|
||||||
target_link_options(emulator-emscripten PRIVATE -sEXPORTED_RUNTIME_METHODS=_malloc,free,UTF8ToString,stringToUTF8,allocate,ALLOC_NORMAL,lengthBytesUTF8)
|
target_link_options(emulator-emscripten PRIVATE -sEXPORTED_RUNTIME_METHODS=UTF8ToString,stringToUTF8,allocate,ALLOC_NORMAL,lengthBytesUTF8)
|
||||||
target_link_options(emulator-emscripten PRIVATE -sEXPORTED_FUNCTIONS=_emulate,_free,_run_get_method,_create_emulator,_destroy_emulator,_emulate_with_emulator,_version)
|
target_link_options(emulator-emscripten PRIVATE -sEXPORTED_FUNCTIONS=_emulate,_free,_malloc,_run_get_method,_create_emulator,_destroy_emulator,_emulate_with_emulator,_version)
|
||||||
target_link_options(emulator-emscripten PRIVATE -sEXPORT_NAME=EmulatorModule)
|
target_link_options(emulator-emscripten PRIVATE -sEXPORT_NAME=EmulatorModule)
|
||||||
target_link_options(emulator-emscripten PRIVATE -sERROR_ON_UNDEFINED_SYMBOLS=0)
|
target_link_options(emulator-emscripten PRIVATE -sERROR_ON_UNDEFINED_SYMBOLS=0)
|
||||||
target_link_options(emulator-emscripten PRIVATE -Oz)
|
target_link_options(emulator-emscripten PRIVATE -Oz)
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace ton {
|
||||||
namespace keyring {
|
namespace keyring {
|
||||||
|
|
||||||
KeyringImpl::PrivateKeyDescr::PrivateKeyDescr(PrivateKey private_key, bool is_temp)
|
KeyringImpl::PrivateKeyDescr::PrivateKeyDescr(PrivateKey private_key, bool is_temp)
|
||||||
: public_key(private_key.compute_public_key()), is_temp(is_temp) {
|
: public_key(private_key.compute_public_key()), private_key(private_key), is_temp(is_temp) {
|
||||||
auto D = private_key.create_decryptor_async();
|
auto D = private_key.create_decryptor_async();
|
||||||
D.ensure();
|
D.ensure();
|
||||||
decryptor_sign = D.move_as_ok();
|
decryptor_sign = D.move_as_ok();
|
||||||
|
@ -190,6 +190,16 @@ void KeyringImpl::decrypt_message(PublicKeyHash key_hash, td::BufferSlice data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KeyringImpl::export_all_private_keys(td::Promise<std::vector<PrivateKey>> promise) {
|
||||||
|
std::vector<PrivateKey> keys;
|
||||||
|
for (auto& [_, descr] : map_) {
|
||||||
|
if (!descr->is_temp && descr->private_key.exportable()) {
|
||||||
|
keys.push_back(descr->private_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
promise.set_value(std::move(keys));
|
||||||
|
}
|
||||||
|
|
||||||
td::actor::ActorOwn<Keyring> Keyring::create(std::string db_root) {
|
td::actor::ActorOwn<Keyring> Keyring::create(std::string db_root) {
|
||||||
return td::actor::create_actor<KeyringImpl>("keyring", db_root);
|
return td::actor::create_actor<KeyringImpl>("keyring", db_root);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ class Keyring : public td::actor::Actor {
|
||||||
|
|
||||||
virtual void decrypt_message(PublicKeyHash key_hash, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
|
virtual void decrypt_message(PublicKeyHash key_hash, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
|
||||||
|
|
||||||
|
virtual void export_all_private_keys(td::Promise<std::vector<PrivateKey>> promise) = 0;
|
||||||
|
|
||||||
static td::actor::ActorOwn<Keyring> create(std::string db_root);
|
static td::actor::ActorOwn<Keyring> create(std::string db_root);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ class KeyringImpl : public Keyring {
|
||||||
td::actor::ActorOwn<DecryptorAsync> decryptor_sign;
|
td::actor::ActorOwn<DecryptorAsync> decryptor_sign;
|
||||||
td::actor::ActorOwn<DecryptorAsync> decryptor_decrypt;
|
td::actor::ActorOwn<DecryptorAsync> decryptor_decrypt;
|
||||||
PublicKey public_key;
|
PublicKey public_key;
|
||||||
|
PrivateKey private_key;
|
||||||
bool is_temp;
|
bool is_temp;
|
||||||
PrivateKeyDescr(PrivateKey private_key, bool is_temp);
|
PrivateKeyDescr(PrivateKey private_key, bool is_temp);
|
||||||
};
|
};
|
||||||
|
@ -56,6 +57,8 @@ class KeyringImpl : public Keyring {
|
||||||
|
|
||||||
void decrypt_message(PublicKeyHash key_hash, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override;
|
void decrypt_message(PublicKeyHash key_hash, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override;
|
||||||
|
|
||||||
|
void export_all_private_keys(td::Promise<std::vector<PrivateKey>> promise) override;
|
||||||
|
|
||||||
KeyringImpl(std::string db_root) : db_root_(db_root) {
|
KeyringImpl(std::string db_root) : db_root_(db_root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
## 2024.10 Update
|
## 2024.12 Update
|
||||||
|
|
||||||
1. Parallel write to celldb: substantial improvement of sync and GC speed, especially with slow disks.
|
|
||||||
2. Decreased network traffic: only first block candidate is sent optimistically.
|
|
||||||
3. Improved channel creation and dht lookups, introduction of semi-private overlays
|
|
||||||
4. New LS dispatch queue related methods and improvement security
|
|
||||||
5. Fixing recursion in TVM continuations
|
|
||||||
6. Improved stats for actors, validator sessions, perf counters, overlays, adnl, rocksdb
|
|
||||||
7. Migration to C++20
|
|
||||||
8. Improved block size estimates: account for depth in various structures
|
|
||||||
9. Fix bug with `<<` optimization in FunC
|
|
||||||
10. Minor changes of TVM which will be activated by `Config8.version >= 9`
|
|
||||||
11. Multiple minor improvements
|
|
||||||
|
|
||||||
Besides the work of the core team, this update is based on the efforts of @krigga (emulator), Arayz @ TonBit (LS security, TVM recursion), @ret2happy (UB in BLST).
|
|
||||||
|
|
||||||
|
1. FunC 0.4.6: Fix in try/catch handling, fixing pure flag for functions stored in variables
|
||||||
|
2. Merging parts of Accelerator: support of specific shard monitoring, archive/liteserver slice format, support for partial liteservers, proxy liteserver, on-demand neighbour queue loading
|
||||||
|
3. Fix of asynchronous cell loading
|
||||||
|
4. Various improvements: caching certificates checks, better block overloading detection, `_malloc` in emulator
|
||||||
|
5. Introduction of telemetry in overlays
|
||||||
|
6. Use non-null local-id for tonlib-LS interaction - mitigates MitM attack.
|
||||||
|
7. Adding `SECP256K1_XONLY_PUBKEY_TWEAK_ADD`, `SETCONTCTRMANY` instructions to TVM (activated by `Config8.version >= 9`)
|
||||||
|
8. Private keys export via validator-engine-console - required for better backups
|
||||||
|
9. Fix proof checking in tonlib, `hash` in `raw.Message` in tonlib_api
|
||||||
|
|
||||||
|
Besides the work of the core team, this update is based on the efforts of OtterSec and LayerZero (FunC), tg:@throwunless (FunC), Aviv Frenkel and Dima Kogan from Fordefi (LS MitM), @hacker-volodya (Tonlib), OKX team (async cell loading), @krigga (emulator)
|
||||||
|
|
|
@ -149,4 +149,19 @@ std::enable_if_t<std::is_arithmetic<T>::value, string> to_string(const T &x) {
|
||||||
return sb.as_cslice().str();
|
return sb.as_cslice().str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class SB>
|
||||||
|
struct LambdaPrintHelper {
|
||||||
|
SB& sb;
|
||||||
|
};
|
||||||
|
template <class SB, class F>
|
||||||
|
SB& operator<<(const LambdaPrintHelper<SB>& helper, F&& f) {
|
||||||
|
f(helper.sb);
|
||||||
|
return helper.sb;
|
||||||
|
}
|
||||||
|
struct LambdaPrint {};
|
||||||
|
|
||||||
|
inline LambdaPrintHelper<td::StringBuilder> operator<<(td::StringBuilder& sb, const LambdaPrint&) {
|
||||||
|
return LambdaPrintHelper<td::StringBuilder>{sb};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
|
|
||||||
#define LOG(level) LOG_IMPL(level, level, true, ::td::Slice())
|
#define LOG(level) LOG_IMPL(level, level, true, ::td::Slice())
|
||||||
#define LOG_IF(level, condition) LOG_IMPL(level, level, condition, #condition)
|
#define LOG_IF(level, condition) LOG_IMPL(level, level, condition, #condition)
|
||||||
|
#define FLOG(level) LOG_IMPL(level, level, true, ::td::Slice()) << td::LambdaPrint{} << [&](auto &sb)
|
||||||
|
|
||||||
#define VLOG(level) LOG_IMPL(DEBUG, level, true, TD_DEFINE_STR(level))
|
#define VLOG(level) LOG_IMPL(DEBUG, level, true, TD_DEFINE_STR(level))
|
||||||
#define VLOG_IF(level, condition) LOG_IMPL(DEBUG, level, condition, TD_DEFINE_STR(level) " " #condition)
|
#define VLOG_IF(level, condition) LOG_IMPL(DEBUG, level, condition, TD_DEFINE_STR(level) " " #condition)
|
||||||
|
@ -95,13 +96,13 @@ inline bool no_return_func() {
|
||||||
#define DUMMY_LOG_CHECK(condition) LOG_IF(NEVER, !(condition))
|
#define DUMMY_LOG_CHECK(condition) LOG_IF(NEVER, !(condition))
|
||||||
|
|
||||||
#ifdef TD_DEBUG
|
#ifdef TD_DEBUG
|
||||||
#if TD_MSVC
|
#if TD_MSVC
|
||||||
#define LOG_CHECK(condition) \
|
#define LOG_CHECK(condition) \
|
||||||
__analysis_assume(!!(condition)); \
|
__analysis_assume(!!(condition)); \
|
||||||
LOG_IMPL(FATAL, FATAL, !(condition), #condition)
|
LOG_IMPL(FATAL, FATAL, !(condition), #condition)
|
||||||
#else
|
#else
|
||||||
#define LOG_CHECK(condition) LOG_IMPL(FATAL, FATAL, !(condition) && no_return_func(), #condition)
|
#define LOG_CHECK(condition) LOG_IMPL(FATAL, FATAL, !(condition) && no_return_func(), #condition)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#define LOG_CHECK DUMMY_LOG_CHECK
|
#define LOG_CHECK DUMMY_LOG_CHECK
|
||||||
#endif
|
#endif
|
||||||
|
@ -263,6 +264,9 @@ class Logger {
|
||||||
sb_ << other;
|
sb_ << other;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
LambdaPrintHelper<td::Logger> operator<<(const LambdaPrint &) {
|
||||||
|
return LambdaPrintHelper<td::Logger>{*this};
|
||||||
|
}
|
||||||
|
|
||||||
MutableCSlice as_cslice() {
|
MutableCSlice as_cslice() {
|
||||||
return sb_.as_cslice();
|
return sb_.as_cslice();
|
||||||
|
|
|
@ -373,6 +373,10 @@ class TestNode : public td::actor::Actor {
|
||||||
void download_archive(ton::BlockSeqno masterchain_seqno, ton::ShardIdFull shard_prefix, std::string tmp_dir,
|
void download_archive(ton::BlockSeqno masterchain_seqno, ton::ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
||||||
}
|
}
|
||||||
|
void download_out_msg_queue_proof(
|
||||||
|
ton::ShardIdFull dst_shard, std::vector<ton::BlockIdExt> blocks, block::ImportedMsgQueueLimits limits,
|
||||||
|
td::Timestamp timeout, td::Promise<std::vector<td::Ref<ton::validator::OutMsgQueueProof>>> promise) override {
|
||||||
|
}
|
||||||
|
|
||||||
void new_key_block(ton::validator::BlockHandle handle) override {
|
void new_key_block(ton::validator::BlockHandle handle) override {
|
||||||
}
|
}
|
||||||
|
|
|
@ -454,6 +454,10 @@ tonNode.success = tonNode.Success;
|
||||||
tonNode.archiveNotFound = tonNode.ArchiveInfo;
|
tonNode.archiveNotFound = tonNode.ArchiveInfo;
|
||||||
tonNode.archiveInfo id:long = tonNode.ArchiveInfo;
|
tonNode.archiveInfo id:long = tonNode.ArchiveInfo;
|
||||||
|
|
||||||
|
tonNode.importedMsgQueueLimits max_bytes:int max_msgs:int = ImportedMsgQueueLimits;
|
||||||
|
tonNode.outMsgQueueProof queue_proofs:bytes block_state_proofs:bytes msg_counts:(vector int) = tonNode.OutMsgQueueProof;
|
||||||
|
tonNode.outMsgQueueProofEmpty = tonNode.OutMsgQueueProof;
|
||||||
|
|
||||||
tonNode.forgetPeer = tonNode.ForgetPeer;
|
tonNode.forgetPeer = tonNode.ForgetPeer;
|
||||||
|
|
||||||
---functions---
|
---functions---
|
||||||
|
@ -483,6 +487,8 @@ tonNode.downloadKeyBlockProofLink block:tonNode.blockIdExt = tonNode.Data;
|
||||||
tonNode.getArchiveInfo masterchain_seqno:int = tonNode.ArchiveInfo;
|
tonNode.getArchiveInfo masterchain_seqno:int = tonNode.ArchiveInfo;
|
||||||
tonNode.getShardArchiveInfo masterchain_seqno:int shard_prefix:tonNode.shardId = tonNode.ArchiveInfo;
|
tonNode.getShardArchiveInfo masterchain_seqno:int shard_prefix:tonNode.shardId = tonNode.ArchiveInfo;
|
||||||
tonNode.getArchiveSlice archive_id:long offset:long max_size:int = tonNode.Data;
|
tonNode.getArchiveSlice archive_id:long offset:long max_size:int = tonNode.Data;
|
||||||
|
tonNode.getOutMsgQueueProof dst_shard:tonNode.shardId blocks:(vector tonNode.blockIdExt)
|
||||||
|
limits:tonNode.importedMsgQueueLimits = tonNode.OutMsgQueueProof;
|
||||||
|
|
||||||
tonNode.getCapabilities = tonNode.Capabilities;
|
tonNode.getCapabilities = tonNode.Capabilities;
|
||||||
|
|
||||||
|
@ -725,6 +731,8 @@ engine.validator.perfTimerStats stats:(vector engine.validator.PerfTimerStatsByN
|
||||||
|
|
||||||
engine.validator.shardOutQueueSize size:long = engine.validator.ShardOutQueueSize;
|
engine.validator.shardOutQueueSize size:long = engine.validator.ShardOutQueueSize;
|
||||||
|
|
||||||
|
engine.validator.exportedPrivateKeys encrypted_data:bytes = engine.validator.ExportedPrivateKeys;
|
||||||
|
|
||||||
|
|
||||||
---functions---
|
---functions---
|
||||||
|
|
||||||
|
@ -755,6 +763,7 @@ engine.validator.delListeningPort ip:int port:int categories:(vector int) priori
|
||||||
engine.validator.delProxy out_ip:int out_port:int categories:(vector int) priority_categories:(vector int) = engine.validator.Success;
|
engine.validator.delProxy out_ip:int out_port:int categories:(vector int) priority_categories:(vector int) = engine.validator.Success;
|
||||||
|
|
||||||
engine.validator.sign key_hash:int256 data:bytes = engine.validator.Signature;
|
engine.validator.sign key_hash:int256 data:bytes = engine.validator.Signature;
|
||||||
|
engine.validator.exportAllPrivateKeys encryption_key:PublicKey = engine.validator.ExportedPrivateKeys;
|
||||||
|
|
||||||
engine.validator.getStats = engine.validator.Stats;
|
engine.validator.getStats = engine.validator.Stats;
|
||||||
engine.validator.getConfig = engine.validator.JsonConfig;
|
engine.validator.getConfig = engine.validator.JsonConfig;
|
||||||
|
|
Binary file not shown.
|
@ -120,6 +120,26 @@ struct ShardIdFull {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
return std::string{buffer, (unsigned)snprintf(buffer, 63, "(%d,%016llx)", workchain, (unsigned long long)shard)};
|
return std::string{buffer, (unsigned)snprintf(buffer, 63, "(%d,%016llx)", workchain, (unsigned long long)shard)};
|
||||||
}
|
}
|
||||||
|
static td::Result<ShardIdFull> parse(td::Slice s) {
|
||||||
|
// Formats: (0,2000000000000000) (0:2000000000000000) 0,2000000000000000 0:2000000000000000
|
||||||
|
if (s.empty()) {
|
||||||
|
return td::Status::Error("empty string");
|
||||||
|
}
|
||||||
|
if (s[0] == '(' && s.back() == ')') {
|
||||||
|
s = s.substr(1, s.size() - 2);
|
||||||
|
}
|
||||||
|
auto sep = s.find(':');
|
||||||
|
if (sep == td::Slice::npos) {
|
||||||
|
sep = s.find(',');
|
||||||
|
}
|
||||||
|
if (sep == td::Slice::npos || s.size() - sep - 1 != 16) {
|
||||||
|
return td::Status::Error(PSTRING() << "invalid shard " << s);
|
||||||
|
}
|
||||||
|
ShardIdFull shard;
|
||||||
|
TRY_RESULT_ASSIGN(shard.workchain, td::to_integer_safe<td::int32>(s.substr(0, sep)));
|
||||||
|
TRY_RESULT_ASSIGN(shard.shard, td::hex_to_integer_safe<td::uint64>(s.substr(sep + 1)));
|
||||||
|
return shard;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AccountIdPrefixFull {
|
struct AccountIdPrefixFull {
|
||||||
|
|
|
@ -5673,6 +5673,26 @@ td::Status TonlibClient::do_request(const tonlib_api::blocks_lookupBlock& reques
|
||||||
td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_lookupBlockResult>& result, int mode, ton::BlockId blkid, ton::BlockIdExt client_mc_blkid, td::uint64 lt, td::uint32 utime) {
|
td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_lookupBlockResult>& result, int mode, ton::BlockId blkid, ton::BlockIdExt client_mc_blkid, td::uint64 lt, td::uint32 utime) {
|
||||||
try {
|
try {
|
||||||
ton::BlockIdExt cur_id = ton::create_block_id(result->mc_block_id_);
|
ton::BlockIdExt cur_id = ton::create_block_id(result->mc_block_id_);
|
||||||
|
if (!cur_id.is_masterchain_ext()) {
|
||||||
|
return td::Status::Error("invalid response: mc block id is not from masterchain");
|
||||||
|
}
|
||||||
|
if (client_mc_blkid != cur_id) {
|
||||||
|
auto state = block::check_extract_state_proof(client_mc_blkid, result->client_mc_state_proof_.as_slice(),
|
||||||
|
result->mc_block_proof_.as_slice());
|
||||||
|
if (state.is_error()) {
|
||||||
|
LOG(WARNING) << "cannot check state proof: " << state.move_as_error().to_string();
|
||||||
|
return state.move_as_error();
|
||||||
|
}
|
||||||
|
auto state_root = state.move_as_ok();
|
||||||
|
auto prev_blocks_dict = block::get_prev_blocks_dict(state_root);
|
||||||
|
if (!prev_blocks_dict) {
|
||||||
|
return td::Status::Error("cannot extract prev blocks dict from state");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!block::check_old_mc_block_id(*prev_blocks_dict, cur_id)) {
|
||||||
|
return td::Status::Error("couldn't check old mc block id");
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
for (auto& link : result->shard_links_) {
|
for (auto& link : result->shard_links_) {
|
||||||
ton::BlockIdExt prev_id = create_block_id(link->id_);
|
ton::BlockIdExt prev_id = create_block_id(link->id_);
|
||||||
|
@ -5686,23 +5706,6 @@ td::Status check_lookup_block_proof(lite_api_ptr<ton::lite_api::liteServer_looku
|
||||||
return td::Status::Error("invalid block hash in proof");
|
return td::Status::Error("invalid block hash in proof");
|
||||||
}
|
}
|
||||||
if (cur_id.is_masterchain()) {
|
if (cur_id.is_masterchain()) {
|
||||||
if (client_mc_blkid != cur_id) {
|
|
||||||
auto state = block::check_extract_state_proof(client_mc_blkid, result->client_mc_state_proof_.as_slice(),
|
|
||||||
result->mc_block_proof_.as_slice());
|
|
||||||
if (state.is_error()) {
|
|
||||||
LOG(WARNING) << "cannot check state proof: " << state.move_as_error().to_string();
|
|
||||||
return state.move_as_error();
|
|
||||||
}
|
|
||||||
auto state_root = state.move_as_ok();
|
|
||||||
auto prev_blocks_dict = block::get_prev_blocks_dict(state_root);
|
|
||||||
if (!prev_blocks_dict) {
|
|
||||||
return td::Status::Error("cannot extract prev blocks dict from state");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!block::check_old_mc_block_id(*prev_blocks_dict, cur_id)) {
|
|
||||||
return td::Status::Error("couldn't check old mc block id");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
block::gen::Block::Record blk;
|
block::gen::Block::Record blk;
|
||||||
block::gen::BlockExtra::Record extra;
|
block::gen::BlockExtra::Record extra;
|
||||||
block::gen::McBlockExtra::Record mc_extra;
|
block::gen::McBlockExtra::Record mc_extra;
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
#include "ton/ton-tl.hpp"
|
#include "ton/ton-tl.hpp"
|
||||||
#include "td/utils/JsonBuilder.h"
|
#include "td/utils/JsonBuilder.h"
|
||||||
#include "auto/tl/ton_api_json.h"
|
#include "auto/tl/ton_api_json.h"
|
||||||
|
#include "keys/encryptor.h"
|
||||||
|
#include "td/utils/port/path.h"
|
||||||
#include "tl/tl_json.h"
|
#include "tl/tl_json.h"
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
@ -283,6 +285,66 @@ td::Status SignFileQuery::receive(td::BufferSlice data) {
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td::Status ExportAllPrivateKeysQuery::run() {
|
||||||
|
TRY_RESULT_ASSIGN(directory_, tokenizer_.get_token<std::string>());
|
||||||
|
TRY_STATUS(tokenizer_.check_endl());
|
||||||
|
client_pk_ = ton::privkeys::Ed25519::random();
|
||||||
|
return td::Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
td::Status ExportAllPrivateKeysQuery::send() {
|
||||||
|
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_exportAllPrivateKeys>(
|
||||||
|
client_pk_.compute_public_key().tl());
|
||||||
|
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||||
|
return td::Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
td::Status ExportAllPrivateKeysQuery::receive(td::BufferSlice data) {
|
||||||
|
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_exportedPrivateKeys>(data.as_slice(), true),
|
||||||
|
"received incorrect answer: ");
|
||||||
|
// Private keys are encrypted using client-provided public key to avoid storing them in
|
||||||
|
// non-secure buffers (not td::SecureString)
|
||||||
|
TRY_RESULT_PREFIX(decryptor, client_pk_.create_decryptor(), "cannot create decryptor: ");
|
||||||
|
TRY_RESULT_PREFIX(keys_data, decryptor->decrypt(f->encrypted_data_.as_slice()), "cannot decrypt data: ");
|
||||||
|
SCOPE_EXIT {
|
||||||
|
keys_data.as_slice().fill_zero_secure();
|
||||||
|
};
|
||||||
|
td::Slice slice = keys_data.as_slice();
|
||||||
|
if (slice.size() < 32) {
|
||||||
|
return td::Status::Error("data is too small");
|
||||||
|
}
|
||||||
|
slice.remove_suffix(32);
|
||||||
|
std::vector<ton::PrivateKey> private_keys;
|
||||||
|
while (!slice.empty()) {
|
||||||
|
if (slice.size() < 4) {
|
||||||
|
return td::Status::Error("unexpected end of data");
|
||||||
|
}
|
||||||
|
td::uint32 size;
|
||||||
|
td::MutableSlice{reinterpret_cast<char *>(&size), 4}.copy_from(slice.substr(0, 4));
|
||||||
|
if (size > slice.size()) {
|
||||||
|
return td::Status::Error("unexpected end of data");
|
||||||
|
}
|
||||||
|
slice.remove_prefix(4);
|
||||||
|
TRY_RESULT_PREFIX(private_key, ton::PrivateKey::import(slice.substr(0, size)), "cannot parse private key: ");
|
||||||
|
if (!private_key.exportable()) {
|
||||||
|
return td::Status::Error("private key is not exportable");
|
||||||
|
}
|
||||||
|
private_keys.push_back(std::move(private_key));
|
||||||
|
slice.remove_prefix(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_STATUS_PREFIX(td::mkpath(directory_ + "/"), "cannot create directory " + directory_ + ": ");
|
||||||
|
td::TerminalIO::out() << "exported " << private_keys.size() << " private keys" << "\n";
|
||||||
|
for (const ton::PrivateKey &private_key : private_keys) {
|
||||||
|
std::string hash_hex = private_key.compute_short_id().bits256_value().to_hex();
|
||||||
|
TRY_STATUS_PREFIX(td::write_file(directory_ + "/" + hash_hex, private_key.export_as_slice()),
|
||||||
|
"failed to write file: ");
|
||||||
|
td::TerminalIO::out() << "pubkey_hash " << hash_hex << "\n";
|
||||||
|
}
|
||||||
|
td::TerminalIO::out() << "written all files to " << directory_ << "\n";
|
||||||
|
return td::Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
td::Status AddAdnlAddrQuery::run() {
|
td::Status AddAdnlAddrQuery::run() {
|
||||||
TRY_RESULT_ASSIGN(key_hash_, tokenizer_.get_token<ton::PublicKeyHash>());
|
TRY_RESULT_ASSIGN(key_hash_, tokenizer_.get_token<ton::PublicKeyHash>());
|
||||||
TRY_RESULT_ASSIGN(category_, tokenizer_.get_token<td::uint32>());
|
TRY_RESULT_ASSIGN(category_, tokenizer_.get_token<td::uint32>());
|
||||||
|
@ -979,8 +1041,7 @@ td::Status ImportCertificateQuery::receive(td::BufferSlice data) {
|
||||||
|
|
||||||
|
|
||||||
td::Status SignShardOverlayCertificateQuery::run() {
|
td::Status SignShardOverlayCertificateQuery::run() {
|
||||||
TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token<td::int32>());
|
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<ton::ShardIdFull>() );
|
||||||
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<td::int64>() );
|
|
||||||
TRY_RESULT_ASSIGN(key_, tokenizer_.get_token<ton::PublicKeyHash>());
|
TRY_RESULT_ASSIGN(key_, tokenizer_.get_token<ton::PublicKeyHash>());
|
||||||
TRY_RESULT_ASSIGN(expire_at_, tokenizer_.get_token<td::int32>());
|
TRY_RESULT_ASSIGN(expire_at_, tokenizer_.get_token<td::int32>());
|
||||||
TRY_RESULT_ASSIGN(max_size_, tokenizer_.get_token<td::uint32>());
|
TRY_RESULT_ASSIGN(max_size_, tokenizer_.get_token<td::uint32>());
|
||||||
|
@ -990,8 +1051,9 @@ td::Status SignShardOverlayCertificateQuery::run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status SignShardOverlayCertificateQuery::send() {
|
td::Status SignShardOverlayCertificateQuery::send() {
|
||||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_signShardOverlayCertificate>
|
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_signShardOverlayCertificate>(
|
||||||
(wc_, shard_, ton::create_tl_object<ton::ton_api::engine_validator_keyHash>(key_.tl()), expire_at_, max_size_);
|
shard_.workchain, shard_.shard, ton::create_tl_object<ton::ton_api::engine_validator_keyHash>(key_.tl()),
|
||||||
|
expire_at_, max_size_);
|
||||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
@ -1009,8 +1071,7 @@ td::Status SignShardOverlayCertificateQuery::receive(td::BufferSlice data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status ImportShardOverlayCertificateQuery::run() {
|
td::Status ImportShardOverlayCertificateQuery::run() {
|
||||||
TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token<td::int32>());
|
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<ton::ShardIdFull>());
|
||||||
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<td::int64>() );
|
|
||||||
TRY_RESULT_ASSIGN(key_, tokenizer_.get_token<ton::PublicKeyHash>());
|
TRY_RESULT_ASSIGN(key_, tokenizer_.get_token<ton::PublicKeyHash>());
|
||||||
TRY_RESULT_ASSIGN(in_file_, tokenizer_.get_token<std::string>());
|
TRY_RESULT_ASSIGN(in_file_, tokenizer_.get_token<std::string>());
|
||||||
|
|
||||||
|
@ -1021,8 +1082,9 @@ td::Status ImportShardOverlayCertificateQuery::send() {
|
||||||
TRY_RESULT(data, td::read_file(in_file_));
|
TRY_RESULT(data, td::read_file(in_file_));
|
||||||
TRY_RESULT_PREFIX(cert, ton::fetch_tl_object<ton::ton_api::overlay_Certificate>(data.as_slice(), true),
|
TRY_RESULT_PREFIX(cert, ton::fetch_tl_object<ton::ton_api::overlay_Certificate>(data.as_slice(), true),
|
||||||
"incorrect certificate");
|
"incorrect certificate");
|
||||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_importShardOverlayCertificate>
|
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_importShardOverlayCertificate>(
|
||||||
(wc_, shard_, ton::create_tl_object<ton::ton_api::engine_validator_keyHash>(key_.tl()), std::move(cert));
|
shard_.workchain, shard_.shard, ton::create_tl_object<ton::ton_api::engine_validator_keyHash>(key_.tl()),
|
||||||
|
std::move(cert));
|
||||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
@ -1111,14 +1173,12 @@ td::Status GetPerfTimerStatsJsonQuery::receive(td::BufferSlice data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status GetShardOutQueueSizeQuery::run() {
|
td::Status GetShardOutQueueSizeQuery::run() {
|
||||||
TRY_RESULT_ASSIGN(block_id_.workchain, tokenizer_.get_token<int>());
|
TRY_RESULT(shard, tokenizer_.get_token<ton::ShardIdFull>());
|
||||||
TRY_RESULT_ASSIGN(block_id_.shard, tokenizer_.get_token<long long>());
|
block_id_.workchain = shard.workchain;
|
||||||
|
block_id_.shard = shard.shard;
|
||||||
TRY_RESULT_ASSIGN(block_id_.seqno, tokenizer_.get_token<int>());
|
TRY_RESULT_ASSIGN(block_id_.seqno, tokenizer_.get_token<int>());
|
||||||
if (!tokenizer_.endl()) {
|
if (!tokenizer_.endl()) {
|
||||||
ton::ShardIdFull dest;
|
TRY_RESULT_ASSIGN(dest_, tokenizer_.get_token<ton::ShardIdFull>());
|
||||||
TRY_RESULT_ASSIGN(dest.workchain, tokenizer_.get_token<int>());
|
|
||||||
TRY_RESULT_ASSIGN(dest.shard, tokenizer_.get_token<long long>());
|
|
||||||
dest_ = dest;
|
|
||||||
}
|
}
|
||||||
TRY_STATUS(tokenizer_.check_endl());
|
TRY_STATUS(tokenizer_.check_endl());
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
|
@ -1126,8 +1186,7 @@ td::Status GetShardOutQueueSizeQuery::run() {
|
||||||
|
|
||||||
td::Status GetShardOutQueueSizeQuery::send() {
|
td::Status GetShardOutQueueSizeQuery::send() {
|
||||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_getShardOutQueueSize>(
|
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_getShardOutQueueSize>(
|
||||||
dest_ ? 1 : 0, ton::create_tl_block_id_simple(block_id_), dest_ ? dest_.value().workchain : 0,
|
dest_.is_valid() ? 1 : 0, ton::create_tl_block_id_simple(block_id_), dest_.workchain, dest_.shard);
|
||||||
dest_ ? dest_.value().shard : 0);
|
|
||||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
@ -1501,14 +1560,13 @@ td::Status GetAdnlStatsQuery::receive(td::BufferSlice data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status AddShardQuery::run() {
|
td::Status AddShardQuery::run() {
|
||||||
TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token<td::int32>());
|
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<ton::ShardIdFull>());
|
||||||
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<td::int64>());
|
TRY_STATUS(tokenizer_.check_endl());
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status AddShardQuery::send() {
|
td::Status AddShardQuery::send() {
|
||||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_addShard>(
|
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_addShard>(ton::create_tl_shard_id(shard_));
|
||||||
ton::create_tl_shard_id(ton::ShardIdFull(wc_, shard_)));
|
|
||||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
@ -1521,14 +1579,13 @@ td::Status AddShardQuery::receive(td::BufferSlice data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status DelShardQuery::run() {
|
td::Status DelShardQuery::run() {
|
||||||
TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token<td::int32>());
|
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<ton::ShardIdFull>());
|
||||||
TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token<td::int64>());
|
TRY_STATUS(tokenizer_.check_endl());
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
td::Status DelShardQuery::send() {
|
td::Status DelShardQuery::send() {
|
||||||
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_delShard>(
|
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_delShard>(ton::create_tl_shard_id(shard_));
|
||||||
ton::create_tl_shard_id(ton::ShardIdFull(wc_, shard_)));
|
|
||||||
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "ton/ton-types.h"
|
#include "ton/ton-types.h"
|
||||||
|
|
||||||
#include "keys/keys.hpp"
|
#include "keys/keys.hpp"
|
||||||
|
#include "td/utils/base64.h"
|
||||||
|
|
||||||
class ValidatorEngineConsole;
|
class ValidatorEngineConsole;
|
||||||
|
|
||||||
|
@ -95,27 +96,25 @@ inline td::Result<td::SharedSlice> Tokenizer::get_token() {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline td::Result<ton::PublicKeyHash> Tokenizer::get_token() {
|
inline td::Result<td::Bits256> Tokenizer::get_token() {
|
||||||
TRY_RESULT(S, get_raw_token());
|
TRY_RESULT(word, get_raw_token());
|
||||||
TRY_RESULT(F, td::hex_decode(S));
|
std::string data;
|
||||||
if (F.size() == 32) {
|
if (word.size() == 64) {
|
||||||
return ton::PublicKeyHash{td::Slice{F}};
|
TRY_RESULT_ASSIGN(data, td::hex_decode(word));
|
||||||
|
} else if (word.size() == 44) {
|
||||||
|
TRY_RESULT_ASSIGN(data, td::base64_decode(word));
|
||||||
} else {
|
} else {
|
||||||
return td::Status::Error("cannot parse keyhash: bad length");
|
return td::Status::Error("cannot parse keyhash: bad length");
|
||||||
}
|
}
|
||||||
|
td::Bits256 v;
|
||||||
|
v.as_slice().copy_from(data);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline td::Result<td::Bits256> Tokenizer::get_token() {
|
inline td::Result<ton::PublicKeyHash> Tokenizer::get_token() {
|
||||||
TRY_RESULT(S, get_raw_token());
|
TRY_RESULT(x, get_token<td::Bits256>());
|
||||||
TRY_RESULT(F, td::hex_decode(S));
|
return ton::PublicKeyHash{x};
|
||||||
if (F.size() == 32) {
|
|
||||||
td::Bits256 v;
|
|
||||||
v.as_slice().copy_from(F);
|
|
||||||
return v;
|
|
||||||
} else {
|
|
||||||
return td::Status::Error("cannot parse keyhash: bad length");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -146,6 +145,18 @@ inline td::Result<std::vector<T>> Tokenizer::get_token_vector() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline td::Result<ton::ShardIdFull> Tokenizer::get_token() {
|
||||||
|
TRY_RESULT(word, get_raw_token());
|
||||||
|
auto r_wc = td::to_integer_safe<ton::WorkchainId>(word);
|
||||||
|
if (r_wc.is_ok()) {
|
||||||
|
TRY_RESULT_ASSIGN(word, get_raw_token());
|
||||||
|
TRY_RESULT(shard, td::to_integer_safe<ton::ShardId>(word));
|
||||||
|
return ton::ShardIdFull{r_wc.move_as_ok(), shard};
|
||||||
|
}
|
||||||
|
return ton::ShardIdFull::parse(word);
|
||||||
|
}
|
||||||
|
|
||||||
class QueryRunner {
|
class QueryRunner {
|
||||||
public:
|
public:
|
||||||
virtual ~QueryRunner() = default;
|
virtual ~QueryRunner() = default;
|
||||||
|
@ -222,10 +233,10 @@ class GetTimeQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice R) override;
|
td::Status receive(td::BufferSlice R) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "gettime";
|
return "get-time";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "gettime\tshows current server unixtime";
|
return "get-time\tshows current server unixtime";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -287,10 +298,10 @@ class NewKeyQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice R) override;
|
td::Status receive(td::BufferSlice R) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "newkey";
|
return "new-key";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "newkey\tgenerates new key pair on server";
|
return "new-key\tgenerates new key pair on server";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -308,10 +319,10 @@ class ImportPrivateKeyFileQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice R) override;
|
td::Status receive(td::BufferSlice R) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "importf";
|
return "import-f";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "importf <filename>\timport private key";
|
return "import-f <filename>\timport private key";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -330,10 +341,10 @@ class ExportPublicKeyQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice R) override;
|
td::Status receive(td::BufferSlice R) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "exportpub";
|
return "export-pub";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "exportpub <keyhash>\texports public key by key hash";
|
return "export-pub <keyhash>\texports public key by key hash";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -352,10 +363,10 @@ class ExportPublicKeyFileQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice R) override;
|
td::Status receive(td::BufferSlice R) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "exportpubf";
|
return "export-pubf";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "exportpubf <keyhash> <filename>\texports public key by key hash";
|
return "export-pub-f <keyhash> <filename>\texports public key by key hash";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -398,10 +409,10 @@ class SignFileQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "signf";
|
return "sign-f";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "signf <keyhash> <infile> <outfile>\tsigns bytestring with privkey";
|
return "sign-f <keyhash> <infile> <outfile>\tsigns bytestring with privkey";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -413,6 +424,30 @@ class SignFileQuery : public Query {
|
||||||
std::string out_file_;
|
std::string out_file_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExportAllPrivateKeysQuery : public Query {
|
||||||
|
public:
|
||||||
|
ExportAllPrivateKeysQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
|
||||||
|
: Query(console, std::move(tokenizer)) {
|
||||||
|
}
|
||||||
|
td::Status run() override;
|
||||||
|
td::Status send() override;
|
||||||
|
td::Status receive(td::BufferSlice R) override;
|
||||||
|
static std::string get_name() {
|
||||||
|
return "export-all-private-keys";
|
||||||
|
}
|
||||||
|
static std::string get_help() {
|
||||||
|
return "export-all-private-keys <directory>\texports all private keys from validator engine and stores them to "
|
||||||
|
"<directory>";
|
||||||
|
}
|
||||||
|
std::string name() const override {
|
||||||
|
return get_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string directory_;
|
||||||
|
ton::PrivateKey client_pk_;
|
||||||
|
};
|
||||||
|
|
||||||
class AddAdnlAddrQuery : public Query {
|
class AddAdnlAddrQuery : public Query {
|
||||||
public:
|
public:
|
||||||
AddAdnlAddrQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
|
AddAdnlAddrQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
|
||||||
|
@ -422,10 +457,10 @@ class AddAdnlAddrQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "addadnl";
|
return "add-adnl";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "addadnl <keyhash> <category>\tuse key as ADNL addr";
|
return "add-adnl <keyhash> <category>\tuse key as ADNL addr";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -445,10 +480,10 @@ class AddDhtIdQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "adddht";
|
return "add-dht";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "adddht <keyhash>\tcreate DHT node with specified ADNL addr";
|
return "add-dht <keyhash>\tcreate DHT node with specified ADNL addr";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -467,10 +502,10 @@ class AddValidatorPermanentKeyQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "addpermkey";
|
return "add-perm-key";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "addpermkey <keyhash> <election-date> <expire-at>\tadd validator permanent key";
|
return "add-perm-key <keyhash> <election-date> <expire-at>\tadd validator permanent key";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -491,10 +526,10 @@ class AddValidatorTempKeyQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "addtempkey";
|
return "add-temp-key";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "addtempkey <permkeyhash> <keyhash> <expireat>\tadd validator temp key";
|
return "add-temp-key <permkeyhash> <keyhash> <expireat>\tadd validator temp key";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -515,10 +550,10 @@ class AddValidatorAdnlAddrQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "addvalidatoraddr";
|
return "add-validator-addr";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "addvalidatoraddr <permkeyhash> <keyhash> <expireat>\tadd validator ADNL addr";
|
return "add-validator-addr <permkeyhash> <keyhash> <expireat>\tadd validator ADNL addr";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -539,10 +574,10 @@ class ChangeFullNodeAdnlAddrQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "changefullnodeaddr";
|
return "change-full-node-addr";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "changefullnodeaddr <keyhash>\tchanges fullnode ADNL address";
|
return "change-full-node-addr <keyhash>\tchanges fullnode ADNL address";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -561,10 +596,10 @@ class AddLiteServerQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "addliteserver";
|
return "add-liteserver";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "addliteserver <port> <keyhash>\tadd liteserver";
|
return "add-liteserver <port> <keyhash>\tadd liteserver";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -584,10 +619,10 @@ class DelAdnlAddrQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "deladnl";
|
return "del-adnl";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "deladnl <keyhash>\tdel unused ADNL addr";
|
return "del-adnl <keyhash>\tdel unused ADNL addr";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -606,10 +641,10 @@ class DelDhtIdQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "deldht";
|
return "del-dht";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "deldht <keyhash>\tdel unused DHT node";
|
return "del-dht <keyhash>\tdel unused DHT node";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -628,10 +663,10 @@ class DelValidatorPermanentKeyQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "delpermkey";
|
return "del-perm-key";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "delpermkey <keyhash>\tforce del unused validator permanent key";
|
return "del-perm-key <keyhash>\tforce del unused validator permanent key";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -650,10 +685,10 @@ class DelValidatorTempKeyQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "deltempkey";
|
return "del-temp-key";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "deltempkey <permkeyhash> <keyhash>\tforce del unused validator temp key";
|
return "del-temp-key <permkeyhash> <keyhash>\tforce del unused validator temp key";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -673,10 +708,10 @@ class DelValidatorAdnlAddrQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "delvalidatoraddr";
|
return "del-validator-addr";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "delvalidatoraddr <permkeyhash> <keyhash>\tforce del unused validator ADNL addr";
|
return "del-validator-addr <permkeyhash> <keyhash>\tforce del unused validator ADNL addr";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -696,10 +731,10 @@ class GetConfigQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getconfig";
|
return "get-config";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getconfig\tdownloads current config";
|
return "get-config\tdownloads current config";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -717,10 +752,10 @@ class SetVerbosityQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "setverbosity";
|
return "set-verbosity";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "setverbosity <value>\tchanges verbosity level";
|
return "set-verbosity <value>\tchanges verbosity level";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -739,10 +774,10 @@ class GetStatsQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getstats";
|
return "get-stats";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getstats\tprints stats";
|
return "get-stats\tprints stats";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -783,10 +818,10 @@ class AddNetworkAddressQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "addaddr";
|
return "add-addr";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "addaddr <ip> {cats...} {priocats...}\tadds ip address to address list";
|
return "add-addr <ip> {cats...} {priocats...}\tadds ip address to address list";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -807,10 +842,10 @@ class AddNetworkProxyAddressQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "addproxyaddr";
|
return "add-proxy-addr";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "addproxyaddr <inip> <outip> <id> <secret> {cats...} {priocats...}\tadds ip address to address list";
|
return "add-proxy-addr <inip> <outip> <id> <secret> {cats...} {priocats...}\tadds ip address to address list";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -834,10 +869,10 @@ class CreateElectionBidQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "createelectionbid";
|
return "create-election-bid";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "createelectionbid <date> <elector> <wallet> <fname>\tcreate election bid";
|
return "create-election-bid <date> <elector> <wallet> <fname>\tcreate election bid";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -859,10 +894,10 @@ class CreateProposalVoteQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "createproposalvote";
|
return "create-proposal-vote";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "createproposalvote <data> <fname>\tcreate proposal vote";
|
return "create-proposal-vote <data> <fname>\tcreate proposal vote";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -882,10 +917,10 @@ class CreateComplaintVoteQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "createcomplaintvote";
|
return "create-complaint-vote";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "createcomplaintvote <election-id> <data> <fname>\tcreate proposal vote";
|
return "create-complaint-vote <election-id> <data> <fname>\tcreate proposal vote";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -906,10 +941,10 @@ class CheckDhtServersQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "checkdht";
|
return "check-dht";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "checkdht <adnlid>\tchecks, which root DHT servers are accessible from this ADNL addr";
|
return "check-dht <adnlid>\tchecks, which root DHT servers are accessible from this ADNL addr";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -928,10 +963,10 @@ class GetOverlaysStatsQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getoverlaysstats";
|
return "get-overlays-stats";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getoverlaysstats\tgets stats for all overlays";
|
return "get-overlays-stats\tgets stats for all overlays";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -947,10 +982,10 @@ class GetOverlaysStatsJsonQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getoverlaysstatsjson";
|
return "get-overlays-stats-json";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getoverlaysstatsjson <outfile>\tgets stats for all overlays and writes to json file";
|
return "get-overlays-stats-json <outfile>\tgets stats for all overlays and writes to json file";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -969,10 +1004,11 @@ class SignCertificateQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "signcert";
|
return "sign-cert";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "signcert <overlayid> <adnlid> <expireat> <maxsize> <signwith> <outfile>\tsign overlay certificate by <signwith> key";
|
return "sign-cert <overlayid> <adnlid> <expireat> <maxsize> <signwith> <outfile>\tsign overlay certificate by "
|
||||||
|
"<signwith> key";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1005,10 +1041,10 @@ class ImportCertificateQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "importcert";
|
return "import-cert";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "importcert <overlayid> <adnlid> <key> <certfile>\timport overlay certificate for specific key";
|
return "import-cert <overlayid> <adnlid> <key> <certfile>\timport overlay certificate for specific key";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1030,10 +1066,11 @@ class SignShardOverlayCertificateQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "signshardoverlaycert";
|
return "sign-shard-overlay-cert";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "signshardoverlaycert <workchain> <shardprefix> <key> <expireat> <maxsize> <outfile>\tsign certificate for <key> in currently active shard overlay";
|
return "sign-shard-overlay-cert <wc>:<shard> <key> <expireat> <maxsize> <outfile>\tsign certificate "
|
||||||
|
"for <key> in currently active shard overlay";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1041,8 +1078,7 @@ class SignShardOverlayCertificateQuery : public Query {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
td::int32 wc_;
|
ton::ShardIdFull shard_;
|
||||||
td::int64 shard_;
|
|
||||||
td::int32 expire_at_;
|
td::int32 expire_at_;
|
||||||
ton::PublicKeyHash key_;
|
ton::PublicKeyHash key_;
|
||||||
td::uint32 max_size_;
|
td::uint32 max_size_;
|
||||||
|
@ -1059,10 +1095,11 @@ class ImportShardOverlayCertificateQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "importshardoverlaycert";
|
return "import-shard-overlay-cert";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "importshardoverlaycert <workchain> <shardprefix> <key> <certfile>\timport certificate for <key> in currently active shard overlay";
|
return "import-shard-overlay-cert <wc>:<shard> <key> <certfile>\timport certificate for <key> in "
|
||||||
|
"currently active shard overlay";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1070,8 +1107,7 @@ class ImportShardOverlayCertificateQuery : public Query {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
td::int32 wc_;
|
ton::ShardIdFull shard_;
|
||||||
td::int64 shard_;
|
|
||||||
ton::PublicKeyHash key_;
|
ton::PublicKeyHash key_;
|
||||||
std::string in_file_;
|
std::string in_file_;
|
||||||
};
|
};
|
||||||
|
@ -1085,10 +1121,10 @@ class GetActorStatsQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getactorstats";
|
return "get-actor-stats";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getactorstats [<outfile>]\tget actor stats and print it either in stdout or in <outfile>";
|
return "get-actor-stats [<outfile>]\tget actor stats and print it either in stdout or in <outfile>";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1107,10 +1143,11 @@ class GetPerfTimerStatsJsonQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getperftimerstatsjson";
|
return "get-perf-timer-stats-json";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getperftimerstatsjson <outfile>\tgets min, average and max event processing time for last 60, 300 and 3600 seconds and writes to json file";
|
return "get-perf-timer-stats-json <outfile>\tgets min, average and max event processing time for last 60, 300 and "
|
||||||
|
"3600 seconds and writes to json file";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1129,10 +1166,10 @@ class GetShardOutQueueSizeQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getshardoutqueuesize";
|
return "get-shard-out-queue-size";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getshardoutqueuesize <wc> <shard> <seqno> [<dest_wc> <dest_shard>]\treturns number of messages in the "
|
return "get-shard-out-queue-size <wc>:<shard> <seqno> [<dest_wc>:<dest_shard>]\treturns number of messages in the "
|
||||||
"queue of the given shard. Destination shard is optional.";
|
"queue of the given shard. Destination shard is optional.";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
|
@ -1141,7 +1178,7 @@ class GetShardOutQueueSizeQuery : public Query {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ton::BlockId block_id_;
|
ton::BlockId block_id_;
|
||||||
td::optional<ton::ShardIdFull> dest_;
|
ton::ShardIdFull dest_ = ton::ShardIdFull{ton::workchainInvalid};
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetExtMessagesBroadcastDisabledQuery : public Query {
|
class SetExtMessagesBroadcastDisabledQuery : public Query {
|
||||||
|
@ -1153,11 +1190,11 @@ class SetExtMessagesBroadcastDisabledQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "setextmessagesbroadcastdisabled";
|
return "set-ext-messages-broadcast-disabled";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "setextmessagesbroadcastdisabled <value>\tdisable broadcasting and rebroadcasting ext messages; value is 0 "
|
return "set-ext-messages-broadcast-disabled <value>\tdisable broadcasting and rebroadcasting ext messages; value "
|
||||||
"or 1.";
|
"is 0 or 1.";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1176,10 +1213,10 @@ class AddCustomOverlayQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "addcustomoverlay";
|
return "add-custom-overlay";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "addcustomoverlay <filename>\tadd custom overlay with config from file <filename>";
|
return "add-custom-overlay <filename>\tadd custom overlay with config from file <filename>";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1198,10 +1235,10 @@ class DelCustomOverlayQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "delcustomoverlay";
|
return "del-custom-overlay";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "delcustomoverlay <name>\tdelete custom overlay with name <name>";
|
return "del-custom-overlay <name>\tdelete custom overlay with name <name>";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1220,10 +1257,10 @@ class ShowCustomOverlaysQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "showcustomoverlays";
|
return "show-custom-overlays";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "showcustomoverlays\tshow all custom overlays";
|
return "show-custom-overlays\tshow all custom overlays";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1239,10 +1276,10 @@ class SetStateSerializerEnabledQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "setstateserializerenabled";
|
return "set-state-serializer-enabled";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "setstateserializerenabled <value>\tdisable or enable persistent state serializer; value is 0 or 1";
|
return "set-state-serializer-enabled <value>\tdisable or enable persistent state serializer; value is 0 or 1";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1261,10 +1298,10 @@ class SetCollatorOptionsJsonQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "setcollatoroptionsjson";
|
return "set-collator-options-json";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "setcollatoroptionsjson <filename>\tset collator options from file <filename>";
|
return "set-collator-options-json <filename>\tset collator options from file <filename>";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1283,10 +1320,10 @@ class ResetCollatorOptionsQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "resetcollatoroptions";
|
return "reset-collator-options";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "resetcollatoroptions\tset collator options to default values";
|
return "reset-collator-options\tset collator options to default values";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1302,10 +1339,10 @@ class GetCollatorOptionsJsonQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getcollatoroptionsjson";
|
return "get-collator-options-json";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getcollatoroptionsjson <filename>\tsave current collator options to file <filename>";
|
return "get-collator-options-json <filename>\tsave current collator options to file <filename>";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1324,11 +1361,11 @@ class GetAdnlStatsJsonQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getadnlstatsjson";
|
return "get-adnl-stats-json";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getadnlstatsjson <filename> [all]\tsave adnl stats to <filename>. all - returns all peers (default - only "
|
return "get-adnl-stats-json <filename> [all]\tsave adnl stats to <filename>. all - returns all peers (default - "
|
||||||
"peers with traffic in the last 10 minutes)";
|
"only peers with traffic in the last 10 minutes)";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1348,11 +1385,11 @@ class GetAdnlStatsQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "getadnlstats";
|
return "get-adnl-stats";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "getadnlstats [all]\tdisplay adnl stats. all - returns all peers (default - only peers with traffic in the "
|
return "get-adnl-stats [all]\tdisplay adnl stats. all - returns all peers (default - only peers with traffic in "
|
||||||
"last 10 minutes)";
|
"the last 10 minutes)";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
|
@ -1372,18 +1409,17 @@ class AddShardQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "addshard";
|
return "add-shard";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "addshard <workchain> <shard>\tstart monitoring shard";
|
return "add-shard <wc>:<shard>\tstart monitoring shard";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
td::int32 wc_;
|
ton::ShardIdFull shard_;
|
||||||
td::int64 shard_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DelShardQuery : public Query {
|
class DelShardQuery : public Query {
|
||||||
|
@ -1395,16 +1431,15 @@ class DelShardQuery : public Query {
|
||||||
td::Status send() override;
|
td::Status send() override;
|
||||||
td::Status receive(td::BufferSlice data) override;
|
td::Status receive(td::BufferSlice data) override;
|
||||||
static std::string get_name() {
|
static std::string get_name() {
|
||||||
return "delshard";
|
return "del-shard";
|
||||||
}
|
}
|
||||||
static std::string get_help() {
|
static std::string get_help() {
|
||||||
return "delshard <workchain> <shard>\tstop monitoring shard";
|
return "del-shard <wc>:<shard>\tstop monitoring shard";
|
||||||
}
|
}
|
||||||
std::string name() const override {
|
std::string name() const override {
|
||||||
return get_name();
|
return get_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
td::int32 wc_;
|
ton::ShardIdFull shard_;
|
||||||
td::int64 shard_;
|
|
||||||
};
|
};
|
|
@ -112,6 +112,7 @@ void ValidatorEngineConsole::run() {
|
||||||
add_query_runner(std::make_unique<QueryRunnerImpl<ExportPublicKeyFileQuery>>());
|
add_query_runner(std::make_unique<QueryRunnerImpl<ExportPublicKeyFileQuery>>());
|
||||||
add_query_runner(std::make_unique<QueryRunnerImpl<SignQuery>>());
|
add_query_runner(std::make_unique<QueryRunnerImpl<SignQuery>>());
|
||||||
add_query_runner(std::make_unique<QueryRunnerImpl<SignFileQuery>>());
|
add_query_runner(std::make_unique<QueryRunnerImpl<SignFileQuery>>());
|
||||||
|
add_query_runner(std::make_unique<QueryRunnerImpl<ExportAllPrivateKeysQuery>>());
|
||||||
add_query_runner(std::make_unique<QueryRunnerImpl<AddAdnlAddrQuery>>());
|
add_query_runner(std::make_unique<QueryRunnerImpl<AddAdnlAddrQuery>>());
|
||||||
add_query_runner(std::make_unique<QueryRunnerImpl<AddDhtIdQuery>>());
|
add_query_runner(std::make_unique<QueryRunnerImpl<AddDhtIdQuery>>());
|
||||||
add_query_runner(std::make_unique<QueryRunnerImpl<AddValidatorPermanentKeyQuery>>());
|
add_query_runner(std::make_unique<QueryRunnerImpl<AddValidatorPermanentKeyQuery>>());
|
||||||
|
@ -205,9 +206,8 @@ void ValidatorEngineConsole::show_help(std::string command, td::Promise<td::Buff
|
||||||
td::TerminalIO::out() << cmd.second->help() << "\n";
|
td::TerminalIO::out() << cmd.second->help() << "\n";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto it = query_runners_.find(command);
|
if (auto query = get_query(command)) {
|
||||||
if (it != query_runners_.end()) {
|
td::TerminalIO::out() << query->help() << "\n";
|
||||||
td::TerminalIO::out() << it->second->help() << "\n";
|
|
||||||
} else {
|
} else {
|
||||||
td::TerminalIO::out() << "unknown command '" << command << "'\n";
|
td::TerminalIO::out() << "unknown command '" << command << "'\n";
|
||||||
}
|
}
|
||||||
|
@ -231,10 +231,9 @@ void ValidatorEngineConsole::parse_line(td::BufferSlice data) {
|
||||||
}
|
}
|
||||||
auto name = tokenizer.get_token<std::string>().move_as_ok();
|
auto name = tokenizer.get_token<std::string>().move_as_ok();
|
||||||
|
|
||||||
auto it = query_runners_.find(name);
|
if (auto query = get_query(name)) {
|
||||||
if (it != query_runners_.end()) {
|
|
||||||
running_queries_++;
|
running_queries_++;
|
||||||
it->second->run(actor_id(this), std::move(tokenizer));
|
query->run(actor_id(this), std::move(tokenizer));
|
||||||
} else {
|
} else {
|
||||||
td::TerminalIO::out() << "unknown command '" << name << "'\n";
|
td::TerminalIO::out() << "unknown command '" << name << "'\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,9 +57,23 @@ class ValidatorEngineConsole : public td::actor::Actor {
|
||||||
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> make_callback();
|
std::unique_ptr<ton::adnl::AdnlExtClient::Callback> make_callback();
|
||||||
|
|
||||||
std::map<std::string, std::unique_ptr<QueryRunner>> query_runners_;
|
std::map<std::string, std::unique_ptr<QueryRunner>> query_runners_;
|
||||||
|
std::map<std::string, std::string> alternate_names_;
|
||||||
|
static std::string simplify_name(std::string name) {
|
||||||
|
std::erase_if(name, [](char c) { return c == '-'; });
|
||||||
|
return name;
|
||||||
|
}
|
||||||
void add_query_runner(std::unique_ptr<QueryRunner> runner) {
|
void add_query_runner(std::unique_ptr<QueryRunner> runner) {
|
||||||
auto name = runner->name();
|
auto name = runner->name();
|
||||||
query_runners_[name] = std::move(runner);
|
query_runners_[name] = std::move(runner);
|
||||||
|
alternate_names_[simplify_name(name)] = name;
|
||||||
|
}
|
||||||
|
QueryRunner* get_query(std::string name) {
|
||||||
|
auto it = alternate_names_.find(name);
|
||||||
|
if (it != alternate_names_.end()) {
|
||||||
|
name = it->second;
|
||||||
|
}
|
||||||
|
auto it2 = query_runners_.find(name);
|
||||||
|
return it2 == query_runners_.end() ? nullptr : it2->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1503,17 +1503,6 @@ td::Status ValidatorEngine::load_global_config() {
|
||||||
h.push_back(b);
|
h.push_back(b);
|
||||||
}
|
}
|
||||||
validator_options_.write().set_hardforks(std::move(h));
|
validator_options_.write().set_hardforks(std::move(h));
|
||||||
|
|
||||||
auto r_total_mem_stat = td::get_total_mem_stat();
|
|
||||||
if (r_total_mem_stat.is_error()) {
|
|
||||||
LOG(ERROR) << "Failed to get total RAM size: " << r_total_mem_stat.move_as_error();
|
|
||||||
} else {
|
|
||||||
td::uint64 total_ram = r_total_mem_stat.ok().total_ram;
|
|
||||||
LOG(WARNING) << "Total RAM = " << td::format::as_size(total_ram);
|
|
||||||
if (total_ram >= (90ULL << 30)) {
|
|
||||||
fast_state_serializer_enabled_ = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
validator_options_.write().set_fast_state_serializer_enabled(fast_state_serializer_enabled_);
|
validator_options_.write().set_fast_state_serializer_enabled(fast_state_serializer_enabled_);
|
||||||
|
|
||||||
return td::Status::OK();
|
return td::Status::OK();
|
||||||
|
@ -3333,6 +3322,70 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_sign &que
|
||||||
std::move(query.data_), std::move(P));
|
std::move(query.data_), std::move(P));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_exportAllPrivateKeys &query,
|
||||||
|
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
|
||||||
|
td::Promise<td::BufferSlice> promise) {
|
||||||
|
if (!(perm & ValidatorEnginePermissions::vep_unsafe)) {
|
||||||
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (keyring_.empty()) {
|
||||||
|
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started keyring")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ton::PublicKey client_pubkey = ton::PublicKey{query.encryption_key_};
|
||||||
|
if (!client_pubkey.is_ed25519()) {
|
||||||
|
promise.set_value(
|
||||||
|
create_control_query_error(td::Status::Error(ton::ErrorCode::protoviolation, "encryption key is not Ed25519")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
td::actor::send_closure(
|
||||||
|
keyring_, &ton::keyring::Keyring::export_all_private_keys,
|
||||||
|
[promise = std::move(promise),
|
||||||
|
client_pubkey = std::move(client_pubkey)](td::Result<std::vector<ton::PrivateKey>> R) mutable {
|
||||||
|
if (R.is_error()) {
|
||||||
|
promise.set_value(create_control_query_error(R.move_as_error()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Private keys are encrypted using client-provided public key to avoid storing them in
|
||||||
|
// non-secure buffers (not td::SecureString)
|
||||||
|
std::vector<td::SecureString> serialized_keys;
|
||||||
|
size_t data_size = 32;
|
||||||
|
for (const ton::PrivateKey &key : R.ok()) {
|
||||||
|
serialized_keys.push_back(key.export_as_slice());
|
||||||
|
data_size += serialized_keys.back().size() + 4;
|
||||||
|
}
|
||||||
|
td::SecureString data{data_size};
|
||||||
|
td::MutableSlice slice = data.as_mutable_slice();
|
||||||
|
for (const td::SecureString &s : serialized_keys) {
|
||||||
|
td::uint32 size = td::narrow_cast_safe<td::uint32>(s.size()).move_as_ok();
|
||||||
|
CHECK(slice.size() >= size + 4);
|
||||||
|
slice.copy_from(td::Slice{reinterpret_cast<const td::uint8 *>(&size), 4});
|
||||||
|
slice.remove_prefix(4);
|
||||||
|
slice.copy_from(s.as_slice());
|
||||||
|
slice.remove_prefix(s.size());
|
||||||
|
}
|
||||||
|
CHECK(slice.size() == 32);
|
||||||
|
td::Random::secure_bytes(slice);
|
||||||
|
|
||||||
|
auto r_encryptor = client_pubkey.create_encryptor();
|
||||||
|
if (r_encryptor.is_error()) {
|
||||||
|
promise.set_value(create_control_query_error(r_encryptor.move_as_error_prefix("cannot create encryptor: ")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto encryptor = r_encryptor.move_as_ok();
|
||||||
|
auto r_encrypted = encryptor->encrypt(data.as_slice());
|
||||||
|
if (r_encryptor.is_error()) {
|
||||||
|
promise.set_value(create_control_query_error(r_encrypted.move_as_error_prefix("cannot encrypt data: ")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
promise.set_value(ton::create_serialize_tl_object<ton::ton_api::engine_validator_exportedPrivateKeys>(
|
||||||
|
r_encrypted.move_as_ok()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_setVerbosity &query, td::BufferSlice data,
|
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_setVerbosity &query, td::BufferSlice data,
|
||||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise) {
|
||||||
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
if (!(perm & ValidatorEnginePermissions::vep_default)) {
|
||||||
|
@ -4489,7 +4542,7 @@ int main(int argc, char *argv[]) {
|
||||||
});
|
});
|
||||||
p.add_option(
|
p.add_option(
|
||||||
'\0', "fast-state-serializer",
|
'\0', "fast-state-serializer",
|
||||||
"faster persistent state serializer, but requires more RAM (enabled automatically on machines with >= 90GB RAM)",
|
"faster persistent state serializer, but requires more RAM",
|
||||||
[&]() {
|
[&]() {
|
||||||
acts.push_back(
|
acts.push_back(
|
||||||
[&x]() { td::actor::send_closure(x, &ValidatorEngine::set_fast_state_serializer_enabled, true); });
|
[&x]() { td::actor::send_closure(x, &ValidatorEngine::set_fast_state_serializer_enabled, true); });
|
||||||
|
|
|
@ -475,6 +475,8 @@ class ValidatorEngine : public td::actor::Actor {
|
||||||
td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||||
void run_control_query(ton::ton_api::engine_validator_sign &query, td::BufferSlice data, ton::PublicKeyHash src,
|
void run_control_query(ton::ton_api::engine_validator_sign &query, td::BufferSlice data, ton::PublicKeyHash src,
|
||||||
td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||||
|
void run_control_query(ton::ton_api::engine_validator_exportAllPrivateKeys &query, td::BufferSlice data,
|
||||||
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||||
void run_control_query(ton::ton_api::engine_validator_setVerbosity &query, td::BufferSlice data,
|
void run_control_query(ton::ton_api::engine_validator_setVerbosity &query, td::BufferSlice data,
|
||||||
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
|
||||||
void run_control_query(ton::ton_api::engine_validator_getStats &query, td::BufferSlice data, ton::PublicKeyHash src,
|
void run_control_query(ton::ton_api::engine_validator_getStats &query, td::BufferSlice data, ton::PublicKeyHash src,
|
||||||
|
|
|
@ -46,6 +46,7 @@ set(VALIDATOR_HEADERS
|
||||||
interfaces/db.h
|
interfaces/db.h
|
||||||
interfaces/external-message.h
|
interfaces/external-message.h
|
||||||
interfaces/liteserver.h
|
interfaces/liteserver.h
|
||||||
|
interfaces/out-msg-queue-proof.h
|
||||||
interfaces/proof.h
|
interfaces/proof.h
|
||||||
interfaces/shard.h
|
interfaces/shard.h
|
||||||
interfaces/signature-set.h
|
interfaces/signature-set.h
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "net/download-proof.hpp"
|
#include "net/download-proof.hpp"
|
||||||
#include "net/get-next-key-blocks.hpp"
|
#include "net/get-next-key-blocks.hpp"
|
||||||
#include "net/download-archive-slice.hpp"
|
#include "net/download-archive-slice.hpp"
|
||||||
|
#include "impl/out-msg-queue-proof.hpp"
|
||||||
|
|
||||||
#include "td/utils/Random.h"
|
#include "td/utils/Random.h"
|
||||||
|
|
||||||
|
@ -669,6 +670,62 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
|
||||||
query.offset_, query.max_size_, std::move(promise));
|
query.offset_, query.max_size_, std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getOutMsgQueueProof &query,
|
||||||
|
td::Promise<td::BufferSlice> promise) {
|
||||||
|
std::vector<BlockIdExt> blocks;
|
||||||
|
for (const auto &x : query.blocks_) {
|
||||||
|
BlockIdExt id = create_block_id(x);
|
||||||
|
if (!id.is_valid_ext()) {
|
||||||
|
promise.set_error(td::Status::Error("invalid block_id"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!shard_is_ancestor(shard_, id.shard_full())) {
|
||||||
|
promise.set_error(td::Status::Error("query in wrong overlay"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blocks.push_back(create_block_id(x));
|
||||||
|
}
|
||||||
|
ShardIdFull dst_shard = create_shard_id(query.dst_shard_);
|
||||||
|
if (!dst_shard.is_valid_ext()) {
|
||||||
|
promise.set_error(td::Status::Error("invalid shard"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
block::ImportedMsgQueueLimits limits{(td::uint32)query.limits_->max_bytes_, (td::uint32)query.limits_->max_msgs_};
|
||||||
|
if (limits.max_msgs > 512) {
|
||||||
|
promise.set_error(td::Status::Error("max_msgs is too big"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (limits.max_bytes > (1 << 21)) {
|
||||||
|
promise.set_error(td::Status::Error("max_bytes is too big"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FLOG(DEBUG) {
|
||||||
|
sb << "Got query getOutMsgQueueProof to shard " << dst_shard.to_str() << " from blocks";
|
||||||
|
for (const BlockIdExt &id : blocks) {
|
||||||
|
sb << " " << id.id.to_str();
|
||||||
|
}
|
||||||
|
sb << " from " << src;
|
||||||
|
};
|
||||||
|
td::actor::send_closure(
|
||||||
|
full_node_, &FullNode::get_out_msg_queue_query_token,
|
||||||
|
[=, manager = validator_manager_, blocks = std::move(blocks),
|
||||||
|
promise = std::move(promise)](td::Result<std::unique_ptr<ActionToken>> R) mutable {
|
||||||
|
TRY_RESULT_PROMISE(promise, token, std::move(R));
|
||||||
|
auto P =
|
||||||
|
td::PromiseCreator::lambda([promise = std::move(promise), token = std::move(token)](
|
||||||
|
td::Result<tl_object_ptr<ton_api::tonNode_outMsgQueueProof>> R) mutable {
|
||||||
|
if (R.is_error()) {
|
||||||
|
promise.set_result(create_serialize_tl_object<ton_api::tonNode_outMsgQueueProofEmpty>());
|
||||||
|
} else {
|
||||||
|
promise.set_result(serialize_tl_object(R.move_as_ok(), true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
td::actor::create_actor<BuildOutMsgQueueProof>("buildqueueproof", dst_shard, std::move(blocks), limits, manager,
|
||||||
|
std::move(P))
|
||||||
|
.release();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query,
|
void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query,
|
||||||
td::Promise<td::BufferSlice> promise) {
|
td::Promise<td::BufferSlice> promise) {
|
||||||
if (!active_) {
|
if (!active_) {
|
||||||
|
@ -944,6 +1001,47 @@ void FullNodeShardImpl::download_archive(BlockSeqno masterchain_seqno, ShardIdFu
|
||||||
.release();
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FullNodeShardImpl::download_out_msg_queue_proof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits, td::Timestamp timeout,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) {
|
||||||
|
// TODO: maybe more complex download (like other requests here)
|
||||||
|
auto &b = choose_neighbour();
|
||||||
|
if (b.adnl_id == adnl::AdnlNodeIdShort::zero()) {
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::notready, "no nodes"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> blocks_tl;
|
||||||
|
for (const BlockIdExt &id : blocks) {
|
||||||
|
blocks_tl.push_back(create_tl_block_id(id));
|
||||||
|
}
|
||||||
|
td::BufferSlice query = create_serialize_tl_object<ton_api::tonNode_getOutMsgQueueProof>(
|
||||||
|
create_tl_shard_id(dst_shard), std::move(blocks_tl),
|
||||||
|
create_tl_object<ton_api::tonNode_importedMsgQueueLimits>(limits.max_bytes, limits.max_msgs));
|
||||||
|
|
||||||
|
auto P = td::PromiseCreator::lambda(
|
||||||
|
[=, promise = std::move(promise), blocks = std::move(blocks)](td::Result<td::BufferSlice> R) mutable {
|
||||||
|
if (R.is_error()) {
|
||||||
|
promise.set_result(R.move_as_error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TRY_RESULT_PROMISE(promise, f, fetch_tl_object<ton_api::tonNode_OutMsgQueueProof>(R.move_as_ok(), true));
|
||||||
|
ton_api::downcast_call(
|
||||||
|
*f, td::overloaded(
|
||||||
|
[&](ton_api::tonNode_outMsgQueueProofEmpty &x) {
|
||||||
|
promise.set_error(td::Status::Error("node doesn't have this block"));
|
||||||
|
},
|
||||||
|
[&](ton_api::tonNode_outMsgQueueProof &x) {
|
||||||
|
delay_action(
|
||||||
|
[=, promise = std::move(promise), blocks = std::move(blocks), x = std::move(x)]() mutable {
|
||||||
|
promise.set_result(OutMsgQueueProof::fetch(dst_shard, blocks, limits, x));
|
||||||
|
},
|
||||||
|
td::Timestamp::now());
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, b.adnl_id, adnl_id_, overlay_id_,
|
||||||
|
"get_msg_queue", std::move(P), timeout, std::move(query), 1 << 22, rldp_);
|
||||||
|
}
|
||||||
|
|
||||||
void FullNodeShardImpl::set_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
|
void FullNodeShardImpl::set_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
|
||||||
CHECK(!handle_);
|
CHECK(!handle_);
|
||||||
handle_ = std::move(handle);
|
handle_ = std::move(handle);
|
||||||
|
|
|
@ -66,6 +66,9 @@ class FullNodeShard : public td::actor::Actor {
|
||||||
td::Promise<std::vector<BlockIdExt>> promise) = 0;
|
td::Promise<std::vector<BlockIdExt>> promise) = 0;
|
||||||
virtual void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
virtual void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
|
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
|
||||||
|
virtual void download_out_msg_queue_proof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits, td::Timestamp timeout,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) = 0;
|
||||||
|
|
||||||
virtual void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
|
virtual void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
|
||||||
|
|
||||||
|
|
|
@ -139,8 +139,8 @@ class FullNodeShardImpl : public FullNodeShard {
|
||||||
td::Promise<td::BufferSlice> promise);
|
td::Promise<td::BufferSlice> promise);
|
||||||
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveSlice &query,
|
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveSlice &query,
|
||||||
td::Promise<td::BufferSlice> promise);
|
td::Promise<td::BufferSlice> promise);
|
||||||
// void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareNextKeyBlockProof &query,
|
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getOutMsgQueueProof &query,
|
||||||
// td::Promise<td::BufferSlice> promise);
|
td::Promise<td::BufferSlice> promise);
|
||||||
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
|
||||||
void receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data);
|
void receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data);
|
||||||
|
|
||||||
|
@ -183,6 +183,9 @@ class FullNodeShardImpl : public FullNodeShard {
|
||||||
td::Promise<std::vector<BlockIdExt>> promise) override;
|
td::Promise<std::vector<BlockIdExt>> promise) override;
|
||||||
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise) override;
|
td::Timestamp timeout, td::Promise<std::string> promise) override;
|
||||||
|
void download_out_msg_queue_proof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits, td::Timestamp timeout,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) override;
|
||||||
|
|
||||||
void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
|
void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "td/actor/MultiPromise.h"
|
#include "td/actor/MultiPromise.h"
|
||||||
#include "full-node.h"
|
#include "full-node.h"
|
||||||
#include "common/delay.h"
|
#include "common/delay.h"
|
||||||
|
#include "impl/out-msg-queue-proof.hpp"
|
||||||
#include "td/utils/Random.h"
|
#include "td/utils/Random.h"
|
||||||
#include "ton/ton-tl.hpp"
|
#include "ton/ton-tl.hpp"
|
||||||
|
|
||||||
|
@ -430,6 +431,24 @@ void FullNodeImpl::download_archive(BlockSeqno masterchain_seqno, ShardIdFull sh
|
||||||
timeout, std::move(promise));
|
timeout, std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FullNodeImpl::download_out_msg_queue_proof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits, td::Timestamp timeout,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) {
|
||||||
|
if (blocks.empty()) {
|
||||||
|
promise.set_value({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// All blocks are expected to have the same minsplit shard prefix
|
||||||
|
auto shard = get_shard(blocks[0].shard_full());
|
||||||
|
if (shard.empty()) {
|
||||||
|
VLOG(FULL_NODE_WARNING) << "dropping download msg queue query to unknown shard";
|
||||||
|
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
td::actor::send_closure(shard, &FullNodeShard::download_out_msg_queue_proof, dst_shard, std::move(blocks), limits,
|
||||||
|
timeout, std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(ShardIdFull shard) {
|
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(ShardIdFull shard) {
|
||||||
if (shard.is_masterchain()) {
|
if (shard.is_masterchain()) {
|
||||||
return shards_[ShardIdFull{masterchainId}].actor.get();
|
return shards_[ShardIdFull{masterchainId}].actor.get();
|
||||||
|
@ -557,6 +576,11 @@ void FullNodeImpl::process_block_candidate_broadcast(BlockIdExt block_id, Catcha
|
||||||
std::move(data));
|
std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FullNodeImpl::get_out_msg_queue_query_token(td::Promise<std::unique_ptr<ActionToken>> promise) {
|
||||||
|
td::actor::send_closure(out_msg_queue_query_token_manager_, &TokenManager::get_token, 1, 0, td::Timestamp::in(10.0),
|
||||||
|
std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
void FullNodeImpl::set_validator_telemetry_filename(std::string value) {
|
void FullNodeImpl::set_validator_telemetry_filename(std::string value) {
|
||||||
validator_telemetry_filename_ = std::move(value);
|
validator_telemetry_filename_ = std::move(value);
|
||||||
update_validator_telemetry_collector();
|
update_validator_telemetry_collector();
|
||||||
|
@ -645,6 +669,12 @@ void FullNodeImpl::start_up() {
|
||||||
td::actor::send_closure(id_, &FullNodeImpl::download_archive, masterchain_seqno, shard_prefix, std::move(tmp_dir),
|
td::actor::send_closure(id_, &FullNodeImpl::download_archive, masterchain_seqno, shard_prefix, std::move(tmp_dir),
|
||||||
timeout, std::move(promise));
|
timeout, std::move(promise));
|
||||||
}
|
}
|
||||||
|
void download_out_msg_queue_proof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits, td::Timestamp timeout,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) override {
|
||||||
|
td::actor::send_closure(id_, &FullNodeImpl::download_out_msg_queue_proof, dst_shard, std::move(blocks), limits,
|
||||||
|
timeout, std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
void new_key_block(BlockHandle handle) override {
|
void new_key_block(BlockHandle handle) override {
|
||||||
td::actor::send_closure(id_, &FullNodeImpl::new_key_block, std::move(handle));
|
td::actor::send_closure(id_, &FullNodeImpl::new_key_block, std::move(handle));
|
||||||
|
|
|
@ -91,6 +91,7 @@ class FullNode : public td::actor::Actor {
|
||||||
virtual void process_block_broadcast(BlockBroadcast broadcast) = 0;
|
virtual void process_block_broadcast(BlockBroadcast broadcast) = 0;
|
||||||
virtual void process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno,
|
virtual void process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno,
|
||||||
td::uint32 validator_set_hash, td::BufferSlice data) = 0;
|
td::uint32 validator_set_hash, td::BufferSlice data) = 0;
|
||||||
|
virtual void get_out_msg_queue_query_token(td::Promise<std::unique_ptr<ActionToken>> promise) = 0;
|
||||||
|
|
||||||
virtual void set_validator_telemetry_filename(std::string value) = 0;
|
virtual void set_validator_telemetry_filename(std::string value) = 0;
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <token-manager.h>
|
||||||
|
|
||||||
namespace ton {
|
namespace ton {
|
||||||
|
|
||||||
|
@ -79,6 +80,9 @@ class FullNodeImpl : public FullNode {
|
||||||
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout, td::Promise<std::vector<BlockIdExt>> promise);
|
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout, td::Promise<std::vector<BlockIdExt>> promise);
|
||||||
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise);
|
td::Timestamp timeout, td::Promise<std::string> promise);
|
||||||
|
void download_out_msg_queue_proof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits, td::Timestamp timeout,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise);
|
||||||
|
|
||||||
void got_key_block_config(td::Ref<ConfigHolder> config);
|
void got_key_block_config(td::Ref<ConfigHolder> config);
|
||||||
void new_key_block(BlockHandle handle);
|
void new_key_block(BlockHandle handle);
|
||||||
|
@ -87,6 +91,7 @@ class FullNodeImpl : public FullNode {
|
||||||
void process_block_broadcast(BlockBroadcast broadcast) override;
|
void process_block_broadcast(BlockBroadcast broadcast) override;
|
||||||
void process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
void process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
|
||||||
td::BufferSlice data) override;
|
td::BufferSlice data) override;
|
||||||
|
void get_out_msg_queue_query_token(td::Promise<std::unique_ptr<ActionToken>> promise) override;
|
||||||
|
|
||||||
void set_validator_telemetry_filename(std::string value) override;
|
void set_validator_telemetry_filename(std::string value) override;
|
||||||
|
|
||||||
|
@ -160,6 +165,9 @@ class FullNodeImpl : public FullNode {
|
||||||
PublicKeyHash validator_telemetry_collector_key_ = PublicKeyHash::zero();
|
PublicKeyHash validator_telemetry_collector_key_ = PublicKeyHash::zero();
|
||||||
|
|
||||||
void update_validator_telemetry_collector();
|
void update_validator_telemetry_collector();
|
||||||
|
|
||||||
|
td::actor::ActorOwn<TokenManager> out_msg_queue_query_token_manager_ =
|
||||||
|
td::actor::create_actor<TokenManager>("tokens", /* max_tokens = */ 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fullnode
|
} // namespace fullnode
|
||||||
|
|
|
@ -16,6 +16,7 @@ set(TON_VALIDATOR_SOURCE
|
||||||
ihr-message.cpp
|
ihr-message.cpp
|
||||||
liteserver.cpp
|
liteserver.cpp
|
||||||
message-queue.cpp
|
message-queue.cpp
|
||||||
|
out-msg-queue-proof.cpp
|
||||||
proof.cpp
|
proof.cpp
|
||||||
shard.cpp
|
shard.cpp
|
||||||
signature-set.cpp
|
signature-set.cpp
|
||||||
|
@ -35,6 +36,7 @@ set(TON_VALIDATOR_SOURCE
|
||||||
liteserver.hpp
|
liteserver.hpp
|
||||||
liteserver-cache.hpp
|
liteserver-cache.hpp
|
||||||
message-queue.hpp
|
message-queue.hpp
|
||||||
|
out-msg-queue-proof.hpp
|
||||||
proof.hpp
|
proof.hpp
|
||||||
shard.hpp
|
shard.hpp
|
||||||
signature-set.hpp
|
signature-set.hpp
|
||||||
|
|
294
validator/impl/out-msg-queue-proof.cpp
Normal file
294
validator/impl/out-msg-queue-proof.cpp
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "out-msg-queue-proof.hpp"
|
||||||
|
#include "interfaces/proof.h"
|
||||||
|
#include "shard.hpp"
|
||||||
|
#include "vm/cells/MerkleProof.h"
|
||||||
|
#include "common/delay.h"
|
||||||
|
#include "interfaces/validator-manager.h"
|
||||||
|
#include "block/block-parse.h"
|
||||||
|
#include "block/block-auto.h"
|
||||||
|
#include "output-queue-merger.h"
|
||||||
|
|
||||||
|
namespace ton {
|
||||||
|
|
||||||
|
namespace validator {
|
||||||
|
|
||||||
|
static td::Status check_no_prunned(const Ref<vm::Cell>& cell) {
|
||||||
|
if (cell.is_null()) {
|
||||||
|
return td::Status::OK();
|
||||||
|
}
|
||||||
|
TRY_RESULT(loaded_cell, cell->load_cell());
|
||||||
|
if (loaded_cell.data_cell->get_level() > 0) {
|
||||||
|
return td::Status::Error("prunned branch");
|
||||||
|
}
|
||||||
|
return td::Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
static td::Status check_no_prunned(const vm::CellSlice& cs) {
|
||||||
|
for (unsigned i = 0; i < cs.size_refs(); ++i) {
|
||||||
|
TRY_STATUS(check_no_prunned(cs.prefetch_ref(i)));
|
||||||
|
}
|
||||||
|
return td::Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
static td::Result<std::vector<td::int32>> process_queue(
|
||||||
|
ShardIdFull dst_shard, std::vector<std::pair<BlockIdExt, block::gen::OutMsgQueueInfo::Record>> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits) {
|
||||||
|
td::uint64 estimated_proof_size = 0;
|
||||||
|
|
||||||
|
td::HashSet<vm::Cell::Hash> visited;
|
||||||
|
std::function<void(const vm::CellSlice&)> dfs_cs;
|
||||||
|
auto dfs = [&](const Ref<vm::Cell>& cell) {
|
||||||
|
if (cell.is_null() || !visited.insert(cell->get_hash()).second) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dfs_cs(vm::CellSlice(vm::NoVm(), cell));
|
||||||
|
};
|
||||||
|
dfs_cs = [&](const vm::CellSlice& cs) {
|
||||||
|
// Based on BlockLimitStatus::estimate_block_size
|
||||||
|
estimated_proof_size += 12 + (cs.size() + 7) / 8 + cs.size_refs() * 3;
|
||||||
|
for (unsigned i = 0; i < cs.size_refs(); i++) {
|
||||||
|
dfs(cs.prefetch_ref(i));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::vector<block::OutputQueueMerger::Neighbor> neighbors;
|
||||||
|
for (auto& b : blocks) {
|
||||||
|
TRY_STATUS_PREFIX(check_no_prunned(*b.second.proc_info), "invalid proc_info proof: ")
|
||||||
|
dfs_cs(*b.second.proc_info);
|
||||||
|
neighbors.emplace_back(b.first, b.second.out_queue->prefetch_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
block::OutputQueueMerger queue_merger{dst_shard, std::move(neighbors)};
|
||||||
|
std::vector<td::int32> msg_count(blocks.size());
|
||||||
|
td::int32 msg_count_total = 0;
|
||||||
|
bool limit_reached = false;
|
||||||
|
|
||||||
|
while (!queue_merger.is_eof()) {
|
||||||
|
auto kv = queue_merger.extract_cur();
|
||||||
|
queue_merger.next();
|
||||||
|
block::EnqueuedMsgDescr enq;
|
||||||
|
auto msg = kv->msg;
|
||||||
|
if (!enq.unpack(msg.write())) {
|
||||||
|
return td::Status::Error("cannot unpack EnqueuedMsgDescr");
|
||||||
|
}
|
||||||
|
if (limit_reached) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++msg_count[kv->source];
|
||||||
|
++msg_count_total;
|
||||||
|
|
||||||
|
dfs_cs(*kv->msg);
|
||||||
|
TRY_STATUS_PREFIX(check_no_prunned(*kv->msg), "invalid message proof: ")
|
||||||
|
if (estimated_proof_size >= limits.max_bytes || msg_count_total >= (long long)limits.max_msgs) {
|
||||||
|
limit_reached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!limit_reached) {
|
||||||
|
std::fill(msg_count.begin(), msg_count.end(), -1);
|
||||||
|
}
|
||||||
|
return msg_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
td::Result<tl_object_ptr<ton_api::tonNode_outMsgQueueProof>> OutMsgQueueProof::build(
|
||||||
|
ShardIdFull dst_shard, std::vector<OneBlock> blocks, block::ImportedMsgQueueLimits limits) {
|
||||||
|
if (!dst_shard.is_valid_ext()) {
|
||||||
|
return td::Status::Error("invalid shard");
|
||||||
|
}
|
||||||
|
if (blocks.empty()) {
|
||||||
|
return create_tl_object<ton_api::tonNode_outMsgQueueProof>(td::BufferSlice{}, td::BufferSlice{},
|
||||||
|
std::vector<td::int32>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<td::Ref<vm::Cell>> block_state_proofs;
|
||||||
|
for (auto& block : blocks) {
|
||||||
|
if (block.id.seqno() != 0) {
|
||||||
|
if (block.block_root.is_null()) {
|
||||||
|
return td::Status::Error("block is null");
|
||||||
|
}
|
||||||
|
TRY_RESULT(proof, create_block_state_proof(block.block_root));
|
||||||
|
block_state_proofs.push_back(std::move(proof));
|
||||||
|
}
|
||||||
|
if (!block::ShardConfig::is_neighbor(dst_shard, block.id.shard_full())) {
|
||||||
|
return td::Status::Error("shards are not neighbors");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRY_RESULT(block_state_proof, vm::std_boc_serialize_multi(block_state_proofs));
|
||||||
|
|
||||||
|
vm::Dictionary states_dict_pure{32};
|
||||||
|
for (size_t i = 0; i < blocks.size(); ++i) {
|
||||||
|
if (blocks[i].state_root.is_null()) {
|
||||||
|
return td::Status::Error("state is null");
|
||||||
|
}
|
||||||
|
states_dict_pure.set_ref(td::BitArray<32>{(long long)i}, blocks[i].state_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
vm::MerkleProofBuilder mpb{states_dict_pure.get_root_cell()};
|
||||||
|
vm::Dictionary states_dict{mpb.root(), 32};
|
||||||
|
std::vector<std::pair<BlockIdExt, block::gen::OutMsgQueueInfo::Record>> data(blocks.size());
|
||||||
|
for (size_t i = 0; i < blocks.size(); ++i) {
|
||||||
|
data[i].first = blocks[i].id;
|
||||||
|
TRY_RESULT(state, ShardStateQ::fetch(blocks[i].id, {}, states_dict.lookup_ref(td::BitArray<32>{(long long)i})));
|
||||||
|
TRY_RESULT(outq_descr, state->message_queue());
|
||||||
|
block::gen::OutMsgQueueInfo::Record qinfo;
|
||||||
|
if (!tlb::unpack_cell(outq_descr->root_cell(), data[i].second)) {
|
||||||
|
return td::Status::Error("invalid message queue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRY_RESULT(msg_count, process_queue(dst_shard, std::move(data), limits));
|
||||||
|
|
||||||
|
TRY_RESULT(proof, mpb.extract_proof());
|
||||||
|
vm::Dictionary states_dict_proof{vm::CellSlice{vm::NoVm(), proof}.prefetch_ref(), 32};
|
||||||
|
std::vector<td::Ref<vm::Cell>> state_proofs;
|
||||||
|
for (size_t i = 0; i < blocks.size(); ++i) {
|
||||||
|
td::Ref<vm::Cell> proof_raw = states_dict_proof.lookup_ref(td::BitArray<32>{(long long)i});
|
||||||
|
CHECK(proof_raw.not_null());
|
||||||
|
state_proofs.push_back(vm::CellBuilder::create_merkle_proof(proof_raw));
|
||||||
|
}
|
||||||
|
TRY_RESULT(queue_proof, vm::std_boc_serialize_multi(state_proofs));
|
||||||
|
return create_tl_object<ton_api::tonNode_outMsgQueueProof>(std::move(queue_proof), std::move(block_state_proof),
|
||||||
|
std::move(msg_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
td::Result<std::vector<td::Ref<OutMsgQueueProof>>> OutMsgQueueProof::fetch(ShardIdFull dst_shard,
|
||||||
|
std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits,
|
||||||
|
const ton_api::tonNode_outMsgQueueProof& f) {
|
||||||
|
try {
|
||||||
|
std::vector<td::Ref<OutMsgQueueProof>> res;
|
||||||
|
TRY_RESULT(queue_proofs, vm::std_boc_deserialize_multi(f.queue_proofs_, (int)blocks.size()));
|
||||||
|
TRY_RESULT(block_state_proofs, vm::std_boc_deserialize_multi(f.block_state_proofs_, (int)blocks.size()));
|
||||||
|
if (queue_proofs.size() != blocks.size()) {
|
||||||
|
return td::Status::Error("invalid size of queue_proofs");
|
||||||
|
}
|
||||||
|
if (f.msg_counts_.size() != blocks.size()) {
|
||||||
|
return td::Status::Error("invalid size of msg_counts");
|
||||||
|
}
|
||||||
|
size_t j = 0;
|
||||||
|
std::vector<std::pair<BlockIdExt, block::gen::OutMsgQueueInfo::Record>> data(blocks.size());
|
||||||
|
for (size_t i = 0; i < blocks.size(); ++i) {
|
||||||
|
td::Bits256 state_root_hash;
|
||||||
|
Ref<vm::Cell> block_state_proof = {};
|
||||||
|
if (blocks[i].seqno() == 0) {
|
||||||
|
state_root_hash = blocks[i].root_hash;
|
||||||
|
} else {
|
||||||
|
if (j == block_state_proofs.size()) {
|
||||||
|
return td::Status::Error("invalid size of block_state_proofs");
|
||||||
|
}
|
||||||
|
block_state_proof = block_state_proofs[j++];
|
||||||
|
TRY_RESULT_ASSIGN(state_root_hash, unpack_block_state_proof(blocks[i], block_state_proof));
|
||||||
|
}
|
||||||
|
auto state_root = vm::MerkleProof::virtualize(queue_proofs[i], 1);
|
||||||
|
if (state_root->get_hash().as_slice() != state_root_hash.as_slice()) {
|
||||||
|
return td::Status::Error("state root hash mismatch");
|
||||||
|
}
|
||||||
|
res.emplace_back(true, blocks[i], state_root, block_state_proof, f.msg_counts_[i]);
|
||||||
|
|
||||||
|
data[i].first = blocks[i];
|
||||||
|
TRY_RESULT(state, ShardStateQ::fetch(blocks[i], {}, state_root));
|
||||||
|
TRY_RESULT(outq_descr, state->message_queue());
|
||||||
|
block::gen::OutMsgQueueInfo::Record qinfo;
|
||||||
|
if (!tlb::unpack_cell(outq_descr->root_cell(), data[i].second)) {
|
||||||
|
return td::Status::Error("invalid message queue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j != block_state_proofs.size()) {
|
||||||
|
return td::Status::Error("invalid size of block_state_proofs");
|
||||||
|
}
|
||||||
|
TRY_RESULT(msg_count, process_queue(dst_shard, std::move(data), limits));
|
||||||
|
if (msg_count != f.msg_counts_) {
|
||||||
|
return td::Status::Error("incorrect msg_count");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} catch (vm::VmVirtError& err) {
|
||||||
|
return td::Status::Error(PSTRING() << "invalid proof: " << err.get_msg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildOutMsgQueueProof::abort_query(td::Status reason) {
|
||||||
|
if (promise_) {
|
||||||
|
FLOG(DEBUG) {
|
||||||
|
sb << "failed to build msg queue proof to " << dst_shard_.to_str() << " from";
|
||||||
|
for (const auto& block : blocks_) {
|
||||||
|
sb << " " << block.id.id.to_str();
|
||||||
|
}
|
||||||
|
sb << ": " << reason;
|
||||||
|
};
|
||||||
|
promise_.set_error(
|
||||||
|
reason.move_as_error_prefix(PSTRING() << "failed to build msg queue proof to " << dst_shard_.to_str() << ": "));
|
||||||
|
}
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildOutMsgQueueProof::start_up() {
|
||||||
|
for (size_t i = 0; i < blocks_.size(); ++i) {
|
||||||
|
BlockIdExt id = blocks_[i].id;
|
||||||
|
++pending;
|
||||||
|
td::actor::send_closure(manager_, &ValidatorManagerInterface::get_shard_state_from_db_short, id,
|
||||||
|
[SelfId = actor_id(this), i](td::Result<Ref<ShardState>> R) {
|
||||||
|
if (R.is_error()) {
|
||||||
|
td::actor::send_closure(SelfId, &BuildOutMsgQueueProof::abort_query,
|
||||||
|
R.move_as_error_prefix("failed to get shard state: "));
|
||||||
|
} else {
|
||||||
|
td::actor::send_closure(SelfId, &BuildOutMsgQueueProof::got_state_root, i,
|
||||||
|
R.move_as_ok()->root_cell());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (id.seqno() != 0) {
|
||||||
|
++pending;
|
||||||
|
td::actor::send_closure(manager_, &ValidatorManagerInterface::get_block_data_from_db_short, id,
|
||||||
|
[SelfId = actor_id(this), i](td::Result<Ref<BlockData>> R) {
|
||||||
|
if (R.is_error()) {
|
||||||
|
td::actor::send_closure(SelfId, &BuildOutMsgQueueProof::abort_query,
|
||||||
|
R.move_as_error_prefix("failed to get block data: "));
|
||||||
|
} else {
|
||||||
|
td::actor::send_closure(SelfId, &BuildOutMsgQueueProof::got_block_root, i,
|
||||||
|
R.move_as_ok()->root_cell());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pending == 0) {
|
||||||
|
build_proof();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildOutMsgQueueProof::got_state_root(size_t i, Ref<vm::Cell> root) {
|
||||||
|
blocks_[i].state_root = std::move(root);
|
||||||
|
if (--pending == 0) {
|
||||||
|
build_proof();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildOutMsgQueueProof::got_block_root(size_t i, Ref<vm::Cell> root) {
|
||||||
|
blocks_[i].block_root = std::move(root);
|
||||||
|
if (--pending == 0) {
|
||||||
|
build_proof();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildOutMsgQueueProof::build_proof() {
|
||||||
|
auto result = OutMsgQueueProof::build(dst_shard_, std::move(blocks_), limits_);
|
||||||
|
if (result.is_error()) {
|
||||||
|
LOG(ERROR) << "Failed to build msg queue proof: " << result.error();
|
||||||
|
}
|
||||||
|
promise_.set_result(std::move(result));
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace validator
|
||||||
|
} // namespace ton
|
64
validator/impl/out-msg-queue-proof.hpp
Normal file
64
validator/impl/out-msg-queue-proof.hpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "vm/cells.h"
|
||||||
|
#include "ton/ton-types.h"
|
||||||
|
#include "auto/tl/ton_api.h"
|
||||||
|
#include "interfaces/out-msg-queue-proof.h"
|
||||||
|
#include "td/actor/actor.h"
|
||||||
|
#include "interfaces/shard.h"
|
||||||
|
#include "validator.h"
|
||||||
|
|
||||||
|
namespace ton {
|
||||||
|
|
||||||
|
namespace validator {
|
||||||
|
using td::Ref;
|
||||||
|
|
||||||
|
class ValidatorManager;
|
||||||
|
class ValidatorManagerInterface;
|
||||||
|
|
||||||
|
class BuildOutMsgQueueProof : public td::actor::Actor {
|
||||||
|
public:
|
||||||
|
BuildOutMsgQueueProof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks, block::ImportedMsgQueueLimits limits,
|
||||||
|
td::actor::ActorId<ValidatorManagerInterface> manager,
|
||||||
|
td::Promise<tl_object_ptr<ton_api::tonNode_outMsgQueueProof>> promise)
|
||||||
|
: dst_shard_(dst_shard), limits_(limits), manager_(manager), promise_(std::move(promise)) {
|
||||||
|
blocks_.resize(blocks.size());
|
||||||
|
for (size_t i = 0; i < blocks_.size(); ++i) {
|
||||||
|
blocks_[i].id = blocks[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void abort_query(td::Status reason);
|
||||||
|
void start_up() override;
|
||||||
|
void got_state_root(size_t i, Ref<vm::Cell> root);
|
||||||
|
void got_block_root(size_t i, Ref<vm::Cell> root);
|
||||||
|
void build_proof();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ShardIdFull dst_shard_;
|
||||||
|
std::vector<OutMsgQueueProof::OneBlock> blocks_;
|
||||||
|
block::ImportedMsgQueueLimits limits_;
|
||||||
|
|
||||||
|
td::actor::ActorId<ValidatorManagerInterface> manager_;
|
||||||
|
td::Promise<tl_object_ptr<ton_api::tonNode_outMsgQueueProof>> promise_;
|
||||||
|
|
||||||
|
size_t pending = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace validator
|
||||||
|
} // namespace ton
|
|
@ -162,5 +162,40 @@ td::Result<Ref<vm::Cell>> ProofQ::get_signatures_root() const {
|
||||||
return proof.signatures->prefetch_ref();
|
return proof.signatures->prefetch_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td::Result<td::Ref<vm::Cell>> create_block_state_proof(td::Ref<vm::Cell> root) {
|
||||||
|
if (root.is_null()) {
|
||||||
|
return td::Status::Error("root is null");
|
||||||
|
}
|
||||||
|
vm::MerkleProofBuilder mpb{std::move(root)};
|
||||||
|
block::gen::Block::Record block;
|
||||||
|
if (!tlb::unpack_cell(mpb.root(), block) || block.state_update->load_cell().is_error()) {
|
||||||
|
return td::Status::Error("invalid block");
|
||||||
|
}
|
||||||
|
TRY_RESULT(proof, mpb.extract_proof());
|
||||||
|
if (proof.is_null()) {
|
||||||
|
return td::Status::Error("failed to create proof");
|
||||||
|
}
|
||||||
|
return proof;
|
||||||
|
}
|
||||||
|
|
||||||
|
td::Result<RootHash> unpack_block_state_proof(BlockIdExt block_id, td::Ref<vm::Cell> proof) {
|
||||||
|
auto virt_root = vm::MerkleProof::virtualize(proof, 1);
|
||||||
|
if (virt_root.is_null()) {
|
||||||
|
return td::Status::Error("invalid Merkle proof");
|
||||||
|
}
|
||||||
|
if (virt_root->get_hash().as_slice() != block_id.root_hash.as_slice()) {
|
||||||
|
return td::Status::Error("hash mismatch");
|
||||||
|
}
|
||||||
|
block::gen::Block::Record block;
|
||||||
|
if (!tlb::unpack_cell(virt_root, block)) {
|
||||||
|
return td::Status::Error("invalid block");
|
||||||
|
}
|
||||||
|
vm::CellSlice upd_cs{vm::NoVmSpec(), block.state_update};
|
||||||
|
if (!(upd_cs.is_special() && upd_cs.prefetch_long(8) == 4 && upd_cs.size_ext() == 0x20228)) {
|
||||||
|
return td::Status::Error("invalid Merkle update");
|
||||||
|
}
|
||||||
|
return upd_cs.prefetch_ref(1)->get_hash(0).bits();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|
57
validator/interfaces/out-msg-queue-proof.h
Normal file
57
validator/interfaces/out-msg-queue-proof.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "vm/cells.h"
|
||||||
|
#include "ton/ton-types.h"
|
||||||
|
#include "auto/tl/ton_api.h"
|
||||||
|
#include "block/block.h"
|
||||||
|
|
||||||
|
namespace ton {
|
||||||
|
|
||||||
|
namespace validator {
|
||||||
|
using td::Ref;
|
||||||
|
|
||||||
|
struct OutMsgQueueProof : public td::CntObject {
|
||||||
|
OutMsgQueueProof(BlockIdExt block_id, Ref<vm::Cell> state_root, Ref<vm::Cell> block_state_proof,
|
||||||
|
td::int32 msg_count = -1)
|
||||||
|
: block_id_(block_id)
|
||||||
|
, state_root_(std::move(state_root))
|
||||||
|
, block_state_proof_(std::move(block_state_proof))
|
||||||
|
, msg_count_(msg_count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockIdExt block_id_;
|
||||||
|
Ref<vm::Cell> state_root_;
|
||||||
|
Ref<vm::Cell> block_state_proof_;
|
||||||
|
td::int32 msg_count_; // -1 - no limit
|
||||||
|
|
||||||
|
static td::Result<std::vector<td::Ref<OutMsgQueueProof>>> fetch(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits,
|
||||||
|
const ton_api::tonNode_outMsgQueueProof &f);
|
||||||
|
|
||||||
|
struct OneBlock {
|
||||||
|
BlockIdExt id;
|
||||||
|
Ref<vm::Cell> state_root;
|
||||||
|
Ref<vm::Cell> block_root;
|
||||||
|
};
|
||||||
|
static td::Result<tl_object_ptr<ton_api::tonNode_outMsgQueueProof>> build(ShardIdFull dst_shard,
|
||||||
|
std::vector<OneBlock> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace validator
|
||||||
|
} // namespace ton
|
|
@ -48,6 +48,9 @@ class Proof : virtual public ProofLink {
|
||||||
virtual td::Result<td::Ref<ProofLink>> export_as_proof_link() const = 0;
|
virtual td::Result<td::Ref<ProofLink>> export_as_proof_link() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
td::Result<td::Ref<vm::Cell>> create_block_state_proof(td::Ref<vm::Cell> root);
|
||||||
|
td::Result<RootHash> unpack_block_state_proof(BlockIdExt block_id, td::Ref<vm::Cell> proof);
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
||||||
} // namespace ton
|
} // namespace ton
|
||||||
|
|
|
@ -146,6 +146,9 @@ class ValidatorManager : public ValidatorManagerInterface {
|
||||||
virtual void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) = 0;
|
virtual void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) = 0;
|
||||||
virtual void send_block_broadcast(BlockBroadcast broadcast, int mode) = 0;
|
virtual void send_block_broadcast(BlockBroadcast broadcast, int mode) = 0;
|
||||||
virtual void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) = 0;
|
virtual void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) = 0;
|
||||||
|
virtual void send_get_out_msg_queue_proof_request(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) = 0;
|
||||||
virtual void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
virtual void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
|
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
|
||||||
|
|
||||||
|
|
|
@ -265,6 +265,11 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
}
|
}
|
||||||
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override {
|
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override {
|
||||||
}
|
}
|
||||||
|
void send_get_out_msg_queue_proof_request(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) override {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -283,7 +288,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
void try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) override;
|
void try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) override;
|
||||||
|
|
||||||
void get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
void get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
||||||
td::Promise<std::unique_ptr<DownloadToken>> promise) override {
|
td::Promise<std::unique_ptr<ActionToken>> promise) override {
|
||||||
promise.set_error(td::Status::Error(ErrorCode::error, "download disabled"));
|
promise.set_error(td::Status::Error(ErrorCode::error, "download disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -335,6 +335,11 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
}
|
}
|
||||||
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override {
|
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override {
|
||||||
}
|
}
|
||||||
|
void send_get_out_msg_queue_proof_request(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) override {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
td::Timestamp timeout, td::Promise<std::string> promise) override {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -357,7 +362,7 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
void try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) override;
|
void try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) override;
|
||||||
|
|
||||||
void get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
void get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
||||||
td::Promise<std::unique_ptr<DownloadToken>> promise) override {
|
td::Promise<std::unique_ptr<ActionToken>> promise) override {
|
||||||
promise.set_error(td::Status::Error(ErrorCode::error, "download disabled"));
|
promise.set_error(td::Status::Error(ErrorCode::error, "download disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1652,6 +1652,13 @@ void ValidatorManagerImpl::send_validator_telemetry(PublicKeyHash key,
|
||||||
callback_->send_validator_telemetry(key, std::move(telemetry));
|
callback_->send_validator_telemetry(key, std::move(telemetry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ValidatorManagerImpl::send_get_out_msg_queue_proof_request(
|
||||||
|
ShardIdFull dst_shard, std::vector<BlockIdExt> blocks, block::ImportedMsgQueueLimits limits,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) {
|
||||||
|
callback_->download_out_msg_queue_proof(dst_shard, std::move(blocks), limits, td::Timestamp::in(10.0),
|
||||||
|
std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
void ValidatorManagerImpl::send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix,
|
void ValidatorManagerImpl::send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix,
|
||||||
std::string tmp_dir, td::Timestamp timeout,
|
std::string tmp_dir, td::Timestamp timeout,
|
||||||
td::Promise<std::string> promise) {
|
td::Promise<std::string> promise) {
|
||||||
|
|
|
@ -512,6 +512,9 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) override;
|
void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) override;
|
||||||
void send_block_broadcast(BlockBroadcast broadcast, int mode) override;
|
void send_block_broadcast(BlockBroadcast broadcast, int mode) override;
|
||||||
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override;
|
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override;
|
||||||
|
void send_get_out_msg_queue_proof_request(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) override;
|
||||||
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise) override;
|
td::Timestamp timeout, td::Promise<std::string> promise) override;
|
||||||
|
|
||||||
|
@ -524,8 +527,8 @@ class ValidatorManagerImpl : public ValidatorManager {
|
||||||
void try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) override;
|
void try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) override;
|
||||||
|
|
||||||
void get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
void get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
||||||
td::Promise<std::unique_ptr<DownloadToken>> promise) override {
|
td::Promise<std::unique_ptr<ActionToken>> promise) override {
|
||||||
td::actor::send_closure(token_manager_, &TokenManager::get_download_token, download_size, priority, timeout,
|
td::actor::send_closure(token_manager_, &TokenManager::get_token, download_size, priority, timeout,
|
||||||
std::move(promise));
|
std::move(promise));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,7 @@ void DownloadBlockNew::got_block_handle(BlockHandle handle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::unique_ptr<DownloadToken>> R) {
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::unique_ptr<ActionToken>> R) {
|
||||||
if (R.is_error()) {
|
if (R.is_error()) {
|
||||||
td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query,
|
td::actor::send_closure(SelfId, &DownloadBlockNew::abort_query,
|
||||||
R.move_as_error_prefix("failed to get download token: "));
|
R.move_as_error_prefix("failed to get download token: "));
|
||||||
|
@ -156,7 +156,7 @@ void DownloadBlockNew::got_block_handle(BlockHandle handle) {
|
||||||
std::move(P));
|
std::move(P));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadBlockNew::got_download_token(std::unique_ptr<DownloadToken> token) {
|
void DownloadBlockNew::got_download_token(std::unique_ptr<ActionToken> token) {
|
||||||
token_ = std::move(token);
|
token_ = std::move(token);
|
||||||
|
|
||||||
if (download_from_.is_zero() && client_.empty()) {
|
if (download_from_.is_zero() && client_.empty()) {
|
||||||
|
|
|
@ -49,7 +49,7 @@ class DownloadBlockNew : public td::actor::Actor {
|
||||||
|
|
||||||
void start_up() override;
|
void start_up() override;
|
||||||
void got_block_handle(BlockHandle handle);
|
void got_block_handle(BlockHandle handle);
|
||||||
void got_download_token(std::unique_ptr<DownloadToken> token);
|
void got_download_token(std::unique_ptr<ActionToken> token);
|
||||||
void got_node_to_download(adnl::AdnlNodeIdShort node);
|
void got_node_to_download(adnl::AdnlNodeIdShort node);
|
||||||
void got_data(td::BufferSlice data);
|
void got_data(td::BufferSlice data);
|
||||||
void got_data_from_db(td::BufferSlice data);
|
void got_data_from_db(td::BufferSlice data);
|
||||||
|
@ -79,7 +79,7 @@ class DownloadBlockNew : public td::actor::Actor {
|
||||||
|
|
||||||
bool allow_partial_proof_ = false;
|
bool allow_partial_proof_ = false;
|
||||||
|
|
||||||
std::unique_ptr<DownloadToken> token_;
|
std::unique_ptr<ActionToken> token_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fullnode
|
} // namespace fullnode
|
||||||
|
|
|
@ -128,7 +128,7 @@ void DownloadBlock::got_block_handle(BlockHandle handle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::unique_ptr<DownloadToken>> R) {
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::unique_ptr<ActionToken>> R) {
|
||||||
if (R.is_error()) {
|
if (R.is_error()) {
|
||||||
td::actor::send_closure(SelfId, &DownloadBlock::abort_query,
|
td::actor::send_closure(SelfId, &DownloadBlock::abort_query,
|
||||||
R.move_as_error_prefix("failed to get download token: "));
|
R.move_as_error_prefix("failed to get download token: "));
|
||||||
|
@ -140,7 +140,7 @@ void DownloadBlock::got_block_handle(BlockHandle handle) {
|
||||||
std::move(P));
|
std::move(P));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadBlock::got_download_token(std::unique_ptr<DownloadToken> token) {
|
void DownloadBlock::got_download_token(std::unique_ptr<ActionToken> token) {
|
||||||
token_ = std::move(token);
|
token_ = std::move(token);
|
||||||
|
|
||||||
if (download_from_.is_zero() && !short_ && client_.empty()) {
|
if (download_from_.is_zero() && !short_ && client_.empty()) {
|
||||||
|
|
|
@ -49,7 +49,7 @@ class DownloadBlock : public td::actor::Actor {
|
||||||
|
|
||||||
void start_up() override;
|
void start_up() override;
|
||||||
void got_block_handle(BlockHandle handle);
|
void got_block_handle(BlockHandle handle);
|
||||||
void got_download_token(std::unique_ptr<DownloadToken> token);
|
void got_download_token(std::unique_ptr<ActionToken> token);
|
||||||
void got_node_to_download(adnl::AdnlNodeIdShort node);
|
void got_node_to_download(adnl::AdnlNodeIdShort node);
|
||||||
void got_block_proof_description(td::BufferSlice proof_description);
|
void got_block_proof_description(td::BufferSlice proof_description);
|
||||||
void got_block_proof(td::BufferSlice data);
|
void got_block_proof(td::BufferSlice data);
|
||||||
|
@ -86,7 +86,7 @@ class DownloadBlock : public td::actor::Actor {
|
||||||
|
|
||||||
bool allow_partial_proof_ = false;
|
bool allow_partial_proof_ = false;
|
||||||
|
|
||||||
std::unique_ptr<DownloadToken> token_;
|
std::unique_ptr<ActionToken> token_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fullnode
|
} // namespace fullnode
|
||||||
|
|
|
@ -107,7 +107,7 @@ void DownloadProof::start_up() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadProof::checked_db() {
|
void DownloadProof::checked_db() {
|
||||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::unique_ptr<DownloadToken>> R) {
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::unique_ptr<ActionToken>> R) {
|
||||||
if (R.is_error()) {
|
if (R.is_error()) {
|
||||||
td::actor::send_closure(SelfId, &DownloadProof::abort_query,
|
td::actor::send_closure(SelfId, &DownloadProof::abort_query,
|
||||||
R.move_as_error_prefix("failed to get download token: "));
|
R.move_as_error_prefix("failed to get download token: "));
|
||||||
|
@ -119,7 +119,7 @@ void DownloadProof::checked_db() {
|
||||||
std::move(P));
|
std::move(P));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadProof::got_download_token(std::unique_ptr<DownloadToken> token) {
|
void DownloadProof::got_download_token(std::unique_ptr<ActionToken> token) {
|
||||||
token_ = std::move(token);
|
token_ = std::move(token);
|
||||||
|
|
||||||
if (download_from_.is_zero() && client_.empty()) {
|
if (download_from_.is_zero() && client_.empty()) {
|
||||||
|
|
|
@ -45,7 +45,7 @@ class DownloadProof : public td::actor::Actor {
|
||||||
|
|
||||||
void start_up() override;
|
void start_up() override;
|
||||||
void checked_db();
|
void checked_db();
|
||||||
void got_download_token(std::unique_ptr<DownloadToken> token);
|
void got_download_token(std::unique_ptr<ActionToken> token);
|
||||||
void got_node_to_download(adnl::AdnlNodeIdShort node);
|
void got_node_to_download(adnl::AdnlNodeIdShort node);
|
||||||
void got_block_proof_description(td::BufferSlice proof_description);
|
void got_block_proof_description(td::BufferSlice proof_description);
|
||||||
void got_block_proof(td::BufferSlice data);
|
void got_block_proof(td::BufferSlice data);
|
||||||
|
@ -72,7 +72,7 @@ class DownloadProof : public td::actor::Actor {
|
||||||
|
|
||||||
td::BufferSlice data_;
|
td::BufferSlice data_;
|
||||||
|
|
||||||
std::unique_ptr<DownloadToken> token_;
|
std::unique_ptr<ActionToken> token_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fullnode
|
} // namespace fullnode
|
||||||
|
|
|
@ -84,7 +84,7 @@ void GetNextKeyBlocks::finish_query() {
|
||||||
void GetNextKeyBlocks::start_up() {
|
void GetNextKeyBlocks::start_up() {
|
||||||
alarm_timestamp() = timeout_;
|
alarm_timestamp() = timeout_;
|
||||||
|
|
||||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::unique_ptr<DownloadToken>> R) {
|
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::unique_ptr<ActionToken>> R) {
|
||||||
if (R.is_error()) {
|
if (R.is_error()) {
|
||||||
td::actor::send_closure(SelfId, &GetNextKeyBlocks::abort_query,
|
td::actor::send_closure(SelfId, &GetNextKeyBlocks::abort_query,
|
||||||
R.move_as_error_prefix("failed to get download token: "));
|
R.move_as_error_prefix("failed to get download token: "));
|
||||||
|
@ -96,7 +96,7 @@ void GetNextKeyBlocks::start_up() {
|
||||||
std::move(P));
|
std::move(P));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetNextKeyBlocks::got_download_token(std::unique_ptr<DownloadToken> token) {
|
void GetNextKeyBlocks::got_download_token(std::unique_ptr<ActionToken> token) {
|
||||||
token_ = std::move(token);
|
token_ = std::move(token);
|
||||||
|
|
||||||
if (download_from_.is_zero() && client_.empty()) {
|
if (download_from_.is_zero() && client_.empty()) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ class GetNextKeyBlocks : public td::actor::Actor {
|
||||||
void finish_query();
|
void finish_query();
|
||||||
|
|
||||||
void start_up() override;
|
void start_up() override;
|
||||||
void got_download_token(std::unique_ptr<DownloadToken> token);
|
void got_download_token(std::unique_ptr<ActionToken> token);
|
||||||
void got_node_to_download(adnl::AdnlNodeIdShort node);
|
void got_node_to_download(adnl::AdnlNodeIdShort node);
|
||||||
void send_request();
|
void send_request();
|
||||||
void got_result(td::BufferSlice res);
|
void got_result(td::BufferSlice res);
|
||||||
|
@ -75,7 +75,7 @@ class GetNextKeyBlocks : public td::actor::Actor {
|
||||||
std::vector<BlockIdExt> pending_;
|
std::vector<BlockIdExt> pending_;
|
||||||
std::vector<BlockIdExt> res_;
|
std::vector<BlockIdExt> res_;
|
||||||
|
|
||||||
std::unique_ptr<DownloadToken> token_;
|
std::unique_ptr<ActionToken> token_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fullnode
|
} // namespace fullnode
|
||||||
|
|
|
@ -22,23 +22,23 @@ namespace ton {
|
||||||
|
|
||||||
namespace validator {
|
namespace validator {
|
||||||
|
|
||||||
void TokenManager::get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
void TokenManager::get_token(size_t size, td::uint32 priority, td::Timestamp timeout,
|
||||||
td::Promise<std::unique_ptr<DownloadToken>> promise) {
|
td::Promise<std::unique_ptr<ActionToken>> promise) {
|
||||||
if (free_priority_tokens_ > 0 && priority > 0) {
|
if (free_priority_tokens_ > 0 && priority > 0) {
|
||||||
--free_priority_tokens_;
|
--free_priority_tokens_;
|
||||||
promise.set_value(gen_token(download_size, priority));
|
promise.set_value(gen_token(size, priority));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (free_tokens_ > 0) {
|
if (free_tokens_ > 0) {
|
||||||
--free_tokens_;
|
--free_tokens_;
|
||||||
promise.set_value(gen_token(download_size, priority));
|
promise.set_value(gen_token(size, priority));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pending_.emplace(PendingPromiseKey{download_size, priority, seqno_++}, PendingPromise{timeout, std::move(promise)});
|
pending_.emplace(PendingPromiseKey{size, priority, seqno_++}, PendingPromise{timeout, std::move(promise)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void TokenManager::download_token_cleared(size_t download_size, td::uint32 priority) {
|
void TokenManager::token_cleared(size_t size, td::uint32 priority) {
|
||||||
(priority ? free_priority_tokens_ : free_tokens_)++;
|
(priority ? free_priority_tokens_ : free_tokens_)++;
|
||||||
if (free_priority_tokens_ > max_priority_tokens_) {
|
if (free_priority_tokens_ > max_priority_tokens_) {
|
||||||
free_priority_tokens_--;
|
free_priority_tokens_--;
|
||||||
|
@ -47,7 +47,7 @@ void TokenManager::download_token_cleared(size_t download_size, td::uint32 prior
|
||||||
|
|
||||||
for (auto it = pending_.begin(); it != pending_.end();) {
|
for (auto it = pending_.begin(); it != pending_.end();) {
|
||||||
if (it->first.priority && (free_tokens_ || free_priority_tokens_)) {
|
if (it->first.priority && (free_tokens_ || free_priority_tokens_)) {
|
||||||
it->second.promise.set_value(gen_token(download_size, priority));
|
it->second.promise.set_value(gen_token(size, priority));
|
||||||
auto it2 = it++;
|
auto it2 = it++;
|
||||||
pending_.erase(it2);
|
pending_.erase(it2);
|
||||||
if (free_priority_tokens_ > 0) {
|
if (free_priority_tokens_ > 0) {
|
||||||
|
@ -56,7 +56,7 @@ void TokenManager::download_token_cleared(size_t download_size, td::uint32 prior
|
||||||
free_tokens_--;
|
free_tokens_--;
|
||||||
}
|
}
|
||||||
} else if (!it->first.priority && free_tokens_) {
|
} else if (!it->first.priority && free_tokens_) {
|
||||||
it->second.promise.set_value(gen_token(download_size, priority));
|
it->second.promise.set_value(gen_token(size, priority));
|
||||||
auto it2 = it++;
|
auto it2 = it++;
|
||||||
pending_.erase(it2);
|
pending_.erase(it2);
|
||||||
free_tokens_--;
|
free_tokens_--;
|
||||||
|
@ -69,7 +69,7 @@ void TokenManager::download_token_cleared(size_t download_size, td::uint32 prior
|
||||||
void TokenManager::alarm() {
|
void TokenManager::alarm() {
|
||||||
for (auto it = pending_.begin(); it != pending_.end();) {
|
for (auto it = pending_.begin(); it != pending_.end();) {
|
||||||
if (it->second.timeout.is_in_past()) {
|
if (it->second.timeout.is_in_past()) {
|
||||||
it->second.promise.set_error(td::Status::Error(ErrorCode::timeout, "timeout in wait download token"));
|
it->second.promise.set_error(td::Status::Error(ErrorCode::timeout, "timeout in wait token"));
|
||||||
it = pending_.erase(it);
|
it = pending_.erase(it);
|
||||||
} else {
|
} else {
|
||||||
it++;
|
it++;
|
||||||
|
@ -77,23 +77,23 @@ void TokenManager::alarm() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DownloadToken> TokenManager::gen_token(size_t download_size, td::uint32 priority) {
|
std::unique_ptr<ActionToken> TokenManager::gen_token(size_t size, td::uint32 priority) {
|
||||||
class Token : public DownloadToken {
|
class TokenImpl : public ActionToken {
|
||||||
public:
|
public:
|
||||||
Token(size_t download_size, td::uint32 priority, td::actor::ActorId<TokenManager> manager)
|
TokenImpl(size_t size, td::uint32 priority, td::actor::ActorId<TokenManager> manager)
|
||||||
: download_size_(download_size), priority_(priority), manager_(manager) {
|
: size_(size), priority_(priority), manager_(manager) {
|
||||||
}
|
}
|
||||||
~Token() override {
|
~TokenImpl() override {
|
||||||
td::actor::send_closure(manager_, &TokenManager::download_token_cleared, download_size_, priority_);
|
td::actor::send_closure(manager_, &TokenManager::token_cleared, size_, priority_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t download_size_;
|
size_t size_;
|
||||||
td::uint32 priority_;
|
td::uint32 priority_;
|
||||||
td::actor::ActorId<TokenManager> manager_;
|
td::actor::ActorId<TokenManager> manager_;
|
||||||
};
|
};
|
||||||
|
|
||||||
return std::make_unique<Token>(download_size, priority, actor_id(this));
|
return std::make_unique<TokenImpl>(size, priority, actor_id(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace validator
|
} // namespace validator
|
||||||
|
|
|
@ -31,16 +31,19 @@ class TokenManager : public td::actor::Actor {
|
||||||
public:
|
public:
|
||||||
TokenManager() {
|
TokenManager() {
|
||||||
}
|
}
|
||||||
|
explicit TokenManager(td::uint32 max_tokens)
|
||||||
|
: free_tokens_(max_tokens), free_priority_tokens_(max_tokens), max_priority_tokens_(max_tokens) {
|
||||||
|
}
|
||||||
void alarm() override;
|
void alarm() override;
|
||||||
|
|
||||||
void get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
void get_token(size_t size, td::uint32 priority, td::Timestamp timeout,
|
||||||
td::Promise<std::unique_ptr<DownloadToken>> promise);
|
td::Promise<std::unique_ptr<ActionToken>> promise);
|
||||||
void download_token_cleared(size_t download_size, td::uint32 priority);
|
void token_cleared(size_t size, td::uint32 priority);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<DownloadToken> gen_token(size_t download_size, td::uint32 priority);
|
std::unique_ptr<ActionToken> gen_token(size_t size, td::uint32 priority);
|
||||||
struct PendingPromiseKey {
|
struct PendingPromiseKey {
|
||||||
size_t download_size;
|
size_t size;
|
||||||
td::uint32 priority;
|
td::uint32 priority;
|
||||||
td::uint64 seqno;
|
td::uint64 seqno;
|
||||||
|
|
||||||
|
@ -50,7 +53,7 @@ class TokenManager : public td::actor::Actor {
|
||||||
};
|
};
|
||||||
struct PendingPromise {
|
struct PendingPromise {
|
||||||
td::Timestamp timeout;
|
td::Timestamp timeout;
|
||||||
td::Promise<std::unique_ptr<DownloadToken>> promise;
|
td::Promise<std::unique_ptr<ActionToken>> promise;
|
||||||
};
|
};
|
||||||
td::uint64 seqno_ = 0;
|
td::uint64 seqno_ = 0;
|
||||||
std::map<PendingPromiseKey, PendingPromise> pending_;
|
std::map<PendingPromiseKey, PendingPromise> pending_;
|
||||||
|
|
|
@ -35,15 +35,16 @@
|
||||||
#include "interfaces/proof.h"
|
#include "interfaces/proof.h"
|
||||||
#include "interfaces/shard.h"
|
#include "interfaces/shard.h"
|
||||||
#include "catchain/catchain-types.h"
|
#include "catchain/catchain-types.h"
|
||||||
|
#include "interfaces/out-msg-queue-proof.h"
|
||||||
#include "interfaces/external-message.h"
|
#include "interfaces/external-message.h"
|
||||||
|
|
||||||
namespace ton {
|
namespace ton {
|
||||||
|
|
||||||
namespace validator {
|
namespace validator {
|
||||||
|
|
||||||
class DownloadToken {
|
class ActionToken {
|
||||||
public:
|
public:
|
||||||
virtual ~DownloadToken() = default;
|
virtual ~ActionToken() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PerfTimerStats {
|
struct PerfTimerStats {
|
||||||
|
@ -186,6 +187,9 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
||||||
td::Promise<std::vector<BlockIdExt>> promise) = 0;
|
td::Promise<std::vector<BlockIdExt>> promise) = 0;
|
||||||
virtual void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
virtual void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
|
||||||
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
|
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
|
||||||
|
virtual void download_out_msg_queue_proof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
|
||||||
|
block::ImportedMsgQueueLimits limits, td::Timestamp timeout,
|
||||||
|
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) = 0;
|
||||||
|
|
||||||
virtual void new_key_block(BlockHandle handle) = 0;
|
virtual void new_key_block(BlockHandle handle) = 0;
|
||||||
virtual void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) = 0;
|
virtual void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) = 0;
|
||||||
|
@ -248,7 +252,7 @@ class ValidatorManagerInterface : public td::actor::Actor {
|
||||||
virtual void add_ext_server_port(td::uint16 port) = 0;
|
virtual void add_ext_server_port(td::uint16 port) = 0;
|
||||||
|
|
||||||
virtual void get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
virtual void get_download_token(size_t download_size, td::uint32 priority, td::Timestamp timeout,
|
||||||
td::Promise<std::unique_ptr<DownloadToken>> promise) = 0;
|
td::Promise<std::unique_ptr<ActionToken>> promise) = 0;
|
||||||
|
|
||||||
virtual void get_block_data_from_db(ConstBlockHandle handle, td::Promise<td::Ref<BlockData>> promise) = 0;
|
virtual void get_block_data_from_db(ConstBlockHandle handle, td::Promise<td::Ref<BlockData>> promise) = 0;
|
||||||
virtual void get_block_data_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) = 0;
|
virtual void get_block_data_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) = 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue