diff --git a/tl/generate/scheme/ton_api.tl b/tl/generate/scheme/ton_api.tl index f04f7863..3a2ad1fc 100644 --- a/tl/generate/scheme/ton_api.tl +++ b/tl/generate/scheme/ton_api.tl @@ -715,6 +715,8 @@ engine.validator.getValidatorSessionsInfo = engine.validator.ValidatorSessionsIn engine.validator.addCollator adnl_id:int256 shard:tonNode.shardId = engine.validator.Success; engine.validator.addShard shard:tonNode.shardId = engine.validator.Success; +engine.validator.delCollator adnl_id:int256 shard:tonNode.shardId = engine.validator.Success; +engine.validator.delShard shard:tonNode.shardId = engine.validator.Success; ---types--- diff --git a/tl/generate/scheme/ton_api.tlo b/tl/generate/scheme/ton_api.tlo index d535668a..2820a789 100644 Binary files a/tl/generate/scheme/ton_api.tlo and b/tl/generate/scheme/ton_api.tlo differ diff --git a/validator-engine-console/validator-engine-console-query.cpp b/validator-engine-console/validator-engine-console-query.cpp index cab34777..7bad3c97 100644 --- a/validator-engine-console/validator-engine-console-query.cpp +++ b/validator-engine-console/validator-engine-console-query.cpp @@ -1119,3 +1119,44 @@ td::Status AddShardQuery::receive(td::BufferSlice data) { td::TerminalIO::out() << "successfully added shard\n"; return td::Status::OK(); } + +td::Status DelCollatorQuery::run() { + TRY_RESULT_ASSIGN(adnl_id_, tokenizer_.get_token()); + TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token()); + TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token()); + return td::Status::OK(); +} + +td::Status DelCollatorQuery::send() { + auto b = ton::create_serialize_tl_object( + adnl_id_.tl(), ton::create_tl_shard_id(ton::ShardIdFull(wc_, shard_))); + td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise()); + return td::Status::OK(); +} + +td::Status DelCollatorQuery::receive(td::BufferSlice data) { + TRY_RESULT_PREFIX(f, ton::fetch_tl_object(data.as_slice(), true), + "received incorrect answer: "); + td::TerminalIO::out() << "successfully removed collator\n"; + return td::Status::OK(); +} + +td::Status DelShardQuery::run() { + TRY_RESULT_ASSIGN(wc_, tokenizer_.get_token()); + TRY_RESULT_ASSIGN(shard_, tokenizer_.get_token()); + return td::Status::OK(); +} + +td::Status DelShardQuery::send() { + auto b = ton::create_serialize_tl_object( + ton::create_tl_shard_id(ton::ShardIdFull(wc_, shard_))); + td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise()); + return td::Status::OK(); +} + +td::Status DelShardQuery::receive(td::BufferSlice data) { + TRY_RESULT_PREFIX(f, ton::fetch_tl_object(data.as_slice(), true), + "received incorrect answer: "); + td::TerminalIO::out() << "successfully removed shard\n"; + return td::Status::OK(); +} diff --git a/validator-engine-console/validator-engine-console-query.h b/validator-engine-console/validator-engine-console-query.h index 316cc5e7..3c2c2193 100644 --- a/validator-engine-console/validator-engine-console-query.h +++ b/validator-engine-console/validator-engine-console-query.h @@ -1162,3 +1162,50 @@ class AddShardQuery : public Query { td::int32 wc_; td::int64 shard_; }; + +class DelCollatorQuery : public Query { + public: + DelCollatorQuery(td::actor::ActorId console, Tokenizer tokenizer) + : Query(console, std::move(tokenizer)) { + } + td::Status run() override; + td::Status send() override; + td::Status receive(td::BufferSlice data) override; + static std::string get_name() { + return "delcollator"; + } + static std::string get_help() { + return "delcollator \tremove collator with given adnl_id and shard"; + } + std::string name() const override { + return get_name(); + } + + private: + ton::PublicKeyHash adnl_id_; + td::int32 wc_; + td::int64 shard_; +}; + +class DelShardQuery : public Query { + public: + DelShardQuery(td::actor::ActorId console, Tokenizer tokenizer) + : Query(console, std::move(tokenizer)) { + } + td::Status run() override; + td::Status send() override; + td::Status receive(td::BufferSlice data) override; + static std::string get_name() { + return "delshard"; + } + static std::string get_help() { + return "delshard \tstop monitoring shard"; + } + std::string name() const override { + return get_name(); + } + + private: + td::int32 wc_; + td::int64 shard_; +}; diff --git a/validator-engine/validator-engine.cpp b/validator-engine/validator-engine.cpp index 14a6961f..cd14ae1e 100644 --- a/validator-engine/validator-engine.cpp +++ b/validator-engine/validator-engine.cpp @@ -418,6 +418,19 @@ td::Result Config::config_add_collator(ton::PublicKeyHash addr, ton::Shard return true; } +td::Result Config::config_del_collator(ton::PublicKeyHash addr, ton::ShardIdFull shard) { + if (!shard.is_valid_ext()) { + return td::Status::Error(PSTRING() << "invalid shard: " << shard.to_str()); + } + Collator c{addr, shard}; + auto it = std::find(collators.begin(), collators.end(), c); + if (it == collators.end()) { + return false; + } + collators.erase(it); + return true; +} + td::Result Config::config_add_full_node_adnl_id(ton::PublicKeyHash id) { if (full_node == id) { return false; @@ -548,6 +561,18 @@ td::Result Config::config_add_shard(ton::ShardIdFull shard) { return true; } +td::Result Config::config_del_shard(ton::ShardIdFull shard) { + if (!shard.is_valid_ext()) { + return td::Status::Error(PSTRING() << "invalid shard " << shard.to_str()); + } + auto it = std::find(shards_to_monitor.begin(), shards_to_monitor.end(), shard); + if (it == shards_to_monitor.end()) { + return false; + } + shards_to_monitor.erase(it); + return true; +} + td::Result Config::config_add_gc(ton::PublicKeyHash key) { return gc.insert(key).second; } @@ -3506,6 +3531,85 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_addShard }); } +void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delCollator &query, + td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm, + td::Promise promise) { + if (!(perm & ValidatorEnginePermissions::vep_modify)) { + promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized"))); + return; + } + if (!started_) { + promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started"))); + return; + } + + auto id = ton::PublicKeyHash{query.adnl_id_}; + auto shard = ton::create_shard_id(query.shard_); + auto R = config_.config_del_collator(id, shard); + if (R.is_error()) { + promise.set_value(create_control_query_error(R.move_as_error())); + return; + } + if (!R.move_as_ok()) { + promise.set_value(create_control_query_error(td::Status::Error("No such collator"))); + return; + } + if (!R.move_as_ok()) { + promise.set_value(ton::serialize_tl_object(ton::create_tl_object(), true)); + return; + } + set_shard_check_function(); + if (!validator_manager_.empty()) { + td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options, + validator_options_); + td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::del_collator, + ton::adnl::AdnlNodeIdShort(id), shard); + } + write_config([promise = std::move(promise)](td::Result R) mutable { + if (R.is_error()) { + promise.set_value(create_control_query_error(R.move_as_error())); + } else { + promise.set_value(ton::serialize_tl_object(ton::create_tl_object(), true)); + } + }); +} + +void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delShard &query, + td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm, + td::Promise promise) { + if (!(perm & ValidatorEnginePermissions::vep_modify)) { + promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized"))); + return; + } + if (!started_) { + promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started"))); + return; + } + + auto shard = ton::create_shard_id(query.shard_); + auto R = config_.config_del_shard(shard); + if (R.is_error()) { + promise.set_value(create_control_query_error(R.move_as_error())); + return; + } + if (!R.move_as_ok()) { + promise.set_value(create_control_query_error(td::Status::Error("No such shard"))); + return; + } + set_shard_check_function(); + if (!validator_manager_.empty()) { + td::actor::send_closure(validator_manager_, &ton::validator::ValidatorManagerInterface::update_options, + validator_options_); + } + write_config([promise = std::move(promise)](td::Result R) mutable { + if (R.is_error()) { + promise.set_value(create_control_query_error(R.move_as_error())); + } else { + promise.set_value(ton::serialize_tl_object(ton::create_tl_object(), true)); + } + }); +} + void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data, td::Promise promise) { diff --git a/validator-engine/validator-engine.hpp b/validator-engine/validator-engine.hpp index 71276e5d..49010bc4 100644 --- a/validator-engine/validator-engine.hpp +++ b/validator-engine/validator-engine.hpp @@ -115,6 +115,7 @@ struct Config { td::Result config_add_validator_adnl_id(ton::PublicKeyHash perm_key, ton::PublicKeyHash adnl_id, ton::UnixTime expire_at); td::Result config_add_collator(ton::PublicKeyHash addr, ton::ShardIdFull shard); + td::Result config_del_collator(ton::PublicKeyHash addr, ton::ShardIdFull shard); td::Result config_add_full_node_adnl_id(ton::PublicKeyHash id); td::Result config_add_full_node_slave(td::IPAddress addr, ton::PublicKey id); td::Result config_add_full_node_master(td::int32 port, ton::PublicKeyHash id); @@ -123,6 +124,7 @@ struct Config { td::Result config_add_control_process(ton::PublicKeyHash key, td::int32 port, ton::PublicKeyHash id, td::uint32 permissions); td::Result config_add_shard(ton::ShardIdFull shard); + td::Result config_del_shard(ton::ShardIdFull shard); td::Result config_add_gc(ton::PublicKeyHash key); td::Result config_del_network_addr(td::IPAddress addr, std::vector cats, std::vector prio_cats); @@ -437,6 +439,10 @@ class ValidatorEngine : public td::actor::Actor { ton::PublicKeyHash src, td::uint32 perm, td::Promise promise); void run_control_query(ton::ton_api::engine_validator_addShard &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm, td::Promise promise); + void run_control_query(ton::ton_api::engine_validator_delCollator &query, td::BufferSlice data, + ton::PublicKeyHash src, td::uint32 perm, td::Promise promise); + void run_control_query(ton::ton_api::engine_validator_delShard &query, td::BufferSlice data, + ton::PublicKeyHash src, td::uint32 perm, td::Promise promise); void run_control_query(ton::ton_api::engine_validator_getPerfTimerStats &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm, td::Promise promise); template diff --git a/validator/collator-node.cpp b/validator/collator-node.cpp index 0a2a050e..c6afa541 100644 --- a/validator/collator-node.cpp +++ b/validator/collator-node.cpp @@ -54,10 +54,20 @@ void CollatorNode::tear_down() { } void CollatorNode::add_shard(ShardIdFull shard) { + if (std::find(shards_.begin(), shards_.end(), shard) != shards_.end()) { + return; + } LOG(INFO) << "Collator node: local_id=" << local_id_ << " , shard=" << shard.to_str(); shards_.push_back(shard); } +void CollatorNode::del_shard(ShardIdFull shard) { + auto it = std::find(shards_.begin(), shards_.end(), shard); + if (it != shards_.end()) { + shards_.erase(it); + } +} + void CollatorNode::new_masterchain_block_notification(td::Ref state) { std::vector top_blocks = {state->get_block_id()}; std::vector next_shards; diff --git a/validator/collator-node.hpp b/validator/collator-node.hpp index b0a2ad90..b3b232cf 100644 --- a/validator/collator-node.hpp +++ b/validator/collator-node.hpp @@ -32,6 +32,7 @@ class CollatorNode : public td::actor::Actor { void start_up() override; void tear_down() override; void add_shard(ShardIdFull shard); + void del_shard(ShardIdFull shard); void new_masterchain_block_notification(td::Ref state); diff --git a/validator/manager-disk.hpp b/validator/manager-disk.hpp index c4403e94..e0aad62e 100644 --- a/validator/manager-disk.hpp +++ b/validator/manager-disk.hpp @@ -395,6 +395,9 @@ class ValidatorManagerImpl : public ValidatorManager { void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override { UNREACHABLE(); } + void del_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override { + UNREACHABLE(); + } void update_options(td::Ref opts) override { opts_ = std::move(opts); diff --git a/validator/manager-hardfork.hpp b/validator/manager-hardfork.hpp index bd30b1de..e8fa327b 100644 --- a/validator/manager-hardfork.hpp +++ b/validator/manager-hardfork.hpp @@ -454,6 +454,9 @@ class ValidatorManagerImpl : public ValidatorManager { void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override { UNREACHABLE(); } + void del_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override { + UNREACHABLE(); + } void update_options(td::Ref opts) override { opts_ = std::move(opts); } diff --git a/validator/manager.cpp b/validator/manager.cpp index 183dc8c1..f56d6901 100644 --- a/validator/manager.cpp +++ b/validator/manager.cpp @@ -1795,7 +1795,7 @@ void ValidatorManagerImpl::new_masterchain_block() { last_masterchain_block_handle_, last_masterchain_state_); } for (auto &c : collator_nodes_) { - td::actor::send_closure(c.second, &CollatorNode::new_masterchain_block_notification, last_masterchain_state_); + td::actor::send_closure(c.second.actor, &CollatorNode::new_masterchain_block_notification, last_masterchain_state_); } if (last_masterchain_seqno_ % 1024 == 0) { @@ -2722,10 +2722,23 @@ void ValidatorManagerImpl::get_validator_sessions_info( void ValidatorManagerImpl::add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) { auto it = collator_nodes_.find(id); if (it == collator_nodes_.end()) { - auto actor = td::actor::create_actor("collatornode", id, actor_id(this), adnl_, rldp_); - it = collator_nodes_.emplace(id, std::move(actor)).first; + it = collator_nodes_.emplace(id, Collator()).first; + it->second.actor = td::actor::create_actor("collatornode", id, actor_id(this), adnl_, rldp_); + } + it->second.shards.insert(shard); + td::actor::send_closure(it->second.actor, &CollatorNode::add_shard, shard); +} + +void ValidatorManagerImpl::del_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) { + auto it = collator_nodes_.find(id); + if (it == collator_nodes_.end()) { + return; + } + td::actor::send_closure(it->second.actor, &CollatorNode::del_shard, shard); + it->second.shards.erase(shard); + if (it->second.shards.empty()) { + collator_nodes_.erase(it); } - td::actor::send_closure(it->second, &CollatorNode::add_shard, shard); } void ValidatorManagerImpl::update_options(td::Ref opts) { diff --git a/validator/manager.hpp b/validator/manager.hpp index 136e5e8a..6fca1178 100644 --- a/validator/manager.hpp +++ b/validator/manager.hpp @@ -563,6 +563,7 @@ class ValidatorManagerImpl : public ValidatorManager { void add_persistent_state_description(td::Ref desc) override; void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override; + void del_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) override; void update_options(td::Ref opts) override; private: @@ -639,7 +640,11 @@ class ValidatorManagerImpl : public ValidatorManager { std::map> shard_client_waiters_; - std::map> collator_nodes_; + struct Collator { + td::actor::ActorOwn actor; + std::set shards; + }; + std::map collator_nodes_; std::set extra_active_shards_; std::map last_validated_blocks_; diff --git a/validator/validator.h b/validator/validator.h index c387caff..0a5a22b5 100644 --- a/validator/validator.h +++ b/validator/validator.h @@ -238,6 +238,7 @@ class ValidatorManagerInterface : public td::actor::Actor { td::Promise> promise) = 0; virtual void add_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) = 0; + virtual void del_collator(adnl::AdnlNodeIdShort id, ShardIdFull shard) = 0; virtual void update_options(td::Ref opts) = 0; };